//
// C++ Implementation: kprocesswrapper
//
// Description: 
//
//
// Author: Christian Hubinger <chubinger@irrsinnig.org>, (C) 2008
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "kprocesswrapper.h"

// QT Includes
#include <tqwidget.h>
#include <tquuid.h>
#include <tqfile.h>
#include <tqtextstream.h>

// KDE includes
#include <tdeapplication.h>
#include <kprocess.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kurl.h>
#include <tdetempfile.h>
#include <tdeio/netaccess.h>

// Project includes
#include "kmftarget.h"

namespace KMF {

//##########  KMFUndoEngine  ##############
//#### static stuff
TDEProcessWrapper* TDEProcessWrapper::m_instance = 0;
TDEProcessWrapper* TDEProcessWrapper::instance() {
	if ( ! m_instance ) {
		m_instance = new TDEProcessWrapper( TQT_TQOBJECT(TDEApplication::kApplication()->mainWidget()) , "TDEProcessWrapper" );
	}
	return m_instance;
}
//##### end static stuff



TDEProcessWrapper::TDEProcessWrapper( TQObject* parent,  const char* name ) : TQObject( parent, name ) {
	m_stderrbuf = new TQString( "" );
	m_stdoutbuf = new TQString( "" );
	m_childproc = new TDEProcess();
	m_status = -1;
	m_exitedNormal = false;
	
	connect( m_childproc, TQT_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), this, TQT_SLOT( slotReceivedOutput( TDEProcess*, char*, int ) ) );
	connect( m_childproc, TQT_SIGNAL( receivedStderr( TDEProcess*, char*, int ) ), this, TQT_SLOT( slotReceivedError( TDEProcess*, char*, int ) ) );
	connect( m_childproc, TQT_SIGNAL( processExited( TDEProcess* ) ), this, TQT_SLOT( slotProcessExited( TDEProcess* ) ) ) ;
}

TDEProcessWrapper::~TDEProcessWrapper()
{
}

void TDEProcessWrapper::slotStartLocalJob( const TQString& jobName, const TQString& command, bool useKdeSu , bool synchronous = false  ) {
	kdDebug() << "Start Local Job: " << jobName << " " << command << endl;
	kdDebug() << "synchronous: " << synchronous << endl;
	m_jobName = jobName;
	*m_stdoutbuf = "";
	*m_stderrbuf = "";
	m_allOut = "";
	m_stdOut = "";
	m_stdErr = "";
	TQString localScriptFile = command;
	KTempFile *f = new KTempFile();
	if ( ! TDEIO::NetAccess::exists( localScriptFile, false, TDEApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "TDEProcessWrapper::slotStartLocalJob(...) - creating temporary script file." << endl;
		TQTextStream *ts = f->textStream();
		*ts << command << endl;
		f->sync();
		f->close();
		localScriptFile = f->name();
	}
	
	
	m_childproc->clearArguments();
	if ( useKdeSu ) {
		*m_childproc << "tdesu" << "-t" << "-i" << "kmyfirewall" << "--noignorebutton" << "-d" << "-c" << localScriptFile;
	} else {
		*m_childproc << "bash" << localScriptFile;
	}
	if ( synchronous ) {
		m_childproc->start( TDEProcess::Block, TDEProcess::AllOutput );
	} else {
		m_childproc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput );
	}
	f->unlink();
	delete f;
} 

