//
// C++ Implementation: kmfnetzone
//
// 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 "kmfnetzone.h"

// TQt includes
#include <tqdom.h>
#include <tqvaluelist.h>
#include <tqobject.h>

// KDE includes
#include <kdebug.h>
#include <tdelocale.h>

// Project includes
#include "kmfcheckinput.h"
#include "kmfnetwork.h"
#include "kmfprotocol.h"
#include "kmfprotocollibrary.h"
#include "kmfprotocolusage.h"
#include "kmfnetwork.h"
#include "kmfnethost.h"
#include "kmftarget.h"
#include "kmfgenericdoc.h"
#include "kmferror.h"
#include "ipaddress.h"
#include "kmfnetzonelist.h"
#include "netfilterobject.h"
#include "xmlnames.h"

#include <stdlib.h>

namespace KMF {

KMFNetZone::KMFNetZone( NetfilterObject *parent, const char* name, const TQString& zoneName ) : NetfilterObject( parent, name ) {
	kdDebug() << "KMFNetZone::KMFNetZone( NetfilterObject *parent, const char* name, const TQString& zoneName )" << endl;
	m_doc = 0;
	m_network = 0;
	m_zone = 0;
	m_guiName = i18n( "New Zone" );
	m_readOnly = false;
	m_err = new KMFError();
	m_address = new IPAddress( 0, 0, 0, 0 );
	m_protocols.setAutoDelete( false );
	m_zones.setAutoDelete( false );
	m_hosts.setAutoDelete( false );
	if ( zoneName.isNull() ) {
		setName( i18n( "New Zone" ) );
	} else {
		setName( zoneName );
	}
	if ( KMFNetZone * zone = dynamic_cast<KMFNetZone*> ( parent ) ) {
		m_zoneType = NODE;
		m_zone = zone;
		setZone( *m_zone->address(), m_zone->maskLength() /* , *m_zone->mask() */ );
	} else if ( KMFGenericDoc * doc = dynamic_cast<KMFGenericDoc*> ( parent ) ) {
		m_zoneType = ROOT;
		m_doc = doc;
	} else if ( KMFNetwork * doc = dynamic_cast<KMFNetwork*> ( parent ) ) {
		m_zoneType = ROOT;
		m_network = doc;
	}

	// kdDebug() << "m_zone" << m_zone << endl;
	// exit(0);
}


KMFNetZone::~KMFNetZone() {
	kdDebug() << "~KMFNetZone: Deleting Children" << endl;
	m_address->setAddress( "0.0.0.0" );
	clear();
	delete m_address;
	delete m_err;
}

int KMFNetZone::operator==( const KMFNetZone& zone ) {
	if ( IPAddress::calcLenthToMask( *mask() ) >  IPAddress::calcLenthToMask( *zone.mask() ) ) {
		return 1;
	} else if ( IPAddress::calcLenthToMask( *mask() ) == IPAddress::calcLenthToMask( *zone.mask() ) ){
		return 0;
	} else {
		return -1;
	}
}

bool KMFNetZone::isSameZone( KMFNetZone* zone ) {
	if ( IPAddress::calcLenthToMask( *mask() ) >  IPAddress::calcLenthToMask( *zone->mask() ) ) {
		return false;
	} else if ( IPAddress::calcLenthToMask( *mask() ) == IPAddress::calcLenthToMask( *zone->mask() ) ){
		return true;
	} else {
		return false;
	}
}

int KMFNetZone::type() {
	// kdDebug() << "KMFNetZone::type()" << endl;
	return NetfilterObject::NETZONE;
}

void KMFNetZone::clear() {
	m_zones.setAutoDelete( true ); 
	m_hosts.setAutoDelete( true ); 
	m_protocols.setAutoDelete( true ); 
	
	m_zones.clear();
	m_hosts.clear();
	m_protocols.clear();
	
	m_zones.setAutoDelete( false ); 
	m_hosts.setAutoDelete( false ); 
	m_protocols.setAutoDelete( false ); 
	changed();
}

KMFGenericDoc* KMFNetZone::doc() const {
	if ( m_zoneType == ROOT ) {
		return m_doc;
	} else if ( m_zoneType == NODE ) {
		return m_zone->doc();
	}
	return 0;
}

KMFNetwork* KMFNetZone::network() const {
	if ( m_zoneType == ROOT ) {
		return m_network;
	} else if ( m_zoneType == NODE ) {
		return m_zone->network();
	}
	return 0;
}

void KMFNetZone::setNetwork( KMFNetwork* net ) {
	m_network = net;
}

KMFNetZone* KMFNetZone::zone() const {
	//kdDebug() << "KMFNetZone::zone()"  << endl;
	/* if ( m_zoneType == NODE ) {
		return m_zone;
	}*/

	return m_zone;
}

KMFNetZone* KMFNetZone::rootZone() {
	// kdDebug() << "KMFNetZone::rootZone()"  << endl; 
	if  ( isRootZone() ) {
		return this;
	} 
	return zone()->rootZone();
}

bool KMFNetZone::isRootZone() {
	// kdDebug() << "bool KMFNetZone::isRootZone(): " << NetfilterObject::name() << endl;
	if ( ! m_zone || isSameZone( m_zone ) ) {
		// kdDebug() << "KMFNetZone: " << NetfilterObject::name() << " is a Root Zone" << endl;
		return true;
	}
	return false;
}

const TQString& KMFNetZone::name() {
	// kdDebug() << "TQString& KMFNetZone::name()" << endl;
	// return "" + uuid();
	
	const TQString& s = generateName( "" );
	return s;
}

const TQString& KMFNetZone::generateName( const TQString& nam ) {
	// kdDebug() << "TQString& KMFNetZone::generateName(" << nam << ")" << endl;
	if ( ! isRootZone() ) {
		TQString s = "";
		s.setNum( zone()->zones().find( this ) );
		return *(new TQString( zone()->generateName( "_zone_" + s + "_" + nam )));
	} else {
		TQString s = "";
		s.append( NetfilterObject::name() );
		s.append( nam );
		// kdDebug() << "TQString& KMFNetZone::generateName(" << nam << ") on Root Zone returns: " << s << endl;
		return *(new TQString(s));
	}
}

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

void KMFNetZone::setGuiName( const TQString& name ) {
	if ( name == m_guiName ) {
		return;
	}
	m_guiName = name;
	changed();
}

TQString KMFNetZone::zoneInfo() {
	return TQString("Zone: guiName: %1 name: %2 objectUuid: %3" ).arg( guiName() ).arg( name() ).arg( uuid() );
}

void KMFNetZone::setMaskLength( int len ){
	// kdDebug() << "void KMFNetZone::setMaskLength( int len )" << endl;
	if ( len < 0 || len > 32 ) {
		kdDebug() << "ERROR: Mask Lengh invalid: " << len << endl;
		m_maskLen = -1;
		return;
	}
	if ( m_maskLen == len ) {
		return;
	}
	m_maskLen = len;
	changed();
}

TQPtrList<KMFProtocolUsage>& KMFNetZone::protocols() const {
	TQPtrList<KMFProtocolUsage>* ret_val = new TQPtrList<KMFProtocolUsage>;
	*ret_val = m_protocols;
	return *ret_val;
}

TQPtrList<KMFNetZone>& KMFNetZone::zones () const {
	TQPtrList<KMFNetZone>* ret_val = new TQPtrList<KMFNetZone>;
	*ret_val = m_zones;
	return *ret_val;
}

TQPtrList<KMFTarget>& KMFNetZone::hosts () const {
	TQPtrList<KMFTarget>* ret_val = new TQPtrList<KMFTarget>;
	*ret_val = m_hosts;
	return *ret_val;
}

void KMFNetZone::setParentZone( KMFNetZone* zone ) {
	kdDebug() << "KMFTarget* KMFNetZone::setParentZone( const KMFNetZone* " <<  ( zone != 0 ? zone->guiName() : "" ) << " in Zone" << guiName() << endl;
	m_zone = zone;
	changed();
}

KMFNetHost* KMFNetZone::findNetHostByName( const TQString& name, bool fromRoot ) {
	KMFTarget* t = findTargetByName( name, fromRoot );
	if ( t && dynamic_cast<KMFNetHost*>(t) ) {
		return dynamic_cast<KMFNetHost*>(t);
	}
	return 0;
}

KMFTarget* KMFNetZone::findTargetByName( const TQString& name, bool fromRoot ) {
	kdDebug() << "KMFTarget* KMFNetZone::findTargetByName( const TQString& " << name << ", " <<  fromRoot <<" )" << endl;
	if ( ! fromRoot ) {
		return findTargetByName_internal( name );
	} else {
		if ( ! isRootZone() ) {
			return rootZone()->findTargetByName_internal( name );
		} else {
			return	findTargetByName_internal( name );
		}
	}
}

KMFTarget* KMFNetZone::findTargetByName_internal( const TQString& name ) {
	kdDebug() << "KMFTarget* KMFNetZone::findTargetByName_internal( const TQString& " << name << "" << endl;
	KMFTarget* foundHost = 0;
	TQPtrListIterator<KMFNetZone> it ( m_zones );
	while ( it.current() ) {
		KMFNetZone *z = *it;
		++it;
		foundHost = z->findTargetByName_internal( name );
		if ( foundHost ) {
			kdDebug() << "KMFNetZone::findTargetByName(..) Found in Child Zone" << endl; 
			return foundHost;
		}
	}

	TQPtrListIterator<KMFTarget> itHosts ( m_hosts );
	while ( itHosts.current() ) {
		KMFTarget *z = *itHosts;
		++itHosts;
		kdDebug() << "KMFNetZone::findTargetByName( " << name << " ) compare with:" << z->name() << endl;
		if ( z->name() == name ) {
			kdDebug() << "KMFNetZone::findTargetByName(..) MATCHED" << endl; 
			return z;
		}
	}

	return 0;
}

KMFNetZone* KMFNetZone::findNetZoneByName( const TQString& name, bool fromRoot ) {
	kdDebug() << "KMFTarget* KMFNetZone::findNetZoneByName( const TQString& " << name << ", " <<  fromRoot <<" )" << endl;
	if ( ! fromRoot ) {
		return findNetZoneByName_internal( name );
	} else {
		if ( ! isRootZone() ) {
			return rootZone()->findNetZoneByName_internal( name );
		} else {
			return	findNetZoneByName_internal( name );
		}
	}
}

KMFNetZone* KMFNetZone::findNetZoneByName_internal( const TQString& name ) {
	kdDebug() << "KMFTarget* KMFNetZone::findNetZoneByName_internal( const TQString& " << name << "" << endl;
	KMFNetZone* foundHost = 0;
	TQPtrListIterator<KMFNetZone> it ( m_zones );
	while ( it.current() ) {
		KMFNetZone *z = *it;
		++it;
		foundHost = z->findNetZoneByName_internal( name );
		if ( foundHost ) {
			kdDebug() << "KMFNetZone::findNetZoneByName(..) Found in Child Zone" << endl; 
			return foundHost;
		}
	}

	TQPtrListIterator<KMFNetZone> itHosts ( m_zones );
	while ( itHosts.current() ) {
		KMFNetZone *z = *itHosts;
		++itHosts;
		kdDebug() << "KMFNetZone::findNetZoneByName( " << name << " ) compare with:" << z->name() << endl;
		if ( z->name() == name ) {
			kdDebug() << "KMFNetZone::findNetZoneByName(..) MATCHED" << endl; 
			return z;
		}
	}

	return 0;
}




KMFProtocolUsage* KMFNetZone::findProtocolUsageByProtocolUuid( const TQUuid& uuid ) const {
 	kdDebug() << "KMFProtocol* KMFNetZone::findProtocolUsageByProtocolUuid( const TQString& " << uuid << " ) const" << endl;
	if ( (new TQUuid(uuid))->isNull() ) {
		exit(1);
	}
	
	TQPtrListIterator<KMFProtocolUsage> it( m_protocols );
	while ( it.current() ) {
		KMFProtocolUsage * p = it.current();
		++it;
		if ( p->protocol()->uuid() == uuid ) {
			kdDebug() << "Found Protocol: name=" << p->protocol()->name() << " uuid="  << uuid << endl;
			return p;
		}
	}
	return 0;
}

bool KMFNetZone::protocolInherited( const TQUuid& uuid ) const {
	// 	kdDebug() << "bool KMFNetZone::protocolInherited() const" << endl;
	if ( m_zoneType != NODE ) {
		// 		kdDebug() << "At ROOT node stopping search" << endl;
		return false;
	}
	if ( uuid.isNull() ) {
		kdDebug() << "ERROR: KMFNetHost::protocolInherited(): uuid.isNull() == true" << endl;
		exit(1);
	}

	TQPtrListIterator<KMFProtocolUsage> it( m_zone->protocols() );
	while ( it.current() ) {
		KMFProtocolUsage * p = it.current();
		++it;
		if ( p->protocol()->uuid() == uuid ) {
 			kdDebug() << "Found Inherited Protocol: " << p->protocol()->name() << endl;
			return true;
		}
	}
	return m_zone->protocolInherited( uuid );
}

void KMFNetZone::setZone( const IPAddress& from, int maskLen  ) {
	m_address->setAddress( from.toString() );
	setMaskLength( maskLen );
	changed();
}


KMFNetZone* KMFNetZone::addZone( const TQString& name, KMFError* err ) {
// 	kdDebug() << "KMFProtocol* KMFNetZone::addZone( const TQString& name, KMFError* err )" << endl;
	TQPtrListIterator<KMFNetZone> it( m_zones );
	while ( it.current() ) {
		KMFNetZone * z = it.current();
		++it;
		if ( z->name() == name ) {
			err->setErrType( KMFError::NORMAL );
			err->setErrMsg( i18n( "Zone %1 already exists, please try again with another name" ).arg( name ) );
			return 0;
		}
	}
	KMFNetZone* new_zone = new KMFNetZone( this, name.latin1(), name );
	new_zone->setMaskLength( 32 );
	new_zone->address()->setAddress( 255, 255, 255, 255 );
	new_zone->setParentZone( this );
	new_zone->setNetwork( network() );
	m_zones.append( new_zone );
	err->setErrType( KMFError::OK );
	changed();
	return new_zone;
}

void KMFNetZone::delZone( KMFNetZone* zone, bool destructive ) {
// 	kdDebug() << "void KMFNetZone::delZone( KMFNetZone* z )" << endl;
	m_zones.remove( zone );
	if ( destructive ) {
		zone->deleteLater();;
	}
	changed();
}




KMFProtocolUsage* KMFNetZone::addProtocolUsage( const TQUuid& protocolUuid, const TQDomDocument& xml ) {
 	kdDebug() << "KMFProtocol* KMFNetZone::addProtocol( const TQUuid& " << protocolUuid  << " , const TQDomDocument& " << xml.toString() << " )" << endl;
 	
 	if ( protocolUuid.isNull() ) {
		exit(1);
	}
 	
 	KMFProtocolUsage* old =  findProtocolUsageByProtocolUuid( protocolUuid );
	if ( old ) {
		kdDebug() << "WARNING: Ignoreing duplicate protocol entry in zone, Returning existing" << endl;
		return old;
	}
	
	KMFProtocol* prot = KMFProtocolLibrary::instance()->findProtocolByUuid( protocolUuid );
	if ( ! prot ) {
		kdDebug() << "ERROR: No Protocol Found By uuid: " << protocolUuid << endl;
		return 0;
	}
	
	KMFProtocolUsage* new_protocol = prot->createUsage();
	TQStringList *errors = new TQStringList();
	new_protocol->loadXML( xml, *errors );
	
	// FIXME: Check Errors
	if ( ! new_protocol->validUsage() ) {
		kdDebug() << "WARNING: ProtocolUsage parsed from: " << xml.toString() << " is not Valid! Skippin Usage." << endl;
		return 0;
	}
	new_protocol->setProtocol( prot );
	m_protocols.append( new_protocol );
	disconnect( new_protocol, TQ_SIGNAL( destroyed( TQObject* ) ),
		this, TQ_SLOT( slotOnProtocolUsageDeleted( TQObject* ) ) );
	connect( new_protocol, TQ_SIGNAL( destroyed( TQObject* ) ),
		this, TQ_SLOT( slotOnProtocolUsageDeleted( TQObject* ) ) );
	changed();
	return new_protocol;
}

void KMFNetZone::delProtocolUsage( KMFProtocolUsage* prot, bool destructive ) {
	TQPtrListIterator<KMFProtocolUsage> it( m_protocols );
	bool deleted = false;
	while ( it.current() ) {
		KMFProtocolUsage * p = it.current();
		++it;
		if ( p->name() == prot->name() ) {
			kdDebug() << "Deleting Protocol: " << p->name() << " from zone: " << name() << endl;
			m_protocols.remove( p );
			if ( destructive ) {
				p->deleteLater();
			}
			deleted = true;
			changed();
		}
	}
	if ( ! deleted ) {
		kdDebug() << "WARNING: Couldn't delete protocol: " << prot->name() << " from zone:  " << name() << endl;
	}
}

void KMFNetZone::slotOnProtocolUsageDeleted( TQObject* prot ) {
	kdDebug() << "KMFNetZone::slotOnProtocolUsageDeleted... Zone name: " << this->name() << endl;
	TQPtrListIterator<KMFProtocolUsage> it( m_protocols );
	while ( it.current() ) {
		KMFProtocolUsage * p = it.current();
		++it;
		if ( p == prot ) {
			kdDebug() << "Deleting Protocol" << endl;
			m_protocols.remove( p );
			p->deleteLater();
			changed();
			return;
		}
	}
}

KMFNetZone* KMFNetZone::placeZoneInZone( KMFNetZone* zone ) {
// 	kdDebug() << "KMFNetZone::placeZoneInZone_internal... Zone name: " << this->name() << endl;
	if ( zone->zone() ) {
		zone->zone()->delZone( zone, false );
	}
// 	kdDebug() << "Placing zone: " << zone->name() << " in zone: " << name() << " GUIName: " << guiName() <<   endl;
	zone->setParentZone( this );
	zone->setNetwork( network() );
	if ( ! zone->readOnly() ) {
		TQString hostnum;
		hostnum = hostnum.setNum( m_zones.count() + 1 );
/*		TQString host_name = "zone_" + this->name() + "_" + hostnum;
		zone->setName( host_name );*/
	}
	m_zones.append( zone );
	changed();
	return zone;
}

TQString KMFNetZone::toString() {
	TQString ret = TQString( 
	"Zone: " +  address()->toString() + 
	"/%1" + 
	" name: " + NetfilterObject::name() + 
	" GUIName: " + guiName() ).arg(maskLength()) ;

	return ret;
}


// KMFTarget* KMFNetZone::placeHostInZone( KMFTarget* host ) {
// 	kdDebug() << "KMFNetZone::placeHostInZone..." << " Zone name: " << this->name() << endl;
// 	return placeHostInZone_internal( host );
// }


KMFTarget* KMFNetZone::placeHostInZone( KMFTarget* host ) {
/*	TQString s = name();
	
	
// 	kdDebug() << "KMFNetZone::placeHostInZone_internal..." << " Zone name: " << name() << endl;
	*/
	
	/*
	kdDebug() << "s: " <<  s << endl;
	
	
	kdDebug() << "asdasdg" << endl;*/
	
	
	if ( host->zone() ) {
		host->zone()->delHost( host, false );
	}
 	kdDebug() << "Placing zhostone: " << host->name() << " in zone: " << this->name() << endl;
	host->setParentZone( this );
	if ( ! host->readOnly() ) {
		TQString hostnum;
		hostnum = hostnum.setNum( m_hosts.count() + 1 );
		TQString host_name = "host_" + this->name() + "_" + hostnum;
		host->setName( host_name );
	}
	m_hosts.append( host );
	changed();
	return host;
}

void KMFNetZone::refreshNetworkTree() {
	kdDebug() << "KMFNetZone::refreshNetworkTree()" << endl;

	// TQPtrList<KMFNetZone>* allZones = new TQPtrList<KMFNetZone>();
	KMFNetZoneList* allZones = new KMFNetZoneList();
	kdDebug() << "Fetch All Zones..." << endl;
	getAllZones( rootZone(), allZones );
	allZones->sort();
	kdDebug() << "Found " << allZones->count() << " Zones" << endl;
	
	// Resort Zones
	TQPtrListIterator<KMFNetZone> it( *allZones );
// 	while ( it.current() ) {
// // 		kdDebug() << "Found Zone : " << it.current()->toString() <<   endl;
// 		++it;
// 	}
	
	// Reinsert Zones
	TQPtrListIterator<KMFNetZone> it3( *allZones );

	for( int i = allZones->count() - 1; allZones->count() > 0 && i >= 0; i-- ) {
		KMFNetZone *currZone = allZones->at(i);
		// kdDebug() << "currZone: " << currZone->guiName() << endl; 
		for( int j = i - 1;  allZones->count() > 1 && j >= 0; j-- ) {
			KMFNetZone *thisTry = allZones->at(j);
			if (  thisTry != currZone && ! (
						( thisTry->address() == currZone->address() ) == IPAddress::EQUAL &&
						thisTry->maskLength() == currZone->maskLength()
					) &&
					
					
					
					IPAddress::hostsOnSameNetwork( *thisTry->address(), *currZone->address(), thisTry->maskLength() ) ) {
				thisTry->placeZoneInZone( currZone );
				// allZones->remove( thisTry );
// 				kdDebug() << "Add Zone: " << currZone->toString() << endl;
// 				kdDebug() << "to Zone : " << thisTry->toString() << endl;
				break;
				// i--;
			}
		}	
	}
	
	kdDebug() << "Finished Zone Reorder" << endl << endl;
	
	TQPtrList<KMFTarget>* allHosts = new TQPtrList<KMFTarget>();
	kdDebug() << "Fetch All Hosts..." << endl;
	
	
	for( uint i = 0; i < allZones->count(); i++ ) {
		TQPtrListIterator<KMFTarget> it_hosts( allZones->at(i)->hosts() );
		while ( it_hosts.current() ) {
			allHosts->append( it_hosts.current() );
// 			kdDebug() << "Found: " << it_hosts.current()->toString() << endl;
			++it_hosts;
		}
	}
	
	allZones->sort();
// 	kdDebug() << "Found " << allZones->count() << " Zones" << endl;
	
	// Resort Zones
	TQPtrListIterator<KMFNetZone> it_2( *allZones );
	while ( it_2.current() ) {
// 		kdDebug() << "Found Zone : " << it_2.current()->toString() <<   endl;
		++it_2;
	}
	
	for( uint i = 0; i < allHosts->count(); i++ ) {
		KMFTarget *currHost = allHosts->at(i);
		for( int j = allZones->count() - 1; allZones->count() > 0 && j >= 0; j-- ) {
			KMFNetZone *currZone = allZones->at(j);
			if (  IPAddress::hostsOnSameNetwork( *currZone->address(), *currHost->address(), currZone->maskLength() ) ) {
				currZone->placeHostInZone( currHost );
/*				kdDebug() << "Add Host: " << currHost->toString() << endl;
				kdDebug() << "to Zone : " << currZone->toString() << endl;*/
				break;
			}
		}
	}
	
	kdDebug() << "Finished Host Reorder" << endl << endl;	
		


}

// void KMFNetZone::refreshNetworkTree_internal( KMFNetZone *curr ) {
// 	kdDebug() << "KMFNetZone::refreshNetworkTree_internal()"  << endl;
// 	
// 	 
// 	 
// }

void KMFNetZone::getAllZones( KMFNetZone* zone, TQPtrList<KMFNetZone>* list ) {
//	kdDebug() << "KMFNetZone::getAllZones(...)"  << endl;
	TQPtrListIterator<KMFNetZone> it( zone->zones() );
	while ( it.current() ) {
		getAllZones( it.current(), list );
		++it;
	}
	list->append( zone );
}

void KMFNetZone::getAllHosts( KMFNetZone* zone, TQPtrList<KMFTarget>* list ) {
//	kdDebug() << "KMFNetZone::getAllHosts(...)"  << endl;
	TQPtrListIterator<KMFNetZone> it( zone->zones() );
	while ( it.current() ) {
		getAllHosts( it.current(), list );
		++it;
	}
	
	TQPtrListIterator<KMFTarget> it2( zone->hosts() );
	while ( it2.current() ) {
		list->append( it2.current() );
		++it2;
	}
}

void KMFNetZone::getAllTargets( KMFNetZone* zone, TQPtrList<KMFTarget>* list ) {
	kdDebug() << "KMFNetZone::getAllTargets(...)"  << endl;
	TQPtrListIterator<KMFNetZone> it( zone->zones() );
	while ( it.current() ) {
		getAllTargets( it.current(), list );
		++it;
	}
	
	TQPtrListIterator<KMFTarget> it2( zone->hosts() );
	while ( it2.current() ) {
		if ( it2.current()->type() == NetfilterObject::KMFTARGET ) {
			list->append( it2.current() );
		}
		++it2;
	}
}

KMFNetHost* KMFNetZone::addNetHost( const TQString& name, const TQDomDocument& xml ) {
	kdDebug() << "KMFProtocol* KMFNetHost::addNetHost( const TQString& name, const TQDomDocument& xml )" << endl;
	TQString hostnum;
	hostnum = hostnum.setNum( m_hosts.count() + 1 );
	TQString host_name = "nethost_" + this->name() + "_" + hostnum;
	KMFNetHost* new_host = new KMFNetHost( this, host_name.latin1(), host_name, network() );
	if ( ! new_host ) {
		kdDebug() << "ERROR couldn't create Host" << endl;
		return 0;
	}
	kdDebug() << "xml.toString(): " <<  xml.toString() << endl;
	TQStringList *errors = new TQStringList();
	new_host->loadXML( xml, *errors );
	// FIXME: Check Errors
	if ( ! new_host->readOnly() ) {
		new_host->setName( host_name );
		new_host->setGuiName( name );
	}
	KMFNetHost *retHost = dynamic_cast<KMFNetHost *> ( placeHostInZone( new_host ) );
	if ( ! retHost ) {
		kdDebug() << "ERROR: couldn't place host!" << endl;
	}
	changed();
	return retHost;
}

KMFTarget* KMFNetZone::addTarget( const TQString& name, const TQDomDocument& xml ) {
	kdDebug() << "KMFProtocol* KMFNetHost::addTarget( const TQString& name, const TQDomDocument& xml )" << endl;
	TQString hostnum;
	hostnum = hostnum.setNum( hosts().count() + 1 );
	TQString host_name = "target_" + this->name() + "_" + hostnum;
	KMFTarget* new_host = new KMFTarget( this , host_name.latin1(), host_name, network() );
	if ( ! new_host ) {
		kdDebug() << "ERROR couldn't create Host" << endl;
		return 0;
	}
	kdDebug() << xml.toString() << endl;
	TQStringList *errors = new TQStringList();
	new_host->loadXML( xml, *errors );
	// FIXME: Check Errors
	if ( ! new_host->readOnly() ) {
		new_host->setName( host_name );
		new_host->setGuiName( name );
	}
	KMFTarget *retHost = dynamic_cast<KMFTarget *> ( placeHostInZone( new_host ) );
	if ( ! retHost ) {
		kdDebug() << "ERROR: couldn't place host!" << endl;
	}
	changed();
	return retHost;
}

void KMFNetZone::delHost( KMFTarget* host, bool destructive ) {
	TQPtrListIterator<KMFTarget> it( m_hosts );
	bool deleted = false;
	while ( it.current() ) {
		KMFTarget * p = it.current();
		++it;
		if ( p == host ) {
			m_hosts.remove( p );
			if ( destructive ) {
				host->deleteLater();
			}
			deleted = true;
			changed();
		}
	}
	if ( !deleted ) {
		kdDebug() << "WARNING: Couldn't delete host: " << host->name() << " from zone:  " << name() << endl;
	}
}

const TQDomDocument& KMFNetZone::getDOMTree() {
	// kdDebug() << "const TQDomDocument& KMFNetZone::getDOMTree() " << endl;
	TQDomDocument doc;
	TQDomElement root = doc.createElement( XML::NetZone_Element );
	NetfilterObject::saveUuid( root );
	root.setAttribute( XML::Name_Attribute, name() );
	root.setAttribute( XML::GUIName_Attribute, guiName() );
	root.setAttribute( XML::Description_Attribute, description() );
	root.setAttribute( XML::ReadOnly_Attribute, readOnly() ? XML::BoolOn_Value : XML::BoolOff_Value );

	TQDomElement from = doc.createElement( XML::FromIP_Element );
	root.appendChild( from );
	TQString num;
	from.setAttribute( XML::Address_Attribute, address()->toString() );

	TQDomElement mask = doc.createElement( XML::NetMask_Element );
	root.appendChild( mask );
	mask.setAttribute( XML::Address_Attribute, maskLength() );

	TQPtrListIterator<KMFNetZone> it ( m_zones );
	while ( it.current() ) {
		root.appendChild( it.current() ->getDOMTree( ) );
		++it;
	}

	TQPtrListIterator<KMFProtocolUsage> it2 ( m_protocols );
	while ( it2.current() ) {
		root.appendChild( it2.current() ->getDOMTree( ) );
		++it2;
	}

	TQPtrListIterator<KMFTarget> it3 ( m_hosts );
	while ( it3.current() ) {
		root.appendChild( it3.current() ->getDOMTree( ) );
		++it3;
	}

	doc.appendChild( root );
	return *( new TQDomDocument( doc ) );
}
void KMFNetZone::loadXML( const TQDomDocument& doc, TQStringList& errors ) {
	// kdDebug() << "void KMFNetZone::loadXML( const TQDomDocument& )" << endl;
 	TQDomElement root = doc.documentElement();
 	loadXML( root, errors );
}
void KMFNetZone::loadXML( TQDomNode root, TQStringList& errors ) {
// void KMFNetZone::loadXML( const TQDomDocument& doc ) {
	kdDebug() << "void KMFNetZone::loadXML( TQDomNode root )" << endl;
	NetfilterObject::loadUuid ( root, errors );
//	TQDomElement root = doc.documentElement();
	TQString name = "";
	TQString guiName = "";
	TQString desc = "";
	TQString readonly = "";

	name = root.toElement().attribute(  XML::Name_Attribute );
	guiName = root.toElement().attribute( XML::GUIName_Attribute );
	desc = root.toElement().attribute( XML::Description_Attribute );
	readonly = root.toElement().attribute( XML::ReadOnly_Attribute );
	setDescription( *( new TQString( desc ) ) );
	// if ( 
	setName( *( new TQString( name ) ) );
	setGuiName( *( new TQString( guiName ) ) );
	
	if ( readonly == XML::BoolOn_Value ) {
		setReadOnly( true );	
	} else {
		setReadOnly( false );
	}	
	
	TQValueList< KMFNetZone* > xmlDefinedZones;
	TQValueList< KMFTarget* > xmlDefinedTargets;
	TQValueList< KMFProtocolUsage* > xmlDefinedProtocols;
	TQDomNode curr = root.firstChild();
	while ( !curr.isNull() ) {
		if ( curr.isElement() && ( curr.nodeName() == XML::FromIP_Element || curr.nodeName() == XML::NetMask_Element ) ) {
			TQString addr = curr.toElement().attribute( XML::Address_Attribute );
			if ( curr.nodeName() == XML::FromIP_Element )
				m_address->setAddress( addr );
			if ( curr.nodeName() == XML::NetMask_Element ) {
				bool ok;
				int len = addr.toInt( &ok );
				if ( ok ) {
					setMaskLength( len );
				} else {
					kdDebug() << "Parsing mask failed" << endl;
				}
			}
		}
		
		if ( curr.isElement() && ( curr.nodeName() == XML::NetZone_Element ) ) {
			TQString name = "";
			name = curr.toElement().attribute(  XML::Name_Attribute );
			kdDebug() << "KMFNetZone: parsing netzone: " << curr.toElement().attribute(  XML::Name_Attribute ) << endl;
			TQDomDocument zone_doc;
			zone_doc.appendChild( curr.cloneNode( true ) );
		
			KMFNetZone *z = 0;
			z = findNetZoneByName( name, true );
			if ( ! z ) {
				kdDebug() << "KMFNetZone: loadXML() - INFO: Zone: " <<  name << " not found in document, Will Create It." << endl;
				z =  addZone( name, m_err );
			}
			if ( z ) {
				z->loadXML( curr, errors );
				xmlDefinedZones.append( z );
			}
		}
		if ( curr.isElement() && ( curr.nodeName() == XML::Protocol_Element ) ) { 
			// FIXME: Remove later
			// Keep that for compatiblity
			TQString name = "";
			name = curr.toElement().attribute(  XML::Name_Attribute );
			kdDebug() << "KMFNetZone: parsing protocol: " << curr.toElement().attribute(  XML::Name_Attribute ) << endl;
			TQDomDocument protocol_doc;
			protocol_doc.appendChild( curr.cloneNode( true ) );
			
			KMFProtocol *p = KMFProtocolLibrary::instance()->findProtocolByName( name );
			if ( ! p ) {
				KMFUndoEngine::instance()->log( i18n("No Protocol Found by name: %1").arg( name ), KMFError::NORMAL, this );
				continue;
			}
			
			
			KMFProtocolUsage *pu = addProtocolUsage( p->uuid(), protocol_doc );
			if ( ! pu ) {
				pu = findProtocolUsageByProtocolUuid( p->uuid() );
			}
			KMFUndoEngine::instance()->log( i18n("Adding xml protocol: %1").arg( pu->name() ), KMFError::OK, this );
			xmlDefinedProtocols.append( pu );
		}
		if ( curr.isElement() && (  curr.nodeName() == XML::ProtocolUsage_Element ) ) {
			TQString protocolUuid = curr.toElement().attribute( XML::ProtocolUuid_Attribute );
			kdDebug() << "KMFNetZone: parsing protocol: " << curr.toElement().attribute(  XML::Name_Attribute ) << endl;
			TQDomDocument protocol_doc;
			protocol_doc.appendChild( curr.cloneNode( true ) );
			KMFProtocolUsage *pu = addProtocolUsage( protocolUuid, protocol_doc );
			if ( ! pu ) {
				pu = findProtocolUsageByProtocolUuid( protocolUuid );
			}
			KMFUndoEngine::instance()->log( i18n("Adding xml protocol: %1").arg( pu->name() ), KMFError::OK, this );
			xmlDefinedProtocols.append( pu );

		}
		if ( curr.isElement() && ( curr.nodeName() == XML::NetHost_Element ) ) {
			TQString name = "";
			name = curr.toElement().attribute(  XML::Name_Attribute );
			TQDomDocument host_doc;
			host_doc.appendChild( curr.cloneNode( true ) );
			KMFNetHost *h = 0;
			h = findNetHostByName( name, true );
			 
			if ( ! h ) {
				kdDebug() << "KMFNetZone: loadXML() - INFO: Host: " <<  name << " not found in document, Will Create It." << endl;
				h = addNetHost( name, host_doc );
			}
			if ( h ) {
				h->loadXML( curr, errors );
				xmlDefinedTargets.append( h );
			}
		}
		if ( curr.isElement() && ( curr.nodeName() == XML::Target_Element ) ) {
			TQString name = curr.toElement().attribute(  XML::Name_Attribute );
			kdDebug() << "KMFNetZone: parsing target: " << curr.toElement().attribute(  XML::Name_Attribute ) << endl;
			KMFTarget *h = 0;
			TQDomDocument host_doc;
			host_doc.appendChild( curr.cloneNode( true ) );
			h = findTargetByName( name, true );
			if ( ! h ) {
				h = addTarget( name, host_doc );
			} 
			if ( ! h ) {
				kdDebug() << "KMFNetZone: loadXML() - ERROR: No Localhost found in document" << endl;
			}
			if ( h ) {
				h->loadXML( host_doc, errors );
				xmlDefinedTargets.append( h );
			}
		}
		curr = curr.nextSibling();
	}
	
	{ 
		TQPtrList< KMFNetZone >& allZones = zones();
		TQPtrListIterator<KMFNetZone> itAllZones( allZones ); 
		while( itAllZones.current() ) {
			KMFNetZone *oldZone = itAllZones.current();
			++itAllZones;
			bool found = false;
			TQValueList< KMFNetZone* >::iterator itZones;
			for( itZones = xmlDefinedZones.begin(); itZones != xmlDefinedZones.end() && ! found; ++itZones ) {
				
				KMFNetZone* z = *itZones;
				if ( z == oldZone ) {
					found = true;
				}
			}
			
			if ( ! found ) {
				KMFUndoEngine::instance()->log( i18n("Removing unused Zone: %1").arg( oldZone->guiName() ), KMFError::OK, this );
				delZone( oldZone, true );
			}
		}
	}
	{
		TQPtrList< KMFTarget >& allTargets = hosts();
		TQPtrListIterator< KMFTarget > itAllTargets( allTargets ); 
		while( itAllTargets.current() ) {
			KMFTarget *oldTarget = itAllTargets.current();
			++itAllTargets;
			
			bool found = false;
			TQValueList< KMFTarget* >::iterator itTargets;
			for( itTargets = xmlDefinedTargets.begin(); itTargets != xmlDefinedTargets.end() && ! found; ++itTargets ) {
				KMFTarget* t = *itTargets;
				if ( t == oldTarget ) {
					found = true;
				}
			}
			
			if ( ! found ) {
				KMFUndoEngine::instance()->log( i18n("Removing unused target: %1").arg( oldTarget->guiName() ), KMFError::OK, this );
				delHost( oldTarget, true );
			}
		}
	}
	
	
	
	{
		TQPtrList< KMFProtocolUsage >& allprotocols = protocols();
		TQPtrListIterator< KMFProtocolUsage > itAllProtocols( allprotocols ); 
		while( itAllProtocols.current() ) {
			KMFProtocolUsage *oldProtocoUsagel = itAllProtocols.current();
			++itAllProtocols;
			KMFUndoEngine::instance()->log( i18n("Existing protocol: %1").arg( oldProtocoUsagel->name() ), KMFError::OK, this );
			
			
			bool found = false;
			TQValueList< KMFProtocolUsage* >::iterator itProtocols;
			for( itProtocols = xmlDefinedProtocols.begin(); itProtocols != xmlDefinedProtocols.end() && ! found; ++itProtocols ) {
				KMFProtocolUsage* protocolUsage = *itProtocols;
				KMFUndoEngine::instance()->log( i18n("Compare with xml protocol: %1").arg( protocolUsage->name() ), KMFError::OK, this );
				if ( protocolUsage == oldProtocoUsagel ) {
					found = true;
				}
			}
			
 			if ( ! found ) {
 				KMFUndoEngine::instance()->log( i18n("Removing unused protocol: %1").arg( oldProtocoUsagel->name() ), KMFError::OK, this );
 				delProtocolUsage( oldProtocoUsagel, true );
 				// delHost( oldTarget, true );
 			}
		}
	}
	
	
	changed();
	kdDebug() << "KMFNetZone - finished parsing XML" << endl;
}

}

#include "kmfnetzone.moc"
