/***************************************************************************
*   Copyright (C) 2005 by Christian Hubinger   *
*   e9806056@student.tuwien.ac.at   *
*                                                                         *
*   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.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
***************************************************************************/
#include "kmfiptwatcher.h"


// QT includes
#include <tqtimer.h>

// KDE includes
#include <kdebug.h>
#include <klocale.h>
#include <kapp.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <dcopclient.h>

// Project includes
#include "../core/kmfiptdoc.h"
#include "../core/kmferror.h"
#include "../core/iptable.h"
#include "../core/iptchain.h"
#include "../core/iptrule.h"
#include "../core/iptruleoption.h"

KMFIPTWatcher::KMFIPTWatcher( TQObject *parent, const char *name )
		: TQObject( parent, name ) {
	m_queryExtendedInfo	= true;
	m_doc = new KMFIPTDoc( 0, "iptdoc" );
	go();
}


KMFIPTWatcher::~KMFIPTWatcher() {}


void KMFIPTWatcher::go() {
	// KMessageBox::information( 0, i18n( "go()" ) );
	m_timer = new TQTimer();
	TQObject::connect( m_timer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( timeout() ) );
	m_timer->start( 3000, false );
}

void KMFIPTWatcher::timeout() {
//	kdDebug() << "timeout()" << endl; 
	

	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	TQString arg = "filter";
	stream << arg;
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "numChainsInTable(TQString)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {

		// KMessageBox::information( 0, i18n( "Error with DCOP: %1" ).tqarg( kapp->dcopClient() ->appId() ) );
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == "int" ) {
			int result;
			answer >> result;
			// KMessageBox::information( 0, i18n( "Got answer %1" ).tqarg(result) );
			emit sigUpdateActive( result > 0 );
		} else
			KMessageBox::information( 0, i18n( "Calling over DCOP succeeded, but the answer had wrong type!" ) );
	}

	if ( m_queryExtendedInfo ) {
		queryExtendedInfo();
	}
}

void KMFIPTWatcher::queryExtendedInfo() {
	queryChainsInTable( "filter", m_doc );
	queryChainsInTable( "nat", m_doc );
	queryChainsInTable( "mangle", m_doc );
	kdDebug() << "emit sigUpdateIPTDoc( m_doc )" << endl;
	emit sigUpdateIPTDoc( m_doc );	
}

void KMFIPTWatcher::queryChainsInTable( const TQString& table, KMFIPTDoc* iptdoc ) {
	kdDebug() << "queryNumRulesInChain( const TQString& table, const TQString& chain )" << endl;
	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	stream << table;
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "getChainsInTable(TQString)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == TQSTRINGLIST_OBJECT_NAME_STRING ) {
			TQStringList result;
			answer >> result;
			IPTable *tableObj = iptdoc->table( table ); 
			kdDebug() << "Filling Table: " << tableObj->name() << endl;
			TQPtrList<IPTChain> *used = new TQPtrList<IPTChain>;
			for ( TQStringList::Iterator it = result.begin(); it != result.end(); ++it ) {
     			kdDebug() << "Found Chain" << *it << endl;
				IPTChain *chain = tableObj->chainForName( *it );	
    			if ( ! chain ) {
					TQString tg = "ACCEPT";
					tableObj->addChain( *it, tg, false, new KMFError() );
				}
 				fetchChainPolicy( tableObj->chainForName( *it ) );
				fetchRulesInChain( tableObj->chainForName( *it ) );
				used->append( tableObj->chainForName( *it ) );
			}
			
			TQPtrListIterator<IPTChain> it_chains( tableObj->chains() );
			IPTChain* found_chain = 0;
			while ( it_chains.current() ) {
				found_chain = it_chains.current();
				bool found = false;
				for ( TQStringList::Iterator it_all = result.begin(); it_all != result.end(); ++it_all ) {
					if ( *it_all == found_chain->name() ) {
						found = true;
					}
				}
				kdDebug() << "Found chain: " << found_chain->name() << " " << found << endl;
				if ( ! found ) {
					tableObj->delChain( found_chain );
				} 
				++it_chains;
			}
			

		} else {
			KMessageBox::information( 0, i18n( "Calling over DCOP succeeded, but the answer had wrong type!" ) );
		}
	}
}

