#include "tools_part.h"

#include <tqfile.h>
#include <tqpopupmenu.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <tqvbox.h>
#include <tqwhatsthis.h>

#include <tdeaction.h>
#include <tdeapplication.h>
#include <tdeconfig.h>
#include <kdebug.h>
#include <kdesktopfile.h>
#include <kdialogbase.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdeparts/part.h>
#include <kprocess.h>
#include <tdetexteditor/document.h>

#include "kdevcore.h"
#include "kdevproject.h"
#include "kdevpartcontroller.h"
#include "kdevappfrontend.h"
#include "kdevplugininfo.h"
#include "urlutil.h"
#include "configwidgetproxy.h"
#include "kdeveditorutil.h"

#include "toolsconfig.h"
#include "toolsconfigwidget.h"

#define TOOLSSETTINGS 1
#define EXTRATOOLSSETTINGS 2

static const KDevPluginInfo pluginData("kdevtools");
K_EXPORT_COMPONENT_FACTORY( libkdevtools, ToolsFactory( pluginData ) )

TQMap<int, TQString> externalToolMenuEntries;

ToolsPart::ToolsPart(TQObject *parent, const char *name, const TQStringList &)
	: KDevPlugin( &pluginData, parent, name ? name : "ToolsPart")
{
  setInstance(ToolsFactory::instance());

  setXMLFile("kdevpart_tools.rc");

	m_configProxy = new ConfigWidgetProxy( core() );
	m_configProxy->createGlobalConfigPage( i18n("Tools Menu"), TOOLSSETTINGS, info()->icon() );
	m_configProxy->createGlobalConfigPage( i18n("External Tools"), EXTRATOOLSSETTINGS, info()->icon() );
	connect( m_configProxy, TQ_SIGNAL(insertConfigWidget(const KDialogBase*, TQWidget*, unsigned int )),
		this, TQ_SLOT(insertConfigWidget(const KDialogBase*, TQWidget*, unsigned int )) );

  connect(core(), TQ_SIGNAL(coreInitialized()), this, TQ_SLOT(updateMenu()));

  connect( core(), TQ_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
           this, TQ_SLOT(contextMenu(TQPopupMenu *, const Context *)) );

  // Apparently action lists can only be plugged after the
  // xmlgui client has been registered
  TQTimer::singleShot(0, this, TQ_SLOT(updateToolsMenu()));
}


ToolsPart::~ToolsPart()
{
	delete m_configProxy;
}

void ToolsPart::insertConfigWidget( const KDialogBase * dlg, TQWidget * page, unsigned int pagenumber )
{
	if ( pagenumber == TOOLSSETTINGS )
	{
		ToolsConfig *w = new ToolsConfig( page, "tools config widget" );
		connect(dlg, TQ_SIGNAL(okClicked()), w, TQ_SLOT(accept()));
		connect(dlg, TQ_SIGNAL(destroyed()), this, TQ_SLOT(updateMenu()));
	}
	else if ( pagenumber == EXTRATOOLSSETTINGS )
	{
		ToolsConfigWidget *w2 = new ToolsConfigWidget( page, "tools config widget" );
		connect(dlg, TQ_SIGNAL(okClicked()), w2, TQ_SLOT(accept()));
		connect(dlg, TQ_SIGNAL(destroyed()), this, TQ_SLOT(updateToolsMenu()));
	}
}

void ToolsPart::updateMenu()
{
  TQPtrList<TDEAction> actions;

  unplugActionList("tools_list");

  TDEConfig *config = ToolsFactory::instance()->config();
  config->setGroup("Tools");

  TQStringList list = config->readListEntry("Tools");
  for (TQStringList::Iterator it = list.begin(); it != list.end(); ++it)
	{
	  TQString name = *it;

	  KDesktopFile df(name, true);
	  if (df.readName().isNull())
		continue;

	  TDEAction *action = new TDEAction(df.readName(), df.readIcon(), 0,
                                        this, TQ_SLOT(slotToolActivated()), (TQObject*)0, name.latin1());
	  actions.append(action);
	}

  plugActionList("tools_list", actions);
}


void ToolsPart::slotToolActivated()
{
  TQString df = sender()->name();
  kapp->startServiceByDesktopPath(df);
}

