/***************************************************************************
    begin                : mon 3-11 20:40:00 CEST 2003
    copyright            : (C) 2003 by Jeroen Wijnhout
    email                : Jeroen.Wijnhout@kdemail.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "kilelauncher.h"

#include "kileinfo.h"
#include "kiletool.h"
#include "kiletoolmanager.h"
#include "kiletool_enums.h"
#include "docpart.h"
#include "kileconfig.h"

#include <tqwidgetstack.h>
#include <tqregexp.h>
#include <tqfileinfo.h>

#include "kiledebug.h"
#include <krun.h>
#include <kprocess.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <klibloader.h>
#include <tdeparts/part.h>
#include <tdeparts/factory.h>
#include <tdeparts/partmanager.h>

 namespace KileTool
{
	Launcher::Launcher() :
		m_tool(0L)
	{
	}
	
	Launcher::~ Launcher()
	{
		KILE_DEBUG() << "DELETING launcher" << endl;
	}

	ProcessLauncher::ProcessLauncher(const char * shellname /* =0 */) :
		m_wd(TQString()),
		m_cmd(TQString()),
		m_options(TQString()),
		m_texinputs(KileConfig::teXPaths()),
		m_bibinputs(KileConfig::bibInputPaths()),
 		m_bstinputs(KileConfig::bstInputPaths()),
		m_changeTo(true)
	{
		KILE_DEBUG() << "==KileTool::ProcessLauncher::ProcessLauncher()==============" << endl;

		m_proc = new KShellProcess(shellname);
		if (m_proc)
			KILE_DEBUG() << "\tKShellProcess created" << endl;
		else
			KILE_DEBUG() << "\tNO KShellProcess created" << endl;

		connect(m_proc, TQ_SIGNAL( receivedStdout(TDEProcess*, char*, int) ), this, TQ_SLOT(slotProcessOutput(TDEProcess*, char*, int ) ) );
 		connect(m_proc, TQ_SIGNAL( receivedStderr(TDEProcess*, char*, int) ),this, TQ_SLOT(slotProcessOutput(TDEProcess*, char*, int ) ) );
		connect(m_proc, TQ_SIGNAL( processExited(TDEProcess*)), this, TQ_SLOT(slotProcessExited(TDEProcess*)));
	}

	ProcessLauncher::~ProcessLauncher()
	{
		KILE_DEBUG() << "DELETING ProcessLauncher" << endl;
		delete m_proc;
	}

	void ProcessLauncher::setWorkingDirectory(const TQString &wd)
	{
		m_wd = wd;
	}

	bool ProcessLauncher::launch()
	{
		KILE_DEBUG() << "KileTool::ProcessLauncher::launch()=================" << endl;
		KILE_DEBUG() << "\tbelongs to tool " << tool()->name() << endl;

		TQString msg, out = "*****\n*****     " + tool()->name() + i18n(" output: \n");

		if ( m_cmd.isNull() ) 
			m_cmd = tool()->readEntry("command");

		if ( m_options.isNull() )
			m_options = tool()->readEntry("options");
		
		if ( m_changeTo && (!m_wd.isNull()) )
		{
			m_proc->setWorkingDirectory(m_wd);
			out += TQString("*****     cd '")+ m_wd +TQString("'\n");
		}

		TQString str;
		tool()->translate(m_cmd);
		tool()->translate(m_options);
		*m_proc  << m_cmd << m_options;
		
		if (m_proc)
		{
			out += TQString("*****     ")+ m_cmd+ ' ' + m_options + '\n';

			TQString src = tool()->source(false);
			TQString trgt = tool()->target();
			if (src == trgt)
				msg = src;
			else
				msg = src + " => " + trgt;

			msg += " (" + m_proc->args()[0] + ')';
			 
			emit(message(Info,msg));

			// QuickView tools need a special TEXINPUTS environment variable
			if ( tool()->isQuickie() ) 
				m_texinputs = KileConfig::previewTeXPaths();

			KILE_DEBUG() << "$PATH=" << tool()->manager()->info()->expandEnvironmentVars("$PATH") << endl;
			KILE_DEBUG() << "$TEXINPUTS=" << tool()->manager()->info()->expandEnvironmentVars(m_texinputs + ":$TEXINPUTS") << endl;
			KILE_DEBUG() << "$BIBINPUTS=" << tool()->manager()->info()->expandEnvironmentVars(m_bibinputs + ":$BIBINPUTS") << endl;
			KILE_DEBUG() << "$BSTINPUTS=" << tool()->manager()->info()->expandEnvironmentVars(m_bstinputs + ":$BSTINPUTS") << endl;
			KILE_DEBUG() << "Tool name is "<< tool()->name() << endl;

			m_proc->setEnvironment("PATH",tool()->manager()->info()->expandEnvironmentVars("$PATH"));

			if (! m_texinputs.isEmpty())
				m_proc->setEnvironment("TEXINPUTS", tool()->manager()->info()->expandEnvironmentVars(m_texinputs + ":$TEXINPUTS"));
			if (! m_bibinputs.isEmpty())
				m_proc->setEnvironment("BIBINPUTS", tool()->manager()->info()->expandEnvironmentVars(m_bibinputs + ":$BIBINPUTS"));
			if (! m_bstinputs.isEmpty())
				m_proc->setEnvironment("BSTINPUTS", tool()->manager()->info()->expandEnvironmentVars(m_bstinputs + ":$BSTINPUTS"));

			out += "*****\n";
			emit(output(out));

			return m_proc->start(tool()->manager()->shouldBlock() ? TDEProcess::Block : TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
		}
		else
			return false;
	}

	bool ProcessLauncher::kill()
	{
		KILE_DEBUG() << "==KileTool::ProcessLauncher::kill()==============" << endl;
		if ( m_proc && m_proc->isRunning() )
		{
			KILE_DEBUG() << "\tkilling" << endl;
			return m_proc->kill();
		}
		else
		{
			KILE_DEBUG() << "\tno process or process not running" << endl;
			return false;
		}
	}

	bool ProcessLauncher::selfCheck()
	{
		emit(message(Error, i18n("Launching failed, diagnostics:")));

		TQString exe = KRun::binaryName(tool()->readEntry("command"), false);
		TQString path = TDEGlobal::dirs()->findExe(exe, TQString(), true);

		if ( path.isNull() )
		{
			emit(message(Error, i18n("There is no executable named \"%1\" in your path.").arg(exe)));
			return false;
		}
		else
		{
			TQFileInfo fi(path);
			if ( ! fi.isExecutable() )
			{
				emit(message(Error, i18n("You do not have permission to run %1.").arg(path)));
				return false;
			}
		}

		emit(message(Info, i18n("Diagnostics could not find any obvious problems.")));
		return true;
	}

	void ProcessLauncher::slotProcessOutput(TDEProcess*, char* buf, int len)
	{
		emit output(TQString::fromLocal8Bit(buf, len));
	}

	void ProcessLauncher::slotProcessExited(TDEProcess*)
	{
		KILE_DEBUG() << "==KileTool::ProcessLauncher::slotProcessExited=============" << endl;
		KILE_DEBUG() << "\t" << tool()->name() << endl;

		if (m_proc)
		{
			if (m_proc->normalExit())
			{
				KILE_DEBUG() << "\tnormal exit" << endl;
				int type = Info;
				if (m_proc->exitStatus() != 0) 
				{
					type = Error;
					emit(message(type,i18n("finished with exit status %1").arg(m_proc->exitStatus())));
				}

				if (type == Info)
					emit(done(Success));
				else
					emit(done(Failed));
			}
			else
			{
				KILE_DEBUG() << "\tabnormal exit" << endl;
				emit(message(Error,i18n("finished abruptly")));
				emit(done(AbnormalExit));
			}
		}
		else
		{
			kdWarning() << "\tNO PROCESS, emitting done" << endl;
			emit(done(Success));
		}
	}

	KonsoleLauncher::KonsoleLauncher(const char * shellname) : ProcessLauncher(shellname)
	{
	}

	bool KonsoleLauncher::launch()
	{
		TQString cmd = tool()->readEntry("command");
		TQString noclose = (tool()->readEntry("close") == "no") ? "--noclose" : "";
		setCommand("konsole");
		setOptions(noclose + " -T \"" + cmd + " (Kile)\" -e " + cmd + ' ' + tool()->readEntry("options"));

		if ( TDEGlobal::dirs()->findExe(KRun::binaryName(cmd, false)).isNull() ) return false;

		return ProcessLauncher::launch();
	}

	PartLauncher::PartLauncher(const char *name /* = 0*/ ) :
		m_part(0L),
		m_state("Viewer"),
		m_name(name),
		m_libName(0L),
		m_className(0L),
		m_options(TQString())
	{
	}

	PartLauncher::~PartLauncher()
	{
		KILE_DEBUG () << "DELETING PartLauncher" << endl;
	}

	bool PartLauncher::launch()
	{
		m_libName = tool()->readEntry("libName").ascii();
		m_className = tool()->readEntry("className").ascii();
		m_options=tool()->readEntry("libOptions");
		m_state=tool()->readEntry("state");

		TQString msg, out = "*****\n*****     " + tool()->name() + i18n(" output: \n");
		
		TQString shrt = "%target";
		tool()->translate(shrt);
		TQString dir  = "%dir_target"; tool()->translate(dir);

		TQString name = shrt;
		if ( dir[0] == '/' )
			name = dir + '/' + shrt;


		KLibFactory *factory = KLibLoader::self()->factory(m_libName);
		if (factory == 0)
		{
			emit(message(Error, i18n("Could not find the %1 library.").arg(m_libName)));
			return false;
		}

		TQWidgetStack *stack = tool()->manager()->widgetStack();
		KParts::PartManager *pm = tool()->manager()->partManager();

		m_part = (KParts::ReadOnlyPart *)factory->create(stack, m_libName, m_className, m_options);

		if (m_part == 0)
		{
			emit(message(Error, i18n("Could not create component %1 from the library %2.").arg(m_className).arg(m_libName)));
			emit(done(Failed));
			return false;
		}
		else
		{
			TQString cmd = TQString(m_libName) + "->" + TQString(m_className) + ' ' + m_options + ' ' + name;
			out += "*****     " + cmd + '\n';

			msg = shrt+ " (" + tool()->readEntry("libName") + ')';
			emit(message(Info,msg));
		}

		out += "*****\n";
		emit(output(out));

		tool()->manager()->wantGUIState(m_state);

		stack->addWidget(m_part->widget() , 1 );
		stack->raiseWidget(1);

		m_part->openURL(KURL(name));
		pm->addPart(m_part, true);
		pm->setActivePart(m_part);

		emit(done(Success));

		return true;
	}

	bool PartLauncher::kill()
	{
		return true;
	}

	bool DocPartLauncher::launch()
	{
		m_state=tool()->readEntry("state");

		TQString shrt = "%target";
		tool()->translate(shrt);
		TQString name="%dir_target/%target";
		tool()->translate(name);

		TQString out = "*****\n*****     " + tool()->name() + i18n(" output: \n") + "*****     TDEHTML " + name + "\n*****\n";
		TQString msg =  shrt+ " (TDEHTML)";
		emit(message(Info, msg));
		emit(output(out));

		TQWidgetStack *stack = tool()->manager()->widgetStack();
		KParts::PartManager *pm = tool()->manager()->partManager();

		DocumentationViewer *htmlpart = new DocumentationViewer(stack,"help");
		m_part = static_cast<KParts::ReadOnlyPart*>(htmlpart);

		connect(htmlpart, TQ_SIGNAL(updateStatus(bool, bool)), tool(), TQ_SIGNAL(updateStatus(bool, bool)));

		tool()->manager()->wantGUIState(m_state);

		htmlpart->openURL(KURL(name));
		htmlpart->addToHistory(name);
		stack->addWidget(htmlpart->widget() , 1 );
		stack->raiseWidget(1);

		pm->addPart(htmlpart, true);
		pm->setActivePart( htmlpart);

		emit(done(Success));
		
		return true;
	}
}

#include "kilelauncher.moc"