void KMFIPTWatcher::fetchChainPolicy( IPTChain* chain ) {
	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	stream << chain->table()->name() << chain->name();
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "getChainPolicy(TQString,TQString)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == TQSTRING_OBJECT_NAME_STRING ) {
			TQString result;
			answer >> result;
			kdDebug() << "Found Chain Policy: " << chain->table()->name()  << " " << chain->name()  << " " << result << endl;
			chain->setDefaultTarget( result );
		}
	}
}

void KMFIPTWatcher::fetchRulesInChain( IPTChain* chain ) {
	kdDebug() << "fetchRulesInChain( const TQString& table, const TQString& chain )" << endl;
	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	stream << chain->table()->name() << chain->name();
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "numRulesInChain(TQString,TQString)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == "int" ) {
			int result;
			answer >> result;
			TQPtrList<IPTRule> *used = new TQPtrList<IPTRule>;
			for ( int i = 0; i < result; i++ ) {
				TQString rn =  TQString("rule_%1").tqarg( i );
				IPTRule *rule = 0;
				rule = chain->ruleForName( rn );
				if ( ! rule ) {
					rule = chain->addRule( rn , new KMFError() );
				}
				fetchRulesProperties( rule, i );
				used->append( rule );
			}

			TQPtrListIterator<IPTRule> it_rules( chain->chainRuleset() );
			IPTRule* found_rule = 0;
			while ( it_rules.current() ) {
				found_rule = it_rules.current();
				bool found = false;
				for ( int i = 0; i < result; i++ ) {
					TQString rn = TQString("rule_%1").tqarg( i );
					if ( rn == found_rule->name() ) {
						found = true;
					}
				}
				if ( ! found ) {
					chain->delRule( found_rule );
				} 
				++it_rules;
			}
		} else {
			KMessageBox::information( 0, i18n( "Calling over DCOP succeeded, but the answer had wrong type!" ) );
		}
	}	
}

void KMFIPTWatcher::fetchRulesProperties( IPTRule* rule, int index ) {
	kdDebug() << "queryNumRulesInChain( const TQString& table, const TQString& chain )" << endl;
	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	stream << rule->chain()->table()->name() <<  rule->chain()->name() << index;
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "getRuleProperties(TQString,TQString,int)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == TQSTRINGLIST_OBJECT_NAME_STRING ) {
			TQStringList result;
			answer >> result;
			if ( *result.at( 0 ) == "ERROR" ) {
				return;
			}
			rule->setTarget( *result.at( 0 ) );
			

		} else {
			KMessageBox::information( 0, i18n( "Calling over DCOP succeeded, but the answer had wrong type!" ) );
		}
	}

}


void KMFIPTWatcher::queryNumRulesInChain( const TQString& table, const TQString& chain, KMFIPTDoc* doc ) {
	kdDebug() << "queryNumRulesInChain( const TQString& table, const TQString& chain )" << endl;
	DCOPClient *client = kapp->dcopClient();
	TQCString reply_type;
	TQByteArray params;
	TQDataStream stream( params, IO_WriteOnly );
	stream << table << chain;
	TQByteArray reply_data;

	if ( ! client->call( *( new TQCString( "kmfiptinterface" ) ),
	                     *( new TQCString( "KMFIPTInterface" ) ),
	                     *( new TQCString( "numRulesInChain(TQString,TQString)" ) ), params,
	                     reply_type, reply_data, false, 10000 ) ) {
		emit sigUpdateActive( false );
	} else {
		TQDataStream answer( reply_data, IO_ReadOnly );
		if ( reply_type == "int" ) {
			int result;
			answer >> result;
			
		} else
			KMessageBox::information( 0, i18n( "Calling over DCOP succeeded, but the answer had wrong type!" ) );
	}
}

void KMFIPTWatcher::worked() {
	KMessageBox::information( 0, i18n( "Callback Worked" ) );
}

void KMFIPTWatcher::slotQueryDetails( bool on ) {
	kdDebug() << "slotQueryDetails( bool " <<  on << " )" << endl;
	m_queryExtendedInfo = on;
}
#include "kmfiptwatcher.moc"