void ToolsPart::startCommand(TQString cmdline, bool captured, TQString fileName)
{
    KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( partController()->activePart() );

    if ( fileName.isNull() && doc )
        fileName = doc->url().path();
    
    TQString projectDirectory;
    if (project())
        projectDirectory = project()->projectDirectory();
    
    TQString selection = KDevEditorUtil::currentSelection( doc );
    if ( !selection.isEmpty() )
        selection = KShellProcess::quote( selection );

    TQString word = KDevEditorUtil::currentWord( doc );
    
    // This should really be checked before inserting into the popup
    if (cmdline.contains("%D") && projectDirectory.isNull())
        return;
    cmdline.replace(TQRegExp("%D"), projectDirectory);
    
    if (cmdline.contains("%S") && fileName.isNull())
        return;
    cmdline.replace(TQRegExp("%S"), fileName);

    if (cmdline.contains("%T") && selection.isNull())
        return;
    cmdline.replace(TQRegExp("%T"), selection);

    if (cmdline.contains("%W") && word.isNull())
        return;
    cmdline.replace(TQRegExp("%W"), word);

    if (captured)
    {
       if (KDevAppFrontend *appFrontend = extension<KDevAppFrontend>("TDevelop/AppFrontend"))
            appFrontend->startAppCommand(TQString(), cmdline, false);
    }
    else 
    {
        KShellProcess proc;
        proc << cmdline;
        proc.start(TDEProcess::DontCare, TDEProcess::NoCommunication);
    }
}


void ToolsPart::updateToolsMenu()
{
    TDEConfig *config = ToolsFactory::instance()->config();
    config->setGroup("External Tools");
    TQStringList l = config->readListEntry("Tool Menu");


    TQPtrList<TDEAction> actions;
    TQStringList::ConstIterator it;
    for (it = l.begin(); it != l.end(); ++it) {
        TQString menutext = *it;
        TDEConfig *config = ToolsFactory::instance()->config();
        config->setGroup("Tool Menu " + menutext);
        bool isdesktopfile = config->readBoolEntry("DesktopFile");
        TDEAction *action = new TDEAction(*it, 0,
                                      this, TQ_SLOT(toolsMenuActivated()),
                                      (TQObject*) 0, menutext.utf8());
        if (isdesktopfile) {
            KDesktopFile df(config->readPathEntry("CommandLine"));
            action->setIcon(df.readIcon());
        }
        actions.append(action);
    }

    unplugActionList("tools2_list");
    plugActionList("tools2_list", actions);
}


void ToolsPart::contextMenu(TQPopupMenu *popup, const Context *context)
{
    if (!context->hasType( Context::FileContext ))
        return;

    const FileContext *fcontext = static_cast<const FileContext*>(context);
    m_contextPopup = popup;
    m_contextFileName = fcontext->urls().first().path();
    externalToolMenuEntries.clear();
    
    TDEConfig *config = ToolsFactory::instance()->config();
    config->setGroup("External Tools");
    TQStringList filecontextList = config->readListEntry("File Context");

    if (URLUtil::isDirectory(m_contextFileName)) {
        TQStringList l = config->readListEntry("Dir Context");
        TQStringList::ConstIterator it;
        for (it = l.begin(); it != l.end(); ++it)
            externalToolMenuEntries.insert( popup->insertItem( (*it), this, TQ_SLOT(dirContextActivated(int)) ), (*it) );
    } else {
        TQStringList l = config->readListEntry("File Context");
        TQStringList::ConstIterator it;
        for (it = l.begin(); it != l.end(); ++it)
            externalToolMenuEntries.insert( popup->insertItem( (*it), this, TQ_SLOT(fileContextActivated(int))  ), (*it) );
    }
}


void ToolsPart::toolsMenuActivated()
{
    TQString menutext = sender()->name();
    TDEConfig *config = ToolsFactory::instance()->config();
    config->setGroup("Tool Menu " + menutext);
    TQString cmdline = config->readPathEntry("CommandLine");
    bool isdesktopfile = config->readBoolEntry("DesktopFile");
    bool captured = config->readBoolEntry("Captured");
    kdDebug() << "tools:" << "activating " << menutext
              << "with cmdline " << cmdline
              << "and desktopfile " << isdesktopfile << endl;
    if (isdesktopfile)
        kapp->startServiceByDesktopPath(cmdline);
    else
        startCommand(cmdline, captured, TQString());
}


void ToolsPart::fileContextActivated(int id)
{
    TQString menutext = externalToolMenuEntries[ id ];

    TDEConfig *config = ToolsFactory::instance()->config();
    config->setGroup("File Context " + menutext);
    TQString cmdline = config->readPathEntry("CommandLine");
    bool captured = config->readBoolEntry("Captured");
    kdDebug() << "filecontext:" << "activating " << menutext
              << " with cmdline " << cmdline
              << " on file " << m_contextFileName << endl;
    startCommand(cmdline, captured, m_contextFileName);
}


void ToolsPart::dirContextActivated(int id)
{
    TQString menutext = externalToolMenuEntries[ id ];

    TDEConfig *config = ToolsFactory::instance()->config();
    config->setGroup("Dir Context " + menutext);
    TQString cmdline = config->readPathEntry("CommandLine");
    bool captured = config->readBoolEntry("Captured");
    kdDebug() << "dircontext:" << "activating " << menutext
              << "with cmdline " << cmdline
              << " on directory " << m_contextFileName << endl;
    startCommand(cmdline, captured, m_contextFileName);
}

#include "tools_part.moc"
