//
//
// C++ Implementation: $MODULE$
//
// Description:
//
//
// Author: Christian Hubinger <chubinger@irrsinnig.org>, (C) 2003
//
// Copyright: See COPYING file that comes with this distribution
//
//
/***************************************************************************
 *                                                                         *
 *   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 "kmfnetwork.h"

// QT includes
#include <tqfile.h>
#include <tqdom.h>
#include <tqstring.h>
#include <tqstringlist.h>

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

// Project includes
#include "../version.h"
#include "kmfcompilerinterface.h"
#include "kmfplugin.h"
#include "kmfpluginfactory.h"
#include "kmferror.h"
#include "kmfprotocol.h"
#include "kmfnetzone.h"
#include "kmftarget.h"
#include "kmfconfig.h"
#include "ipaddress.h"
#include "kmfgenericdoc.h"
#include "kmfiptdoc.h"
#include "xmlnames.h"


namespace KMF {

KMFNetwork::KMFNetwork( NetfilterObject* parent, const char* name, KMyFirewallInterface* ) : KMFDoc( parent, name ) {
	kdDebug() << "KMFNetwork::KMFNetwork( TQObject *parent, const char *name ) : KMFDoc( parent, name )" << endl;
	
	m_target = 0;
	m_myNetwork = 0;
	m_myNetwork = new KMFNetZone( this, Constants::MyNetwork_Name.latin1(), Constants::MyNetwork_Name );
	m_myNetwork->setNetwork( this );
	initDoc();
	KMFUndoEngine::instance()->clearStacks();
	KMFUndoEngine::instance()->saved();
}


KMFNetwork::~KMFNetwork() {}

int KMFNetwork::type() {
// 	kdDebug() << "IPTRule::type()" << endl;
	return NetfilterObject::KMFNETWORK;
}

KMFError* KMFNetwork::exportXMLRuleset( bool promtFile, bool asTemplate  ) {
	kdDebug() << "KMFNetwork::exportXMLRuleset( const KURL& )" << endl;
	KMFError *err = KMFDoc::exportXMLRuleset( promtFile, asTemplate );
	KMFUndoEngine::instance()->saved();
	return err;
}	

KMFError* KMFNetwork::exportXMLRuleset( const KURL& url  ) {
	kdDebug() << "KMFNetwork::exportXMLRuleset( const KURL& )" << endl;
	KMFError *err = KMFDoc::exportXMLRuleset( url );
	KMFUndoEngine::instance()->saved();
	return err;
}	

void KMFNetwork::clear() {
	kdDebug() << "void KMFNetwork::clear()" << endl;
	setDescription( i18n("No description available") );
	m_myNetwork->clear();
	resetUrl();
	initDoc();
}

const TQString& KMFNetwork::getFileDialogFilter() {
	return *( new TQString("*.kmfnet|KMyFirewall Network (*.kmfnet)") );
}

void KMFNetwork::setupDefaultHosts() {
	kdDebug() << "KMFNetwork::setupDefaultHosts()" << endl;	
	if ( ! m_myNetwork->findTargetByName( Constants::Localhost_Name, true ) ) {
		kdDebug() << "Creating Localhost" << endl;	
		KMFTarget * localhost = new KMFTarget( m_myNetwork, "My Local Comuter", i18n("My Local Comuter"), this );
		localhost->setGuiName( i18n("My Local Computer") );
		localhost->setDescription( i18n("Local copmuter running KMyFirewall") );
		localhost->setAddress( Constants::Localhost_IP );
		localhost->setName( Constants::Localhost_Name );
		localhost->setReadOnly( true );

		m_myNetwork->placeHostInZone( localhost );
		localhost->setName( Constants::Localhost_Name );
		localhost->setReadOnly( true );
		m_myNetwork->refreshNetworkTree();
	}
}


void KMFNetwork::initDoc() {
	kdDebug() << "void KMFNetwork::initDoc()" << endl;
	m_err = new KMFError;
	// setName( i18n("Unamed Ruleset") );
	m_url.setFileName( i18n( "Untitled" ) );
	m_myNetwork->setGuiName( i18n("Gloabl Network") );
	m_myNetwork->setDescription( i18n("This is the global zone that contains all valid IP addresses.") );
	m_myNetwork->setZone( IPAddress( 0,0,0,0 ), 0 );
	m_myNetwork->setReadOnly( true );
	m_myNetwork->clear();
	setupDefaultHosts();
	
	KMFTarget *tg = netzone()->findTargetByName( Constants::Localhost_Name );
	if ( ! tg ) {
		kdDebug() << "WARINING: KMFNetwork::initDoc() - netzone()->findTargetByName( 'localhost' ) returned 0" << endl; 
	}
	
	m_target = tg;
	kdDebug() << "KMFNetwork::initDoc() - CurrentTarget: " <<  m_target->name() << endl; 
}

void KMFNetwork::setCurrentTarget( KMFTarget* target ) {
	if ( ! target ) {
		kdDebug() << "KMFNetwork::setCurrentTarget( KMFTarget* target ): target was no vailid pointer!" << endl; 
	}
	
	m_target = target;
}

KMFDoc* KMFNetwork::currentDoc() {
	KMFTarget *curr = currentTarget();
	if ( ! curr ) {
		kdDebug() << "ERROR: No Current Target Found!!!" << endl;
		return 0;
	}
	KMFDoc *doc = curr->doc();
	if ( ! doc ) {
		kdDebug() << "ERROR: Current Target has no Doc assigned Found!!!" << endl;
		return 0;
	}
	return doc;
}

KMFIPTDoc* KMFNetwork::currentDocAsIPTDoc() {
	KMFDoc *doc = currentDoc();
	if ( ! doc ) {
		kdDebug() << "ERROR: Current Target has no Doc assigned Found!!!" << endl;
		return 0;
	}
	KMFIPTDoc *ret = dynamic_cast<KMFIPTDoc*>( doc );
	if ( ! ret ) {
		kdDebug() << "ERROR: Returning 0 KMFNetwork::currentDocAsIPTDoc()" << endl;
		return 0;
	}
	
	return ret;
}

KMFGenericDoc* KMFNetwork::currentDocAsGenericDoc(){
	KMFDoc *doc = currentDoc();
	if ( ! doc ) {
		kdDebug() << "ERROR: Current Target has no Doc assigned Found!!!" << endl;
		return 0;
	}
	KMFGenericDoc *ret = dynamic_cast<KMFGenericDoc*>( doc );
	if ( ! ret ) {
		kdDebug() << "ERROR: Returning 0 KMFNetwork::currentDocAsGenericDoc()" << endl;
		return 0;
	}
	return ret;
}

KMFTarget* KMFNetwork::currentTarget() {
	if ( ! m_target ) {
		// setupDefaultHosts();
		KMFTarget* tg = m_myNetwork->findTargetByName( Constants::Localhost_Name );
		if ( ! tg ) {
			kdDebug() << "ERROR: Retuning 0 KMFNetwork::currentTarget()" << endl;
			return 0;
		}
		m_target = tg;
	}
	
	// kdDebug() << "KMFNetwork::currentTarget(): Current Target: " << m_target->name() << endl;
	return m_target;
}

bool KMFNetwork::isEmpty() {
// 	kdDebug() << "bool KMFNetwork::isEmpty()" << endl;
	return false;
}

void KMFNetwork::parseDocument( const KURL& url, TQStringList& errors ) {
	kdDebug() << "KMFDoc* KMFNetwork::parseDocument( const KURL& url )" << endl;
	TQString xmlfile;
	if ( ! KIO::NetAccess::download( url, xmlfile, KApplication::kApplication()->mainWidget() ) ) {
		clear();
		m_url.setFileName( i18n( "Untitled" ) );
		return;
	}

	if ( !xmlfile.isEmpty() ) {
// 		kdDebug() << "Found xmlfile: " << xmlfile << endl;
		// delete old chainsets if there
		clear();
		TQFile kmfrsFile( xmlfile );
		TQDomDocument domTree;
		if ( !kmfrsFile.open( IO_ReadOnly ) ) {
			return;
		}
		if ( !domTree.setContent( &kmfrsFile ) ) {
			kmfrsFile.close();
			return;
		}
		kmfrsFile.close();

		
		kdDebug() << "############ Start Parsing ############" << endl;
		
		//FIXME: Preserve object uuids 
		// KMFUndoEngine::instance()->setPreserveObjectUuid( true );
		loadXML( domTree, errors );
		// KMFUndoEngine::instance()->setPreserveObjectUuid( false );
		
		// FIXME: Check errors
		
		// I'm the one and only network, so set to saved state after load
		KMFUndoEngine::instance()->clearStacks();
		KMFUndoEngine::instance()->saved();
		kdDebug() << "########## Finished Parsing ###########" << endl;

		// setUrl( url );
		m_url = url;
		m_newSavePathNeeded = false;
		emit documentChanged();
		KIO::NetAccess::removeTempFile( xmlfile );
		return;
	}
	KIO::NetAccess::removeTempFile( xmlfile );
	return;
}

const TQDomDocument& KMFNetwork::getDOMTree() {
	// kdDebug() << "const TQDomDocument& KMFNetwork::getDOMTree()" << endl;
	TQDomDocument doc( "kmyfirewall-ruleset" );
	TQDomElement root = doc.createElement( XML::KMFNetwork_DocumentElement );
	NetfilterObject::saveUuid( root );
	root.setAttribute( XML::Version_Attribute, KMYFIREWALL_VERSION );
	root.setAttribute( XML::MinVersion_Attribute, "1.1.0" );
	root.setAttribute( XML::MaxVersion_Attribute, "~" );
	if ( KMFConfig::useGenericInterface() ) {
		root.setAttribute( XML::Interface_Attribute, XML::GenericGUIInterface_Value );
	} else {
		root.setAttribute( XML::Interface_Attribute, XML::IPTablesGUIInterface_Value );
	}
	
	root.appendChild( m_myNetwork->getDOMTree() );
	doc.appendChild( root );
	return *( new TQDomDocument( doc ) );
}
void KMFNetwork::loadXML( const TQDomDocument& doc, TQStringList& errors ) {
	kdDebug() << "void KMFNetwork::loadXML( const TQDomDocument& )" << endl;
 	TQDomElement root = doc.documentElement();
 	if ( root.nodeName() != XML::KMFNetwork_DocumentElement ) {
		kdDebug() << "!!! ERROR: Wrong XML format " << root.nodeName() << " found !!!" << endl;
		errors.append( KMFError::getAsString( KMFError::FATAL, i18n("Wrong XML format <b>%1</b> found! Expected kmfnet").arg( root.nodeName() ) ) );
		return;
 	}
 	
 	
 	loadXML( root, errors );
}
void KMFNetwork::loadXML( TQDomNode root, TQStringList& errors ) {
// void KMFNetwork::loadXML( const TQDomDocument& doc ) {
	// kdDebug() << "void KMFNetwork::loadXML( const TQDomDocument& )" << endl;
	// TQDomElement root = doc.documentElement();
	NetfilterObject::loadUuid( root, errors );
	TQDomNode curr = root.firstChild();
	while ( !curr.isNull() ) {
		kdDebug() << "Parsing Node: " << curr.nodeName() << endl;
		if ( curr.isElement() && curr.nodeName() == XML::NetZone_Element ) {
			TQString name = curr.toElement().attribute( XML::Name_Attribute );
			if ( name == Constants::MyNetwork_Name ) {
				kdDebug() << "Parsing netzone: " << curr.toElement().attribute(  XML::Name_Attribute ) << endl;
				m_myNetwork->loadXML( curr, errors );
			}
			
		} 
		curr = curr.nextSibling();
	}
}

}