void TDEProcessWrapper::slotStartRemoteJob( const TQString& jobName, const TQString& scriptFile, KMFTarget* execHost ) {
	TQString localScriptFile = scriptFile;
	m_jobName = jobName;
	*m_stdoutbuf = "";
	*m_stderrbuf = "";
	m_allOut = "";
	m_stdOut = "";
	m_stdErr = "";
	KTempFile *f = new KTempFile();
	if ( ! TDEIO::NetAccess::exists( scriptFile, false, TDEApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "TDEProcessWrapper::slotStartRemoteJob(...) - creating temporary script file." << endl;
		TQTextStream *ts = f->textStream();
		*ts << scriptFile << endl;
		f->sync();
		f->close();
		localScriptFile = f->name();
	}
	
	
	TQUuid uuid = TQUuid::createUuid();
	KURL remFileUrl(  execHost->getFishUrl() + "/tmp/" + uuid.toString() );
	kdDebug() << "UPLOADING: Temporary script file: " << localScriptFile << " to: " << remFileUrl.url() <<  endl;
	
	if ( ! TDEIO::NetAccess::upload( localScriptFile, remFileUrl, TDEApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "ERROR: Could not upload temp file." << endl;
		m_exitedNormal = false;
		m_status = 1;
		m_stdErr = i18n( "Could not upload the temporary comand script file." );
		// m_allOut = m_stdErr;
		m_stdOut = "";
		emit sigProcessFinished( m_jobName, m_status, m_exitedNormal, m_stdOut, m_stdErr, m_allOut );
		
		
		return;	
	}
	f->unlink();
	delete f;
	
	TQString cmd = "bash /tmp/" + uuid.toString();
	kdDebug() << "Execute: " << cmd << " at: " << execHost->getFishUrl() << endl;
	const TQString& ret = TDEIO::NetAccess::fish_execute( execHost->getFishUrl(), cmd, TDEApplication::kApplication()->mainWidget() ); 
	if ( ! TDEIO::NetAccess::del( remFileUrl, TDEApplication::kApplication()->mainWidget() ) ) {
		m_exitedNormal = false;
		m_status = 1;
		m_stdErr = i18n( "Could not delete the temporary comand script file." );
		// m_allOut = m_stdErr;
		m_stdOut = "";
		emit sigProcessFinished( m_jobName, m_status, m_exitedNormal, m_stdOut, m_stdErr, m_allOut );
		return;	
	}
	kdDebug() << "Got Output:" << ret << endl;
	
	
	const TQString& resultVal = ret.right( ret.find( "\n###RESULT:" ) + 10 );
	kdDebug() << "resultVal: " << resultVal << endl;
	m_status = 0;
	if ( ret.contains( "###RESULT: 0" ) == 0 ) {
		 m_status = 1;
	} 
	
	
	const TQString& retNew = ret.left( ret.find( "\n###RESULT:" ) );
	
	kdDebug() << "Real Output: " << retNew << endl;
	
	m_allOut = retNew;
	m_stdErr = retNew;
	m_stdOut = retNew;
	
	m_exitedNormal = true;
	
	
	emit sigProcessFinished( m_jobName, m_status, m_exitedNormal, retNew, retNew, retNew );
} 



void TDEProcessWrapper::slotKillJob() {
	kdDebug() << "void TDEProcessWrapper::killJob()" << endl;
	m_childproc->kill();
}

void TDEProcessWrapper::slotReceivedOutput( TDEProcess *, char *buffer, int buflen ) {
	kdDebug() << "TDEProcessWrapper::slotReceivedOutput( TDEProcess *, char *buffer, int buflen )" << endl;
	if ( !m_stderrbuf->isEmpty() ) {
		m_allOut.append( *m_stderrbuf );
		m_stdErr.append( *m_stderrbuf );
		emit sigReceivedStdErr( m_jobName,  *m_stderrbuf );
		*m_stderrbuf = "";
	}

	*m_stdoutbuf += TQString::fromLatin1( buffer, buflen );
	m_allOut.append( *m_stdoutbuf );
	m_stdOut.append( *m_stdoutbuf );
	
	emit sigReceivedStdOut( m_jobName, *m_stdoutbuf );
	*m_stdoutbuf = "";
	
	
// 	int pos;
// 	while ( ( pos = m_stdoutbuf->find( '\n' ) ) != -1 ) {
// 		TQString line = m_stdoutbuf->left( pos );
// 		m_allOut.append( *m_stdoutbuf );
// 		m_stdOut.append( *m_stdoutbuf );
// 		m_stdoutbuf->remove( 0, pos + 1 );
// 	}
}

void TDEProcessWrapper::slotReceivedError( TDEProcess *, char *buffer, int buflen ) {
	kdDebug() << "TDEProcessWrapper::slotReceivedError( TDEProcess *, char *buffer, int buflen )" << endl;
	// Flush stdout buffer
	if ( !m_stdoutbuf->isEmpty() ) {
		// Do What
		m_allOut.append( *m_stdoutbuf );
		m_stdOut.append( *m_stdoutbuf );
		*m_stdoutbuf = "";
	}

	*m_stderrbuf += TQString::fromLatin1( buffer, buflen );
	m_allOut.append( *m_stderrbuf );
	m_stdErr.append( *m_stderrbuf );
	*m_stderrbuf = "";
	
/*	int pos;
	while ( ( pos = m_stderrbuf->find( '\n' ) ) != -1 ) {
		TQString line = m_stderrbuf->left( pos );
		m_allOut.append( line );
		m_stdErr.append( line );
		m_stderrbuf->remove( 0, pos + 1 );
	}*/
}

void TDEProcessWrapper::slotProcessExited( TDEProcess* ) {
	kdDebug() << "TDEProcessWrapper::slotProcessExited()" << endl;
	m_status = m_childproc->exitStatus();
	m_exitedNormal = m_childproc->normalExit();
	
	
	emit sigProcessFinished( m_jobName, m_status, m_exitedNormal, m_stdOut, m_stdErr, m_allOut );
	return;
}


//##





} // end namespace KMF
