/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
/*
Author: Christian Hubinger <chubinger@irrsinnig.org>, (C) 2001-2008
*/

#include "kmftarget.h"


// QT includes
#include <tqwidget.h>

// KDE includes
#include <kapplication.h>
#include <klocale.h>
#include <kdebug.h>
#include <ktrader.h>
#include <kstandarddirs.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>

// Project Inclueds
#include "ipaddress.h"
#include "kmferror.h"
#include "kmfnetzone.h"
#include "kmfnetwork.h"
#include "kmftargetconfig.h"
#include "kmfconfig.h"
#include "kmfdoc.h"
#include "kmfiptdoc.h"
#include "kmfgenericdoc.h"
#include "kmfrulesetdoc.h"
#include "kmfinstallerinterface.h"
#include "kmfcompilerinterface.h"
#include "kmfpluginfactory.h"
#include "kprocesswrapper.h"
#include "xmlnames.h"

namespace KMF {

KMFTarget::KMFTarget( NetfilterObject *parent, const char* name, const TQString&, KMFNetwork* net ) : NetfilterObject( parent, name ) {
	kdDebug() << "KMFTarget::KMFTarget( NetfilterObject *parent, const TQString& name )" << endl;
	m_network = net;
	m_address = new IPAddress( 0,0,0,0 );
	m_ssh_port = 22;
	m_zone = 0;
	m_config = new KMFTargetConfig( this, name );
	m_doc = 0;
	
	m_readOnly = false;
}

KMFTarget::~KMFTarget() {
	kdDebug() << "KMFTarget::~KMFTarget()" << endl;
	delete m_address;
	if ( m_doc ) {
		m_doc->deleteLater();
	}
}

void KMFTarget::ensureDoc() {
	if ( m_doc == 0 ) {
		if ( KMFConfig::useGenericInterface() ) {
			kdDebug() <<  "Creating new KMFGenericDoc( this, KMFGenericDoc, this )"  <<  endl;
			m_doc = new KMFGenericDoc( this, "KMFGenericDoc", this );
		} else {
			kdDebug() <<  "Creating new KMFIPTDoc( this, KMFIPTDoc, this )"  <<  endl;
			m_doc = new KMFIPTDoc( this, "KMFIPTDoc", this );
		}
	}
}

void KMFTarget::clear() {
	if( m_doc ) {
		m_doc->clear();
	}
}

KMFDoc* KMFTarget::doc() {
	ensureDoc();
	return m_doc;
}


KMFNetwork* KMFTarget::network() {
	kdDebug() << "KMFTarget::network()" << endl;
	return m_network;
}

TQString KMFTarget::toString() {
	TQString ret = TQString( 
	"Host: " +  address()->toString() + 
	" name: " + NetfilterObject::name() + 
	" GUIName: " + guiName() );
	return ret;
}

bool KMFTarget::isLocalhost() {
	return NetfilterObject::name() == Constants::Localhost_Name;
}

bool KMFTarget::isLocalExecuteTarget() {
	return ( NetfilterObject::name() == Constants::Localhost_Name && ! KMFConfig::useSSHForLocalhost() );
} 

TQString KMFTarget::toFriendlyString() {
	TQString ret = TQString( guiName() + " [" + address()->toString() +"]" );
	return ret;
}

KMFTargetConfig *KMFTarget::config() {
	return m_config;
}

KMFInstallerInterface* KMFTarget::installer() {
	return KMFPluginFactory::KMFInstaller( this );
}
KMFCompilerInterface* KMFTarget::compiler() {
	return KMFPluginFactory::KMFCompiler( this );
}

KMFRulesetDoc* KMFTarget::rulesetDoc() {
//	return dynamic_cast<KMFRulesetDoc*>( this );
	ensureDoc();
	return dynamic_cast<KMFRulesetDoc*>( m_doc );
}

int KMFTarget::type() {
// 	kdDebug() << "KMFTarget::type()" << endl;
	return NetfilterObject::KMFTARGET;
}

void KMFTarget::setSSHPort( int port ) {
	m_ssh_port = port;
}

void KMFTarget::setReadOnly( bool onOff ) {
	m_readOnly = onOff;
}	


void KMFTarget::setGuiName( const TQString& name){
	if ( !name.isNull() && !name.isEmpty() && m_guiName != name ) {
		m_guiName = name;
		changed();
	}
}

void KMFTarget::setAddress( const TQString& addr ) {
	m_address->setAddress( addr );
	changed();
}

void KMFTarget::setParentZone( KMFNetZone* zone ){
	m_zone = zone;
	changed();
}



bool KMFTarget::isCurrentTarget() {
	kdDebug() << "KMFTarget::isCurrentTarget()" << endl;
	if ( ! zone() ) {
		kdDebug() << "zone() == 0" << endl;
		return false;
	}	
	if ( ! zone()->network() ) {
		kdDebug() << "zone()->network() == 0" << endl;
		return false;
	}
	return ( zone()->network()->currentTarget()->uuid() == this->uuid() );
}

const TQString& KMFTarget::name() {
	// kdDebug() << "TQString& KMFTarget::name()" << endl;
	if ( ! zone() || readOnly() ) {
		return NetfilterObject::name();
	}	
	
	int index = 0;
	bool found = false;
	KMFNetZone *z = zone();
	TQPtrListIterator<KMFTarget> it( z->hosts() );	
	while ( it.current() && ! found ) {
		if ( it.current() == this ) {
			found = true;
		}
		index++;
		++it;
	}
	const TQString& s = zone()->name() + "_target_"+ TQString::number( index );
	return *( new TQString(s) );
}

const TQString& KMFTarget::getFishUrl()  {
	TQString addr = isLocalhost() ? "localhost" : m_address->toString();
	return *( new TQString("fish://root@" + addr + ":" +  TQString::number( m_ssh_port ) ) );
}

KMFError* KMFTarget::tryAutoConfiguration() {
	kdDebug() << "KMFError* KMFTarget::tryAutoConfiguration()" << endl;
	KMFError* err = new KMFError();
	
	if ( isLocalExecuteTarget() ) {
		KProcessWrapper::instance()->slotStartLocalJob( "autoconf", "uname", false, true );
	} else {
		KProcessWrapper::instance()->slotStartRemoteJob( "autoconf", "uname", rulesetDoc()->target() );
	}
	if ( KProcessWrapper::instance()->exitStatus() != 0 ) {	
		kdDebug() << "ERROR:" << KProcessWrapper::instance()->stdErr() << endl;
		err->setErrType( KMFError::NORMAL );
		err->setErrMsg( KProcessWrapper::instance()->stdErr() );
		return err;	 
	}
	TQString retValUname = KProcessWrapper::instance()->stdCombined();
	kdDebug() << "Found OS: " << retValUname << endl;
	
	config()->setOS( retValUname.lower().remove( "\n" ).remove( " " ) );
	
	TQString path = "kmyfirewall/scripts/installer/";
	path.append( config()->oS().lower() );
	path.append( "/autoconfighelper.sh" );
	kdDebug() << "Search Path: " << path << endl;
	TQString localFile = KGlobal::dirs() ->findResource( "data", path );
	
	if ( ! KIO::NetAccess::exists( localFile, false, KApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "No autoconfigure script found for os: " << config()->oS() << endl;
		emit sigTargetChanged( this );
		err->setErrType( KMFError::NORMAL );
		err->setErrMsg( i18n("No autoconfigure script found for os: %1").arg( config()->oS() ) );
		return err;
	}
	
	if ( isLocalExecuteTarget() ) {
		KProcessWrapper::instance()->slotStartLocalJob( "autoconf", localFile, false, true );
	} else {
		KProcessWrapper::instance()->slotStartRemoteJob( "autoconf", localFile, rulesetDoc()->target() );
	}
	
	
	if ( KProcessWrapper::instance()->exitStatus() != 0 ) {
		kdDebug() << "ERROR:" << KProcessWrapper::instance()->stdErr() << endl;
		err->setErrType( KMFError::NORMAL );
		err->setErrMsg( KProcessWrapper::instance()->stdErr() );
		return err;	 
	}
	TQString retVal = KProcessWrapper::instance()->stdCombined();
	kdDebug() << "AutoConf XML: \n"<< retVal << endl;
	TQDomDocument doc;
	doc.setContent( retVal );
	TQStringList errors;
	
	config()->setDistribution( "" );
	config()->setIPTPath( "" );
	config()->setInitPath( "" );
	config()->setInterfaces( "" );
	config()->setModprobePath( "" );
	config()->setRcDefaultPath( "" );
	config()->loadXML( doc, errors );
	
	
	emit sigTargetChanged( this );
	err->setErrType( KMFError::OK );
	err->setErrMsg( "" );
	return err;	
}

// void KMFTarget::slotProcessFinished( const TQString& jobName, int status, bool exitedNormal, const TQString& stdOut, const TQString& stdErr, const TQString& completeOut ) {
// 	kdDebug() << "KMFTarget::slotProcessFinished( const TQString& jobName, int status, bool exitedNormal, const TQString& stdOut, const TQString& stdErr, const TQString& completeOut )" << endl;
// 	
// 	disconnect( 
// 		KProcessWrapper::instance(), 
// 		TQT_SIGNAL( sigProcessFinished( 
// 			const TQString&, 
// 			int, 
// 			bool, 
// 			const TQString&, 
// 			const TQString& , 
// 			const TQString& ) ),
// 		this, 
// 		TQT_SLOT( slotProcessFinished( 
// 			const TQString&, 
// 			int, 
// 			bool, 
// 			const TQString&, 
// 			const TQString&, 
// 			const TQString& ) ) );
// 	
// 	
// 	const TQString& ret = completeOut; 
// 	kdDebug() << "Got Output: " << ret << endl;
// 	
// 	TQDomDocument doc;
// 	doc.setContent( ret );
// 	TQStringList errors;
// 	
// 	config()->setDistribution( "" );
// 	config()->setIPTPath( "" );
// 	config()->setInitPath( "" );
// 	config()->setInterfaces( "" );
// 	config()->setModprobePath( "" );
// 	config()->setRcDefaultPath( "" );
// 	
// 	config()->loadXML( doc, errors );
// 
// 	emit sigTargetChanged( this );
// }

const TQDomDocument& KMFTarget::getDOMTree() {
	// kdDebug() << "const TQDomDocument& KMFTarget::getDOMTree() " << endl;
	TQDomDocument doc;
	
	TQDomElement root = doc.createElement( XML::Target_Element );
	NetfilterObject::saveUuid( root );
	root.setAttribute( XML::Name_Attribute, name() );
	root.setAttribute( XML::GUIName_Attribute, m_guiName );
	root.setAttribute( XML::Description_Attribute, description() );
	root.setAttribute( XML::Address_Attribute, m_address->toString() );
	root.setAttribute( XML::SSHPort_Attribute, sshPort() );
	
	root.setAttribute( XML::ReadOnly_Attribute, readOnly() ? XML::BoolOn_Value : XML::BoolOff_Value );
	
	root.appendChild( config()->getDOMTree( ) );
		
	// TQDomElement root = getDOM();
	ensureDoc();
	root.appendChild( m_doc->getDOMTree().documentElement() );
	doc.appendChild( root );
	return *( new TQDomDocument( doc ) );
}

void KMFTarget::loadXML( const TQDomDocument& doc, TQStringList& errors ) {
	kdDebug() << "void KMFTarget::loadXML( const TQDomDocument& )" << endl;
 	TQDomElement root = doc.documentElement();
 	loadXML( root, errors );
}
void KMFTarget::loadXML( TQDomNode root, TQStringList& errors ) {
 	kdDebug() << "void KMFTarget::loadXML( const TQDomDocument& )" << endl;
	NetfilterObject::loadUuid ( root, errors );
	TQString name = "";
	TQString guiName = "";
	TQString desc = "";
	TQString address = "";
	TQString readonly = "";
	TQString sshPort = "";

	name = root.toElement().attribute(  XML::Name_Attribute );
	
	setDescription( root.toElement().attribute( XML::Description_Attribute ) );
	setGuiName( root.toElement().attribute( XML::GUIName_Attribute ) );
	setAddress( root.toElement().attribute( XML::Address_Attribute ) );
	if ( root.toElement().hasAttribute( XML::SSHPort_Attribute ) ) {
		setSSHPort( root.toElement().attribute( XML::SSHPort_Attribute ).toUInt() );
	}
	if ( root.toElement().attribute( XML::ReadOnly_Attribute ) == XML::BoolOn_Value ) {
		setReadOnly( true );	
	} else {
		setReadOnly( false );
	}
	
	TQDomNode curr = root.firstChild();
	while ( !curr.isNull() ) {
		if ( curr.isElement() && ( curr.nodeName() == XML::TargetConfig_Element ) ) {
			kdDebug() << "void KMFTarget::loadXML( ) - parse targetconfig " << endl;
			config()->loadXML( curr, errors );
		}
		if ( curr.isElement() && 
			( ( curr.nodeName() == XML::GenericDoc_DocumentElement ) || ( curr.nodeName() == XML::IPTDoc_DocumentElement ) ) ) {
			kdDebug() << "void KMFTarget::loadXML( ) - parse ruleset: " << curr.nodeName() << endl;
			ensureDoc();
			m_doc->loadXML( curr, errors );
		}
		curr = curr.nextSibling();
	}
	kdDebug() << "void KMFTarget::loadXML( ) - My Config: " << toString() << endl;
	changed();
}

}

