/***************************************************************************
begin                : Thu Feb 7  2002
copyright            : (C) 2002 by Christian Hubinger
email                : chubinger@irrsinnig.org
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "kmfruleedit.h"

//KDE includes
#include <kled.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdelistview.h>
#include <tdepopupmenu.h>
#include <tdemessagebox.h>
#include <tdeapplication.h>
#include <tdelistbox.h>
#include <kpushbutton.h>
#include <kcombobox.h>
#include <ktrader.h>
#include <tdeparts/part.h>
#include <tdeparts/plugin.h>
#include <tdeparts/factory.h>

//TQt includes
#include <tqtooltip.h>
#include <tqwhatsthis.h>
#include <tqheader.h>
#include <tqsplitter.h>

#include <tqpushbutton.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqptrlist.h>
#include <tqstring.h>
#include <tqinputdialog.h>
#include <tqlabel.h>
#include <tqmessagebox.h>
#include <tqgroupbox.h>
#include <tqsize.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqwidgetstack.h>

// project includes
#include "../core/xmlnames.h"
#include "../core/kmfdoc.h"
#include "../core/kmfiptdoc.h"
#include "../core/kmfnetwork.h"
#include "../core/iptchain.h"
#include "../core/iptrule.h"
#include "../core/kmfcheckinput.h"
#include "../core/kmferror.h"
#include "../core/kmferrorhandler.h"
#include "../core/kmfconfig.h"
#include "../core/kmfpluginfactory.h"
#include "../core/kmfappstate.h"
#include "../core/kmyfirewallinterface.h"
#include "../core/kmfruleoptioneditinterface.h"
#include "../core/kmfruletargetoptioneditinterface.h"


#include "../kmfwidgets/kmflistview.h"
#include "../kmfwidgets/kmfmynetworkwidget.h"
#include "../kmfwidgets/kmflistviewitem.h"
#include "../kmfwidgets/kmfobjectinfo.h"
#include "../kmfwidgets/kmfmainwindow.h"

#include "kmfchainedit.h"
#include "kmfnewchaindlg.h"
namespace KMF {
KMFRuleEdit::KMFRuleEdit( TQWidget* parent, const char* name, WFlags fl )
		: KMyFirewallRuleEditor( parent, name, fl ), KMFRuleEditInterface() {
	if ( !name )
		setName( "KMFRuleEdit" );
	m_lastDisplayDoc = 0;
	loadIcons();
	m_editPlugins.clear();
	b_move_up->setPixmap( icon_up );
	b_move_down->setPixmap( icon_down );
	// need to remove dummy page from TQTDesigner ;-)
	m_ws_target_opt->removeWidget( page );

	m_err = new KMFError();
	m_err_handler = new KMFErrorHandler( "KMFRuleEdit" );
	kb_optSelect->clear();
	connect( kb_optSelect, TQ_SIGNAL( activated( int ) ) , this, TQ_SLOT( slotNewOptionType( int ) ) );

	m_lv_table_filter = new KMFListView( m_widgetStack, "m_lv_table_filter" );
	m_lv_table_filter->show();

	connect( m_lv_table_filter, TQ_SIGNAL( contextMenuRequested ( TQListViewItem*, const TQPoint&, int ) ),
	         this, TQ_SLOT( slotRuleRBM( TQListViewItem*, const TQPoint&, int ) ) );

	connect( m_lv_table_filter, TQ_SIGNAL( itemRenamed ( TQListViewItem*, int, const TQString& ) ),
	         this, TQ_SLOT( slotRenameRule( TQListViewItem*, int, const TQString& ) ) );

	connect( m_lv_table_filter, TQ_SIGNAL( clicked( TQListViewItem* ) ),
	         this, TQ_SLOT( slotNewItemSelected( TQListViewItem* ) ) );
	
// 	connect( this, TQ_SIGNAL( sigUpdateView() ),
// 	         m_lv_table_filter, TQ_SLOT( slotUpdateView() ) );
	
	m_widgetStack->addWidget( m_lv_table_filter );


	m_lv_table_nat = new KMFListView( m_widgetStack, "m_lv_table_nat" );
	m_lv_table_nat->show();

	connect( m_lv_table_nat, TQ_SIGNAL( contextMenuRequested ( TQListViewItem*, const TQPoint&, int ) ),
	         this, TQ_SLOT( slotRuleRBM( TQListViewItem*, const TQPoint&, int ) ) );

	connect( m_lv_table_nat, TQ_SIGNAL( itemRenamed ( TQListViewItem*, int, const TQString& ) ),
	         this, TQ_SLOT( slotRenameRule( TQListViewItem*, int, const TQString& ) ) );

	connect( m_lv_table_nat, TQ_SIGNAL( clicked( TQListViewItem* ) ),
	         this, TQ_SLOT( slotNewItemSelected( TQListViewItem* ) ) );

	m_widgetStack->addWidget( m_lv_table_nat );

	m_lv_table_mangle = new KMFListView( m_widgetStack, "m_lv_table_mangle" );
	m_lv_table_mangle->show();

	connect( m_lv_table_mangle, TQ_SIGNAL( contextMenuRequested ( TQListViewItem*, const TQPoint&, int ) ),
	         this, TQ_SLOT( slotRuleRBM( TQListViewItem*, const TQPoint&, int ) ) );

	connect( m_lv_table_mangle, TQ_SIGNAL( itemRenamed ( TQListViewItem*, int, const TQString& ) ),
	         this, TQ_SLOT( slotRenameRule( TQListViewItem*, int, const TQString& ) ) );

	connect( m_lv_table_mangle, TQ_SIGNAL( clicked( TQListViewItem* ) ),
	         this, TQ_SLOT( slotNewItemSelected( TQListViewItem* ) ) );
	
	
	
	m_widgetStack->addWidget( m_lv_table_mangle );
	
	m_splitter->setResizeMode( gb_options, TQSplitter::KeepSize );

	m_editchain = new KMFChainEdit( this, "chianditor", 0 );
	kdDebug() << "CONNECTING CHAINEDITOR" << endl;
	connect( m_editchain, TQ_SIGNAL( sigHideMe() ),
	         this, TQ_SLOT( slotShowOverview() ) );
	m_widgetStack->addWidget( m_editchain );


	m_object_info = new KMFObjectInfo( this, "rule info" );
	connect( m_object_info, TQ_SIGNAL( sigHideMe() ),
	         this, TQ_SLOT( slotShowOverview() ) );

	m_widgetStack->addWidget( m_object_info );

	m_new_chain = new KMFNewChainDlg();
	connect( m_new_chain, TQ_SIGNAL( sigUpdateView() ),
	         this, TQ_SIGNAL( sigUpdateView() ) );

	m_myNetworkWidget = new KMFMyNetworkWidget( this, "KMFMyNetworkWidget" );
	connect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_myNetworkWidget, TQ_SLOT( slotUpdateView() ) );
	connect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_myNetworkWidget, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );
	
	connect( m_myNetworkWidget, TQ_SIGNAL( sigActiveTargetChanged() ), this, TQ_SLOT( slotUpdateView() ) );
	m_myNetworkWidget->hide(); //close( false );

	m_check_input = new KMFCheckInput();
	m_contextMenu = new TDEPopupMenu( this );
	
	connect( cb_log_rule, TQ_SIGNAL( clicked() ),
	         this, TQ_SLOT( slotLogRuleChanged() ) );
	connect( cb_disable_rule, TQ_SIGNAL( clicked() ),
	         this, TQ_SLOT( slotEnableRuleChanged() ) );
	rb_filter->setChecked( true );
	
	loadPlugins();
	
	m_rule = 0;
	m_chain = 0;
	m_table = 0;
	m_network = 0;
	m_widgetStack->show();
	// slotNewTableSelected();
	// slotShowOverview();
	adjustSize();
	show();
}

KMFRuleEdit::~KMFRuleEdit() {}

void KMFRuleEdit::setKMFMainWindow( KMFMainWindow* win ) {
	m_app = win;
}

void KMFRuleEdit::slotSelectionInvalid() {
	m_rule = 0;
	m_chain = 0;
	m_table = 0;
}

void KMFRuleEdit::loadDoc( KMFNetwork* network ) {
	kdDebug() << "void KMFRuleEdit::loadDoc(KMFIPTDoc* doc)" << endl;
	if ( network == 0 ) {
		m_err->setErrType(KMFError::NORMAL );
		const TQString& msg = i18n( "KMFRuleEdit:::loadDoc(KMFIPTDoc* doc)\n"
		                           "KMFIPTDoc* doc == 0. This is a bug." );
		m_err->setErrMsg( msg );
		m_err_handler->showError( m_err );
		setEnabled( false );
		return ;
	}

	if ( !isEnabled() ) {
		setEnabled( true );
	}
	m_network = network;
	m_myNetworkWidget->setNetwork( m_network );
	
	rb_filter->setEnabled( m_network->currentDocAsIPTDoc()->useFilter() );
	rb_mangle->setEnabled( m_network->currentDocAsIPTDoc()->useMangle() );
	rb_nat->setEnabled( m_network->currentDocAsIPTDoc()->useNat() );
	if ( m_network->currentDocAsIPTDoc()->useModules() ) {
		m_led_modules->setColor( green );
		m_led_modules->on();
	} else {
		m_led_modules->setColor( red );
		m_led_modules->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useIPFwd() ) {
		m_led_fwd->setColor( green );
		m_led_fwd->on();
	} else {
		m_led_fwd->setColor( red );
		m_led_fwd->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useSynCookies() ) {
		m_led_syn->setColor( green );
		m_led_syn->on();
	} else {
		m_led_syn->setColor( red );
		m_led_syn->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useRPFilter() ) {
		m_led_rp->setColor( green );
		m_led_rp->on();
	} else {
		m_led_rp->setColor( red );
		m_led_rp->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useMartians() ) {
		m_led_martians->setColor( green );
		m_led_martians->on();
	} else {
		m_led_martians->setColor( red );
		m_led_martians->off();
	}
	

	
	IPTable *filter = 0;
	filter = m_network->currentDocAsIPTDoc()->table( Constants::FilterTable_Name );
	if ( filter ) {
		m_lv_table_filter->clearAllItems();
		m_lv_table_filter->slotLoadNode( filter );
	}

//	IPTable *def = 0;
	IPTable *nat = 0;
	nat = m_network->currentDocAsIPTDoc()->table( Constants::NatTable_Name );
	if ( nat ) {
		m_lv_table_nat->clearAllItems();
		m_lv_table_nat->slotLoadNode( nat );
	}
	
	IPTable *mangle = 0;
	mangle = m_network->currentDocAsIPTDoc()->table( Constants::MangleTable_Name );
	if ( mangle ) {
		m_lv_table_mangle->clearAllItems();
		m_lv_table_mangle->slotLoadNode( mangle );
	}
	
	m_rule = 0;
	m_chain = 0;
	m_table = 0;
	
	enableRuleEdit( false );
	slotShowOverview();
	// if ( KMFAppState::upAndRunning() ) {
		rb_filter->setChecked( true );
		slotNewTableSelected();
		emit sigUpdateView();
	//}
}

void KMFRuleEdit::slotLoadDocument( KMFNetwork* network ) {
	kdDebug() << "KMFRuleEdit::slotLoadDocument( KMFNetwork* network )" << endl;
	slotShowOverview();
	loadDoc( network );
}


void KMFRuleEdit::loadPlugins() {
	kdDebug() << "KMFRuleEdit::loadPlugins()" << endl;
	
	TQPtrListIterator<KMFRuleOptionEditInterface> it( *KMFPluginFactory::KMFRuleOptionEditors( this ) );
	while( it.current() ) {
		registerRuleOptionPlugin( it.current() );
		++it;
	}
	
	TQPtrListIterator<KMFRuleTargetOptionEditInterface> it2(  *KMFPluginFactory::KMFRuleTargetOptionEditors( this ) );
	while( it2.current() ) {
		registerRuleTargetOptionPlugin( it2.current() );
		++it2;
	}
	
}

void KMFRuleEdit::registerRuleOptionPlugin( KMFRuleOptionEditInterface* edit ) {
	m_widgetStack->addWidget( edit->editWidget() );
	m_editPlugins.append( edit );
	kb_optSelect->insertItem( i18n("Edit %1").arg( edit->optionEditName() ) );
}

void KMFRuleEdit::registerRuleTargetOptionPlugin( KMFRuleTargetOptionEditInterface* edit ) {
	m_ws_target_opt->addWidget( edit->editWidget() );
	m_editTargetPlugins.append( edit );
}



KMFListView* KMFRuleEdit::currTableView() {
	if ( rb_filter->isChecked() && rb_filter->isEnabled() ) {
		return m_lv_table_filter;
	} else if ( rb_nat->isChecked() && rb_nat->isEnabled() ) {
		return m_lv_table_nat;
	} else if ( rb_mangle->isChecked() && rb_mangle->isEnabled() ) {
		return m_lv_table_mangle;
	} else {
		kdDebug() << "ERROR: currTableView() returning fallbvack table: filter !!!" << endl;
		return m_lv_table_filter;
	}
}





void KMFRuleEdit::slotNewTableSelected() {
	kdDebug() << "void KMFRuleEdit::slotNewTableSelected()" << endl;
	if ( ! m_network->currentDocAsIPTDoc() ) {
		setEnabled( false );
		return ;
	}
	TQString table = Constants::FilterTable_Name;
	if ( !rb_filter->isEnabled() )
		rb_filter->setChecked( false );
	if ( !rb_nat->isEnabled() )
		rb_nat->setChecked( false );
	if ( !rb_mangle->isEnabled() )
		rb_mangle->setChecked( false );


	if ( rb_filter->isChecked() && rb_filter->isEnabled() ) {
		table = Constants::FilterTable_Name;
		kdDebug() << "Enabling Filter View" << endl;
		setCurrTableView( m_lv_table_filter );
	} else if ( rb_nat->isChecked() && rb_nat->isEnabled() ) {
		setEnabled( true );
		table = Constants::NatTable_Name;
		setCurrTableView( m_lv_table_nat );
	} else if ( rb_mangle->isChecked() && rb_mangle->isEnabled() ) {
		setEnabled( true );
		table = Constants::MangleTable_Name;
		setCurrTableView( m_lv_table_mangle );
	} else {
		setEnabled( true );
		table = Constants::FilterTable_Name;
		setCurrTableView( m_lv_table_filter );
		return;
	}

	IPTable *tab = m_network->currentDocAsIPTDoc()->table( table );
	if ( tab == 0 ) {
		setEnabled( false );
		kdDebug() << "Table: " << table << " not found in document!!" << table << endl;
		return ;
	}

	m_table = tab;
	slotShowOverview();
}
void KMFRuleEdit::setCurrTableView( KMFListView* lv ) {
	kdDebug() << "void KMFRuleEdit::setCurrTableView( KMFListView* lv )" << endl;
	if ( lv == m_lv_table_filter ) {
		setEnabled( true );
		kdDebug() << "Enabling Filter View" << endl;
		m_lv_table_filter->setEnabled( true );
		connect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView() ) );
		
		connect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Nat View" << endl;
		m_lv_table_nat->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_nat, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_nat, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Mangle View" << endl;
		m_lv_table_mangle->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );
	} else if  ( lv == m_lv_table_nat ) {
		setEnabled( true );
		kdDebug() << "Disabling Filter View" << endl;
		m_lv_table_filter->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Enabling Nat View" << endl;
		m_lv_table_nat->setEnabled( true );
		connect( this, TQ_SIGNAL( sigUpdateView() ),
			m_lv_table_nat, TQ_SLOT( slotUpdateView() ) );
		connect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
			m_lv_table_nat, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Mangle View" << endl;
		m_lv_table_mangle->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );
	} else if  ( lv == m_lv_table_mangle ) {
		setEnabled( true );

		kdDebug() << "Disabling Filter View" << endl;
		m_lv_table_filter->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Nat View" << endl;
		m_lv_table_nat->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Enabling Mangle View" << endl;
		m_lv_table_mangle->setEnabled( true );
		connect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		connect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );
	} else  if ( ! lv ){
		kdDebug() << "Disabling Filter View" << endl;
		m_lv_table_filter->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_filter, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Nat View" << endl;
		m_lv_table_nat->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );

		kdDebug() << "Disabling Mangle View" << endl;
		m_lv_table_mangle->setEnabled( false );
		disconnect( this, TQ_SIGNAL( sigUpdateView() ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView() ) );
		disconnect( this, TQ_SIGNAL( sigUpdateView( NetfilterObject* ) ),
	         m_lv_table_mangle, TQ_SLOT( slotUpdateView( NetfilterObject* ) ) );
	}
}

void KMFRuleEdit::slotNewItemSelected( TQListViewItem* item ) {
	kdDebug() << "KMFRuleEdit::slotNewItemSelected( TQListViewItem* item )" << endl;
	if ( ! item )
		return ;
	if ( KMFListViewItem * kmf_item = dynamic_cast<KMFListViewItem*>( item ) ) {
		IPTRuleOption * opt = 0;
		switch( kmf_item->type() ) {
			case NetfilterObject::TABLE:
				m_rule = 0;
				m_chain = 0;
				m_table = kmf_item->table();
				slotEditRule();
				break;
			case NetfilterObject::CHAIN:
				m_rule = 0;
				m_chain = kmf_item->chain();
				m_table = m_chain->table();
				slotEditRule();
				break;
			case NetfilterObject::RULE:
				m_rule = kmf_item->rule();
				m_chain = m_rule->chain();
				m_table = m_rule->chain() ->table();
				slotEditRule();
				break;
			case NetfilterObject::RULEOPTION:
				opt = kmf_item->ruleOption();
				m_rule = opt->rule();
				m_chain = opt->rule() ->chain();
				m_table = opt->rule() ->chain() ->table();
				slotEditRule();
				break;
			default:
				kdDebug() << "Strange? KMFListViewItem * kmf_item>type() NOT VALID" << endl;
				m_rule = 0;
				m_chain = 0;
				m_table = 0;
				break;
		}
	}
}

void KMFRuleEdit::slotAddRule() {
	kdDebug() << "KMFRuleEdit::slotAddRule()" << endl;
	if ( ! m_chain ) {
		KMessageBox::sorry( this, i18n( "<qt>No Chain Found to add the Rule.<br>"
		                                "Please make sure that you selected a Chain or Rule before you try to add a Rule." ),
		                    i18n( "Sorry" ) );
		return ;
	}
	bool ok = false;
	const TQString greeting = i18n( "New Rule" );
	const TQString label = i18n( "Please enter a name for the new rule:" );
	TQString text = TQInputDialog::getText( greeting, label, TQLineEdit::Normal, TQString(), &ok, this, "dsa" );
	if ( ok && !text.isEmpty() ) {
		kdDebug() << "Adding Rule Named: " << text << endl;
		TQString ch = m_chain->name();
		kdDebug() << "For Chain: " << ch << endl;
		TQString tab = m_chain->table() ->name();
		kdDebug() << "In Table: " << tab << endl;
		TQString target = "ACCEPT";
		kdDebug() << "With Target: " << target << endl;
		if ( !text.isEmpty() && !ch.isEmpty() && !tab.isEmpty() && !target.isEmpty() ) {
			m_check_input->checkInput( text, "RULENAME", m_err );
			if ( m_err_handler->showError( m_err ) ) {
				KMFUndoEngine::instance()->startTransaction( 
					m_chain,
					i18n( "Add Rule: %1 to Chain: %2" ).arg( text ).arg( m_chain->name() ) 
				);
				
				IPTRule *inserted = m_chain->addRule( text, m_err );
				if ( m_err_handler->showError( m_err ) ) {
					if ( m_rule ) {
						m_chain->moveRule( inserted, ( m_rule->ruleNum() ) -inserted->ruleNum() );
					}
//					m_network->changed();
					KMFUndoEngine::instance()->endTransaction();
				} else {
					KMFUndoEngine::instance()->abortTransaction();
				}
				
				m_rule = inserted;
				emit sigUpdateView( m_chain );
			}
		} else {
			KMessageBox::sorry( this, i18n( "An error occurred while trying to setup a new rule." ), i18n( "Rule Editor" ) );
		}
	}
}

void KMFRuleEdit::slotAddChain() {
	if ( m_table ) {
		m_new_chain->loadDoc( m_table->kmfDoc() );
		m_new_chain->exec();
	}
}

void KMFRuleEdit::slotDelChain() {
	kdDebug() << "void KMFView::slotDelChain()" << endl;
	if ( ! m_chain ) {
		KMessageBox::sorry( this, i18n( "<qt>No Chain Found for deleting.<br>"
		                                "Please make sure that you selected a Chain or Rule before you try to delete the current chain." ),
		                    i18n( "Sorry" ) );
		return ;
	}

	if ( m_chain->isBuildIn() ) {
		KMessageBox::sorry( this, i18n( "<qt><b>Cannot delete built-in chain: %1</b><br>"
		                                "Built-in chains cannot be deleted; you can only delete chains "
		                                "that you have defined yourself." ).arg( m_chain->name() ),
		                    i18n( "Sorry" ) );
		return ;
	}
	int doit = KMessageBox::questionYesNo ( this , i18n( "<p>Are you sure that you want to delete "
	                                        "chain: <b>%1</b> from table: <b>%2</b>?<br>"
	                                        "<b>Note:</b> By deleting the chain all rules that belong "
	                                        "to the chain will be deleted too." ).arg( m_chain ->name() ).arg( m_chain ->table() ->name() ),
	                                        i18n( "Delete Chain" ), KStdGuiItem::yes(), KStdGuiItem::no(), "main_view_delete_chain" );
	kdDebug() << "Message Box returned: " << doit << endl;
	if ( doit == 3 ) {
		kdDebug() << "Try to delete Chain" << endl;
		KMFUndoEngine::instance()->startTransaction( 
			m_table,
			i18n( "Delete Chain: %1 from Table: %2").arg( m_chain->name() ).arg( m_chain->table()->name() )  
		);
		m_err = m_network->currentDocAsIPTDoc()->table( m_chain->table()->name() )->delChain( m_chain );
		if ( m_err_handler ->showError( m_err ) ) {
			emit sigUpdateView( m_chain->table() );
			m_chain = 0;
			m_rule = 0;
			m_table = 0;
			KMFUndoEngine::instance()->endTransaction();
		} else {
			KMFUndoEngine::instance()->abortTransaction();
		}
		
	}
}

void KMFRuleEdit::slotEditRule() {
	m_ws_target_opt->setEnabled(false);	
	if ( ! KMFAppState::upAndRunning() /* || ! KMFAppState::hasOpenDoc() */ ) {
		slotSelectionInvalid();
		return;
	}


	if ( m_rule ) {
		l_editing_rule->setText( "<b>Chain: </b>" + m_rule->chain()->name() + "<br><b>Rule: </b>" + m_rule->name() );
		kb_optSelect->setEnabled( true );
		cb_log_rule ->setEnabled( true );
		cb_disable_rule ->setEnabled( true );
		cb_target ->setEnabled( true );
		cb_frag ->setEnabled( true );
		TQString target = m_rule->target();
		cb_target->clear();
		const TQStringList& list = m_rule->availableTargets();
		cb_target->insertStringList( list );
		bool found = false;
		for ( int i = 0; i < cb_target->count() && ! found; i++ ) {
			if ( !cb_target->text( i ).isNull() && cb_target->text( i ) == m_rule->target( ) ) {
				cb_target->setCurrentItem( i );
				found = true;
			}
		}

		slotEditTargetOption();
		IPTRuleOption *opt = m_rule->getOptionForName( "frag_opt" );
		if ( !opt->isEmpty() ) {
			TQStringList vals = opt->getValues();
			if ( *vals.at( 0 ) == XML::BoolOn_Value && *vals.at( 0 ) == XML::BoolOff_Value ) {
				cb_frag->setChecked( true );
				cb_frag_inv->setChecked( false );
			} else if ( *vals.at( 0 ) == XML::BoolOff_Value && *vals.at( 1 ) == XML::BoolOn_Value ) {
				cb_frag->setChecked( true );
				cb_frag_inv->setChecked( true );
			} else {
				cb_frag->setChecked( false );
				cb_frag_inv->setChecked( false );
			}
		} else {
			cb_frag->setChecked( false );
			cb_frag_inv->setChecked( false );
		}

		cb_disable_rule->setChecked( ! m_rule->enabled() );
		cb_log_rule->setChecked( m_rule->logging() );
		enableRuleEdit( true );

		//*********************************
	} else if ( m_chain ) {
		l_editing_rule->setText( "<b>Chain: </b>" + m_chain->name() + "<br><b>Rule: </b>No rule selected" );
		kb_optSelect->setEnabled( false );
		cb_log_rule ->setEnabled( false );
		cb_disable_rule ->setEnabled( false );
		cb_target ->setEnabled( false );
		cb_frag ->setEnabled( false );
		m_ws_target_opt->setEnabled( false );
		enableRuleEdit( false );
	} else {
		l_editing_rule->setText( "<b>Chain: </b>No chain selected<br><b>Rule: </b>No rule selected" );
		kb_optSelect->setEnabled( false );
		cb_log_rule ->setEnabled( false );
		cb_disable_rule ->setEnabled( false );
		cb_target ->setEnabled( false );
		cb_frag ->setEnabled( false );
		m_ws_target_opt->setEnabled( false );
		enableRuleEdit( false );
	}
}

void KMFRuleEdit::enableRuleEdit( bool on ) {
	if ( on ) {
		b_move_up->setEnabled( true );
		b_move_down->setEnabled( true );
		kb_optSelect->setEnabled( true );
		cb_log_rule ->setEnabled( true );
		cb_disable_rule ->setEnabled( true );
		cb_target ->setEnabled( true );
		cb_frag ->setEnabled( true );
	} else {
		kb_optSelect->setEnabled( false );
		b_move_up->setEnabled( false );
		b_move_down->setEnabled( false );
		cb_log_rule ->setEnabled( false );
		cb_disable_rule ->setEnabled( false );
		cb_target ->setEnabled( false );
		cb_frag ->setEnabled( false );
		m_ws_target_opt->setEnabled( false );
	}
}

void KMFRuleEdit::slotMoveRuleDown() {
	kdDebug() << "KMFRuleEdit::slotMoveRuleDown()" << endl;
	moveRuleInChain( 1 );
// 	if ( m_rule  && kb_optSelect->isEnabled() ) {
// 		KMFUndoEngine::instance()->startTransaction( 
// 			m_chain,
// 			i18n("Move Rule: %1 down").arg( m_rule->name() ) 
// 		);
// 		m_chain->saveState();
// 		if ( m_chain->moveRule( m_rule, 1 ) ) {
// 			m_rule->chain()->changed();
// 			KMFListViewItem* item = currTableView()->findKMFItem( m_rule->name(), 2, m_rule->uuid() );
// 			if ( item ) {
// 				currTableView()->setSelected( item, true );
// 			}
// 			item->loadNetfilterObject( m_rule );
// 			emit sigUpdateView( m_rule->chain() );
// 			KMFUndoEngine::instance()->endTransaction();
// 		} else {
// 			KMFUndoEngine::instance()->abortTransaction();
// 		}
// 		
// 	}
}

void KMFRuleEdit::slotMoveRuleUp() {
	kdDebug() << "KMFRuleEdit::slotMoveRuleUp()" << endl;
	moveRuleInChain( -1 );
// 	if ( m_rule && kb_optSelect->isEnabled() ) {
// 		KMFListViewItem* item = currTableView() ->findKMFItem( m_rule->name(),2, m_rule->uuid() );
// 		if ( item ) {
// 			KMFUndoEngine::instance()->startTransaction( 
// 				m_chain,
// 				i18n("Move Rule: %1 up").arg( m_rule->name() ) 
// 			);
// 			m_chain->saveState();
// 			if ( m_chain->moveRule( m_rule, -1 ) ) {
// 				m_rule->chain()->changed();
// 				currTableView()->setSelected( item, true );
// 				item->loadNetfilterObject( m_rule );
// 				emit sigUpdateView( m_rule->chain()  );
// 			}
// 			KMFUndoEngine::instance()->endTransaction();
// 		}
// 	}
}

void KMFRuleEdit::moveRuleInChain( int amount ) {
	if ( m_rule && kb_optSelect->isEnabled() ) {
		const TQString& transMsg = i18n("Move Rule: %1 %2").arg( m_rule->name() ).arg( amount > 0 ? "down" : "up" );
		KMFListViewItem* item = currTableView()->findKMFItem( m_rule->name(),2, m_rule->uuid() );
		if ( item ) {
			KMFUndoEngine::instance()->startTransaction( 
				m_chain,
				transMsg.arg( m_rule->name() ) 
			);
			if ( m_chain->moveRule( m_rule, -1 ) ) {
				m_rule->chain()->changed();
				currTableView()->setSelected( item, true );
				item->loadNetfilterObject( m_rule );
				KMFUndoEngine::instance()->endTransaction();
				emit sigUpdateView( m_rule->chain()  );
			} else {
				KMFUndoEngine::instance()->abortTransaction();
			}
			
		}
	}
}

void KMFRuleEdit::slotDelRule() {
	kdDebug() << "KMFRuleEdit::slotDelRule()" << endl;
	if ( ! m_rule || ! m_chain ) {
		KMessageBox::sorry( this, i18n( "<qt>No Rule defined to delete.<br>"
		                                "Please make sure that you selected a Rule before you try to delete one." ),
		                    i18n( "Sorry" ) );
		return ;
	} else {
		int doit = KMessageBox::questionYesNo ( this , i18n( "<p>Are you sure that you want to delete "
		                                        "rule: <b>%1</b> from chain: <b>%2</b>?</p>").arg( m_rule->name() ).arg( m_rule->chain() ->name() ),
		                                        i18n( "Delete Rule" ), KStdGuiItem::yes(), KStdGuiItem::no(), "rule_edit_delete_rule" );
		kdDebug() << "Message Box returned: " << doit << endl;
		if ( doit == 3 ) { // OK clicked
			kdDebug() << "clicked ok" << endl;
			KMFUndoEngine::instance()->startTransaction( 
				m_chain,
				i18n("Delete Rule: %1 from Chain: %2").arg( m_rule->name() ).arg( m_chain->name() ) 
			);
			m_err = m_chain->delRule( m_rule );
			if ( m_err_handler->showError( m_err ) ) {
				kdDebug() << "KMFRuleEdit::slotDelRule()\nCalling: m_network->currentDocAsIPTDoc()->updateView()" << endl;
				m_rule = 0;
				slotEditRule();
				KMFUndoEngine::instance()->endTransaction();
				if ( m_chain ) {
					emit sigUpdateView( m_chain );
				} else {
					emit sigUpdateView();
				}
			} else {
				KMFUndoEngine::instance()->abortTransaction();
			}
		}
	}
}
void KMFRuleEdit::showOverview() {
	slotShowOverview();
}

void KMFRuleEdit::slotShowOverview() {
	kdDebug() << "KMFRuleEdit::slotShowOverview()" << endl;
	if ( rb_filter->isChecked() ) {
		m_widgetStack->raiseWidget( m_lv_table_filter );
	} else if ( rb_nat->isChecked() ) {
		m_widgetStack->raiseWidget( m_lv_table_nat );
	} else if ( rb_mangle->isChecked() ) {
		m_widgetStack->raiseWidget( m_lv_table_mangle );
	}
/*	if ( m_network->currentDocAsIPTDoc() ) {
		KMFUndoEngine::instance()->endTransaction();
	}*/
	if ( m_table ) {
		kdDebug() << "emit KMFRuleEdit::sigUpdateView()" << endl;
		emit sigUpdateView();
	}
	slotEditRule();
}

void KMFRuleEdit::slotNewOptionType( int index ) {
	kdDebug() << "KMFRuleEdit::slotNewOptionType( index " << index << " )" << endl;
	if ( index > -1 ) {
		slotEditRule();
		if ( ! m_rule )
			return;
		m_editPlugins.at( index )->loadRule( m_rule );
		m_widgetStack->raiseWidget( m_editPlugins.at( index )->editWidget() );
	}
}



// void KMFRuleEdit::slotEditCustomOpt() {
/*	kdDebug() << "KMFRuleEdit::slotEditTosOpt()" << endl;
	slotEditRule();
	if ( ! m_rule )
		return;
	KMessageBox::information ( this , i18n( "<qt><p>You are about to define custom options for this rule.<br>"
	                                        "There will be <b>no sanity checks</b> for your input, so please make sure "
	                                        "that your options are working and the syntax is correct.</p></qt>" ),
	                           i18n( "Information" ), "custom_option_warning" );
	m_custom_opt->loadRule( m_rule );
	m_widgetStack->raiseWidget( m_custom_opt );*/
// }

void KMFRuleEdit::slotEditRuleInfo() {
	slotEditRule();
	if ( ! m_rule )
		return;
	m_object_info->loadNetfilterObject( m_rule );
	m_widgetStack->raiseWidget( m_object_info );
}

void KMFRuleEdit::slotEditChainInfo() {
	slotEditRule();
	if ( ! m_chain )
		return;
	m_object_info->loadNetfilterObject( m_chain );
	m_widgetStack->raiseWidget( m_object_info );
}

void KMFRuleEdit::slotEditTargetOption() {
	kdDebug() << "void KMFRuleEdit::slotEditTargetOption()\n Target: " << cb_target->currentText() << endl;
	if ( ! m_rule )
		return;
	TQString target = cb_target->currentText();
	TQPtrListIterator<KMFRuleTargetOptionEditInterface> it( m_editTargetPlugins );
	m_ws_target_opt->setEnabled( false );
	while ( it.current() ) {
		KMFRuleTargetOptionEditInterface *edit = it.current();
		++it;
		if ( edit->manageTarget( target ) ) {
			m_ws_target_opt->setEnabled( true );
			edit->setTarget( target );
			edit->loadRule( m_rule );
			m_ws_target_opt->raiseWidget( edit->editWidget() );
			return;
		}
	}
	
	
	
	
	
// 	if ( target == "LOG" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tglog ->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tglog );
// 	} else if ( target == "SNAT" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tgnat ->setMode( true );
// 		m_tgnat ->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tgnat );
// 	} else if ( target == "DNAT" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tgnat ->setMode( false );
// 		m_tgnat ->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tgnat );
// 	} else if ( target == "TOS" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tosed->setType( "SETTOS" );
// 		m_tosed->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tosed );
// 	} else if ( target == "REJECT" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tosed->setType( "REJECTTYPE" );
// 		m_tosed->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tosed );
// 	} else if ( target == "MARK" ) {
// 		m_ws_target_opt->setEnabled( true );
// 		m_tgmark->loadRule( m_rule );
// 		m_ws_target_opt->raiseWidget( m_tgmark );
// 	} else {
// 		m_ws_target_opt->setEnabled( false );
// 	}
}


void KMFRuleEdit::slotEditChain() {
	kdDebug() << "void KMFRuleEdit::slotEditChain()" << endl;
	if ( ! m_chain )
		return;
	m_editchain -> loadChain( m_chain );
	m_widgetStack->raiseWidget( m_editchain );
}

void KMFRuleEdit::slotEditNetwork() {
	kdDebug() << "void KMFRuleEdit::slotEditNewtwork()" << endl;
	// kdDebug() << "Parent is: " << parent()->className() << endl;
// 	KMFMyNetworkWidget *wid = new KMFMyNetworkWidget( this, "name" );
// 	wid->setNetwork( m_network );
// 	wid->slotUpdateView();
/*	connect( wid, TQ_SIGNAL( sigActiveTargetChanged() ), this, TQ_SLOT( slotUpdateView() ) );*/
	m_myNetworkWidget->slotUpdateView();
	m_app->setOutputWidget( m_myNetworkWidget );
	m_app->showOutput();
}

// Slots For Rule Edit Changes
void KMFRuleEdit::slotFragChanged() {
	kdDebug() << "KMFRuleEdit::slotFragChanged(bool frag)" << endl;
	if ( !m_rule )
		return ;
	bool frag = cb_frag->isChecked();
	bool frag_inv = cb_frag_inv->isChecked();

	TQPtrList<TQString>* vals = new TQPtrList<TQString>;
	TQString* cmd = new TQString( "frag_opt" );
	if ( frag ) {
		if ( frag_inv ) {
			vals->append( new TQString( XML::BoolOff_Value ) );
			vals->append( new TQString( XML::BoolOn_Value ) );
		} else {
			vals->append( new TQString( XML::BoolOn_Value ) );
			vals->append( new TQString( XML::BoolOff_Value ) );
		}
	} else {
		vals->append( new TQString( XML::BoolOff_Value ) );
		vals->append( new TQString( XML::BoolOff_Value ) );
	}
	KMFUndoEngine::instance()->startTransaction( 
		m_rule,
		i18n( "Edit Rule: %1 Fragment option" ).arg( m_rule->name() ) 
	);
	m_rule->addRuleOption( *cmd, *vals );
	KMFUndoEngine::instance()->endTransaction();
	emit sigUpdateView( m_rule );
}

void KMFRuleEdit::slotLogRuleChanged() {
	if ( !m_rule )
		return ;
	KMFUndoEngine::instance()->startTransaction( 
		m_rule,
		i18n( "Edit Rule: %1 Log option" ).arg( m_rule->name() ) 
	);
	if ( cb_log_rule->isChecked() ) {
		m_rule->setLogging( true );
	} else {
		m_rule->setLogging( false );
	}
//	m_network->changed();
	KMFUndoEngine::instance()->endTransaction();
	emit sigUpdateView( m_rule );
}

void KMFRuleEdit::slotEnableRuleChanged() {
	if ( !m_rule )
		return ;
	KMFUndoEngine::instance()->startTransaction( 
		m_rule,
		i18n( "Edit Rule: %1 enabled state" ).arg( m_rule->name() ) 
	);
	if ( cb_disable_rule->isChecked() ) {
		m_rule->setEnabled( false );
	} else {
		m_rule->setEnabled( true );
	}
//	m_network->changed();
	KMFUndoEngine::instance()->endTransaction();
	emit sigUpdateView( m_rule );
	slotEditRule();
}

void KMFRuleEdit::slotTargetChanged( const TQString & tg ) {
	kdDebug() << "KMFRuleEdit::slotTargetChanged(const TQString&)" << endl;
	if ( !m_rule )
		return ;

	if ( !tg.isEmpty() ) {
		if ( tg == m_rule->chain() ->name() ) {
			KMessageBox::sorry( this, i18n( "<qt><p>Sorry, you <b>cannot</b> set the target of this rule to be its own chain. "
			                                "Constructing endless loops is not allowed.</qt>" ) );
			return ;
		}
		if ( m_rule->target() == "LOG" || m_rule->target() == "REJECT" ||
		        m_rule->target() == "SNAT" || m_rule->target() == "DNAT" ||
		        m_rule->target() == "MARK" || m_rule->target() == "TOS" ) {
			int ans = KMessageBox::questionYesNo( this, i18n( "<qt>By changing the Target of the Rule all previous"
			                                      " defined <b>Target Options</b> will be deleted.<br>"
			                                      "Click <b>Continue</b> to change the Target.<br>"
			                                      "Click <b>Cancel</b> keep your current Target. </qt>" ), i18n( "Warning" ), KStdGuiItem::cont(), KStdGuiItem::cancel(), "change_target_option_warning" );
			kdDebug() << "KMessageBox:: Returned" << ans << endl;
			switch ( ans ) {

			case 3:
				kdDebug() << "Clicked Continue" << endl;
				if ( m_rule->target() != tg ) {
					KMFUndoEngine::instance()->startTransaction( 
						m_rule,
						i18n( "Change Rule: %1 target from: %2 to: %3" ).arg( m_rule->name() ).arg( m_rule->target() ).arg( tg ) 
					);
					m_rule->setTarget( tg );
					emit sigUpdateView( m_rule->chain()->table() );
					KMFUndoEngine::instance()->endTransaction();
				}
				break;
			case 2:
				kdDebug() << "Canceled Target Change" << endl;
				slotEditRule();
				slotEditTargetOption();
				return ;
				break;
			}
		} else {
			if ( m_rule->target() != tg ) {
				KMFUndoEngine::instance()->startTransaction( 
					m_rule,
					i18n( "Change Rule: %1 target from: %2 to: %3" ).arg( m_rule->name() ).arg( m_rule->target() ).arg( tg ) 
				);
				m_rule->setTarget( tg );
				emit sigUpdateView( m_rule->chain()->table() );
				KMFUndoEngine::instance()->endTransaction();
			}
		}
		slotEditTargetOption();
	}
}

void KMFRuleEdit::addRuleOption(TQString* name, TQPtrList< TQString >* values){
	slotAddRuleOption( name, values );
}

void KMFRuleEdit::slotAddRuleOption( TQString * name, TQPtrList<TQString>* values ) {
	kdDebug() << "KMFRuleEdit::slotAddRuleOption(TQString* name, TQPtrList<TQString>* values)" << endl;
	m_rule->addRuleOption( *name, *values );
	emit sigUpdateView( m_rule );
}

void KMFRuleEdit::addRuleTargetOption(TQString* name, TQPtrList< TQString >* values ){
	slotAddTargetOption( name, values );
} 

void KMFRuleEdit::slotAddTargetOption( TQString * name, TQPtrList<TQString>* values ) {
	kdDebug() << "KMFRuleEdit::slotAddTargetOption(TQString* name, TQPtrList<TQString>* values)" << endl;
	m_rule->addTargetOption( *name, *values );
	emit sigUpdateView( m_rule );
}

void KMFRuleEdit::slotRuleRBM( TQListViewItem * item, const TQPoint & point, int ) {
	kdDebug() << "void KMFRuleEdit::RBM(TQListViewItem* item, const TQPoint & point, int)" << endl;
	if ( ! item ) {
		 if ( m_table ) {
			createRBM( m_table );
			m_contextMenu->popup( point );
		} else {
			return ;
		}
	}
	if ( KMFListViewItem * tmp_item = dynamic_cast<KMFListViewItem*>( item ) ) {
		slotNewItemSelected( item );
		if ( ( tmp_item->type() == NetfilterObject::RULE || tmp_item->type() == NetfilterObject::RULEOPTION )&& m_rule ) {
			createRBM( m_rule );
			m_contextMenu->popup( point );
		} else if ( tmp_item->type() == NetfilterObject::CHAIN && m_chain ) {
			createRBM( m_chain );
			m_contextMenu->popup( point );
		} else if ( tmp_item->type() == NetfilterObject::TABLE && m_table ) {
			createRBM( m_table );
			m_contextMenu->popup( point );
		} else {
			m_contextMenu->clear();
		}
	} else  {
		kdDebug() << "CAST ERROR: KMFRuleEdit::slotRuleRBM(...) " << endl;
	}
}


void KMFRuleEdit::createRBM( NetfilterObject* obj ) {
	kdDebug() << "void createRBM( IPTChain* ){" << endl;
	if ( ! obj )
		return;
	switch( obj->type() ) {
		case NetfilterObject::TABLE:
		if ( IPTable* table =  dynamic_cast<IPTable*> ( obj ) ) {
			m_contextMenu->clear();
			TQString name = table->name();
			TQString lab_str = i18n("Table: %1").arg( name );

			m_contextMenu->insertTitle( lab_str );
			m_contextMenu->insertItem( icon_new, i18n( "Add Chain..." ), this, TQ_SLOT( slotAddChain() ) );
		}
		break;
		case NetfilterObject::CHAIN:
		if ( IPTChain* chain =  dynamic_cast<IPTChain*> ( obj ) ) {
			m_contextMenu->clear();
			TQString name = chain->name();
			TQString lab_str = i18n("Chain: %1").arg( name );

			m_contextMenu->insertTitle( icon_chain, lab_str );
			m_contextMenu->insertItem( icon_new, i18n( "Add Rule..." ), this, TQ_SLOT( slotAddRule() ) );
			m_contextMenu->insertSeparator();
			if ( ! chain->isBuildIn() )
				m_contextMenu->insertItem( icon_edit, i18n( "Chain Documentation" ), this, TQ_SLOT( slotEditChainInfo() ) );
			m_contextMenu->insertItem( icon_new, i18n( "Add Chain..." ), this, TQ_SLOT( slotAddChain() ) );
			m_contextMenu->insertItem( icon_edit, i18n( "Edit Chain" ), this, TQ_SLOT( slotEditChain() ) );
			if ( ! chain->isBuildIn() )
				m_contextMenu->insertItem( icon_del, i18n( "Delete Chain" ), this, TQ_SLOT( slotDelChain() ) );
		}
		case NetfilterObject::RULE:
		if ( IPTRule* rule =  dynamic_cast<IPTRule*> ( obj ) ) {
			m_contextMenu->clear();
			TQString name = rule->name();
			TQString lab_str = i18n("Rule: %1").arg( name );
			m_contextMenu->insertTitle( icon_rule, lab_str );

			TDEPopupMenu *sub_edit = new TDEPopupMenu( m_contextMenu );
			sub_edit->insertTitle( i18n( "Edit Rule Option" ) );
			for( uint i = 0; i < m_editPlugins.count(); i++ ) {
				sub_edit->insertItem( icon_edit, i18n( "Edit %1" ).arg(m_editPlugins.at(i)->optionEditName() ), i );
			}
			connect( sub_edit,TQ_SIGNAL(activated( int ) ), 
				this,TQ_SLOT(slotNewOptionType( int ) ) );			
			m_contextMenu->insertItem( i18n( "Edit Rule Option" ), sub_edit );
			// m_contextMenu->insertItem( icon_new, i18n( "Add Rule..." ), this, TQ_SLOT( slotAddRule() ) );
			m_contextMenu->insertItem( icon_new, i18n( "Insert Rule..." ), this, TQ_SLOT( slotAddRule() ) );
//			m_contextMenu->insertSeparator();
			m_contextMenu->insertItem( icon_del, i18n( "Delete Rule" ), this, TQ_SLOT( slotDelRule() ) );
			m_contextMenu->insertSeparator();
			m_contextMenu->insertItem( icon_rename, i18n( "Rename Rule" ), this, TQ_SLOT( slotRenameRule() ) );
			m_contextMenu->insertItem( icon_edit, i18n( "Rule Documentation" ), this, TQ_SLOT( slotEditRuleInfo() ) );
			m_contextMenu->insertItem( icon_up, i18n( "Move Up" ), this, TQ_SLOT( slotMoveRuleUp() ) );
			m_contextMenu->insertItem( icon_down, i18n( "Move Down" ), this, TQ_SLOT( slotMoveRuleDown() ) );
			m_contextMenu->insertSeparator();
			m_contextMenu->insertItem( icon_edit, i18n( "Edit Chain" ), this, TQ_SLOT( slotEditChain() ) );
			if ( ! rule->chain()->isBuildIn() )
				m_contextMenu->insertItem( icon_del, i18n( "Delete Chain" ), this, TQ_SLOT( slotDelChain() ) );
			m_contextMenu->insertSeparator();

			TDEPopupMenu *sub_copy = new TDEPopupMenu( m_contextMenu );
			connect( sub_copy, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( slotCopyRule( int ) ) );
			sub_copy->insertTitle( i18n( "Copy to Chain" ) );
			TQPtrList<IPTChain> chains = m_table ->chains();
			for ( uint i = 0; i < chains.count(); i++ ) {
				TQString tmp_name = chains.at( i ) ->name();
				sub_copy->insertItem( tmp_name, i );
			}
			m_contextMenu->insertItem( icon_copy, i18n( "Copy Rule" ), sub_copy );

			TDEPopupMenu *sub_move = new TDEPopupMenu( m_contextMenu );
			connect( sub_move, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( slotMoveRule( int ) ) );
			sub_move->insertTitle( i18n( "Move to Chain" ) );
			TQPtrList<IPTChain> chains2 = m_table->chains();
			for ( uint i = 0; i < chains2.count(); i++ ) {
				TQString tmp_name = chains2.at( i ) ->name();
				sub_move->insertItem( tmp_name, i );
			}
			m_contextMenu->insertItem( icon_move, i18n( "Move Rule" ), sub_move );
		}
	}
}


void KMFRuleEdit::slotMoveRule( int index ) {
	kdDebug() << "void KMFRuleEdit::slotCopyRule( int )" << endl;
	kdDebug() << "Move Rule  to Chain Nr: " << index << endl;
	IPTChain *chain_target = 0;
	chain_target = m_network->currentDocAsIPTDoc()->table( m_table->name() ) ->chains().at( index );
	if ( chain_target ) {
		KMFUndoEngine::instance()->startTransaction( 
			m_rule->chain()->table(),
			i18n( "Move Rule: %1 from Chain: %2 to Chain: %3" ).arg( m_rule->name() ).arg( m_rule->chain()->name() ).arg( chain_target->name() ) 
		);
		m_err = m_rule->chain()->table()->moveRuleToChain( m_rule, chain_target );
		if ( m_err_handler->showError( m_err ) ) {
			KMFUndoEngine::instance()->endTransaction();
			emit sigUpdateView( chain_target->table() );
		} else {
			KMFUndoEngine::instance()->abortTransaction();
		}
	}
}

void KMFRuleEdit::slotCopyRule( int index ) {
	kdDebug() << "void KMFRuleEdit::slotCopyRule( int )" << endl;
	kdDebug() << "Move Rule  to Chain Nr: " << index << endl;
	IPTChain *chain_target = 0;
	chain_target = m_network->currentDocAsIPTDoc()->table( m_table->name() ) ->chains().at( index );
	if ( chain_target ) {
		KMFUndoEngine::instance()->startTransaction( 
			m_rule->chain() ->table(),
			i18n( "Copy Rule: %1 from Chain: %2 to Chain: %3" ).arg( m_rule->name() ).arg( m_rule->chain()->name() ).arg( chain_target->name() ) 
		);
		m_err = m_rule->chain() ->table() ->copyRuleToChain( m_rule, chain_target );
		if ( m_err_handler->showError( m_err ) ) {
			KMFUndoEngine::instance()->endTransaction();
			emit sigUpdateView( chain_target->table() );
		} else {
			KMFUndoEngine::instance()->abortTransaction();
		}
	}
}

void KMFRuleEdit::slotRenameRule() {
	if ( ! m_rule )
		return;
	if ( KMFListViewItem* rule_item = currTableView()->findKMFItem( m_rule->name(),2,m_rule->uuid() ) ) {

		rule_item->startRename(2);
	}
}

void KMFRuleEdit::slotRenameRule( TQListViewItem* , int, const TQString& name ) {
	kdDebug() << "void KMFRuleEdit::slotRenameRule( TQListViewItem* item, int, const TQString& name )" << endl;
	if ( name.isNull() || name.isEmpty() ) {
		kdDebug() << "Rename rejected: Name was NULL or empty" << endl;
		return;
	}

// 	 if ( ! m_rule ) {
// 		kdDebug() << "Rename rejected: m_rule == 0:" << endl;
// 		return;
// 	}

	if ( KMFListViewItem* rule_item = currTableView()->findKMFItem( name ,2,m_rule->uuid() ) ) {
		kdDebug() << "Found Rule Item: " << name <<  " ID " << m_rule->uuid() << endl;
		TQPtrList<IPTRule>& rules = rule_item->rule()->chain()->chainRuleset();
		IPTRule *rule = 0;
		for ( rule = rules.first(); rule; rule = rules.next() ) {
			if ( rule->name() == name ) {
				KMessageBox::sorry( this, i18n( "<qt><p>Sorry, there is already a rule named: <b>%1</b> in the chain.<br>"
												"Please make sure that the new rule name is unique in its chain.</qt>" ).arg( name ) );
				rule_item->setText( 2, rule_item->rule()->name() );
				emit sigUpdateView( rule_item->rule()->chain() );
				return ;
			}
		}
		KMFUndoEngine::instance()->startTransaction( 
			rule_item->rule(),
			i18n( "Rename Rule: %1 to %2").arg( rule_item->rule()->name() ).arg( name ) 
		);
		
		TQString origName = rule_item->rule()->name();
		m_err = rule_item->rule()->setRuleName( name );
		if ( m_err_handler->showError( m_err ) ) {
			KMFUndoEngine::instance()->endTransaction();
		} else {
			rule_item->setText( 2, origName );
			KMFUndoEngine::instance()->abortTransaction();
		}
		
		emit sigUpdateView( rule_item->rule()->chain()->table() );
	}
}

void KMFRuleEdit::slotUpdateView() {
	kdDebug() << "void KMFRuleEdit::slotUpdateView()" << endl;
	if ( ! m_network ) {
		kdDebug() << "ERROR: m_network is null" << endl;
		return;
	}
	
	kdDebug() << "upAndRunning(): " << KMFAppState::upAndRunning() << endl;
		slotSelectionInvalid();
	
	bool reload = true;
	if ( ! m_lastDisplayDoc ) {
		m_lastDisplayDoc =  m_network->currentDocAsIPTDoc();
	}
	if ( m_lastDisplayDoc ==  m_network->currentDocAsIPTDoc() ) {
		if ( ! m_network->newSavePathNeeded() ) {
			kdDebug() << "IPTDoc still the same." << endl;
			reload = false;
		}
	} else {
		kdDebug() << "IPTDoc changed." << endl;
		m_lastDisplayDoc = m_network->currentDocAsIPTDoc();
		// reload = true;
	}
	
	IPTable *filter = 0;
	filter = m_network->currentDocAsIPTDoc()->table( Constants::FilterTable_Name );
	if ( filter ) {
		if ( reload ) m_lv_table_filter->clearAllItems();
		m_lv_table_filter->slotLoadNode( filter );
	}

	IPTable *nat = 0;
	nat = m_network->currentDocAsIPTDoc()->table( Constants::NatTable_Name );
	if ( nat ) {
		if ( reload ) m_lv_table_nat->clearAllItems();
		m_lv_table_nat->slotLoadNode( nat );
	}
	
	IPTable *mangle = 0;
	mangle = m_network->currentDocAsIPTDoc()->table( Constants::MangleTable_Name );
	if ( mangle ) {
		if ( reload ) m_lv_table_mangle->clearAllItems();
		m_lv_table_mangle->slotLoadNode( mangle );
	}

	rb_filter->setEnabled( m_network->currentDocAsIPTDoc()->useFilter() );
	rb_mangle->setEnabled( m_network->currentDocAsIPTDoc()->useMangle() );
	rb_nat->setEnabled( m_network->currentDocAsIPTDoc()->useNat() );


	if ( m_network->currentDocAsIPTDoc()->useModules() ) {
		m_led_modules->setColor( green );
		m_led_modules->on();
	} else {
		m_led_modules->setColor( red );
		m_led_modules->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useIPFwd() ) {
		m_led_fwd->setColor( green );
		m_led_fwd->on();
	} else {
		m_led_fwd->setColor( red );
		m_led_fwd->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useSynCookies() ) {
		m_led_syn->setColor( green );
		m_led_syn->on();
	} else {
		m_led_syn->setColor( red );
		m_led_syn->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useRPFilter() ) {
		m_led_rp->setColor( green );
		m_led_rp->on();
	} else {
		m_led_rp->setColor( red );
		m_led_rp->off();
	}

	if ( m_network->currentDocAsIPTDoc()->useMartians() ) {
		m_led_martians->setColor( green );
		m_led_martians->on();
	} else {
		m_led_martians->setColor( red );
		m_led_martians->off();
	}

// 	setCurrTableView( currTableView() );

	if ( ! rb_filter->isEnabled() && ! rb_nat->isEnabled() ) {
		rb_mangle->setChecked( true );
		setCurrTableView( m_lv_table_mangle );
	} else if ( ! rb_filter->isEnabled() &&   ! rb_mangle->isEnabled() ) {
		rb_nat->setChecked( true );
		setCurrTableView( m_lv_table_nat );
	} else if ( ! rb_nat->isEnabled() &&   ! rb_mangle->isEnabled() ) {
		rb_filter->setChecked( true );
		setCurrTableView( m_lv_table_filter );
	}

	emit sigUpdateView();
	m_app->updateCaption();
// 	slotEditRule();
}

/*
 *  Main event handler. Reimplemented to handle application
 *  font changes
 */
bool KMFRuleEdit::event( TQEvent* ev ) {
	bool ret = TQWidget::event( ev );
	if ( ev->type() == TQEvent::ApplicationFontChange ) {}
	return ret;
}

void KMFRuleEdit::slotHelp() {
	kdDebug() << "void KMFRuleEdit::slotHelp()" << endl;
	kapp->invokeHelp( "rules" );
}
void KMFRuleEdit::loadIcons() {
	kdDebug() << "void KMFRuleEdit::loadIcons()" << endl;
	TDEIconLoader *loader = TDEGlobal:: iconLoader();
	TQString icon_name;

	icon_name = "go-up";
	icon_up = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "go-down";
	icon_down = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "edit-delete";
	icon_del = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "document-new";
	icon_new = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "edit";
	icon_edit = loader->loadIcon( icon_name, TDEIcon::Small );


	icon_name = "filter";
	icon_filter = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "text";
	icon_rename = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "rule-22";
	icon_rule = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "view_tree";
	icon_chain = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "reject";
	icon_reject = loader->loadIcon( icon_name, TDEIcon::User );

	icon_name = "target";
	icon_target = loader->loadIcon( icon_name, TDEIcon::User );

	icon_name = "process-stop";
	icon_drop = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "button_ok";
	icon_accept = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "document-save-as";
	icon_log = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "edit-undo";
	icon_return = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "edit-clear";
	icon_cmd = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "filter";
	icon_filter = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "pipe";
	icon_queue = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "edit-copy";
	icon_copy = loader->loadIcon( icon_name, TDEIcon::Small );

	icon_name = "forward";
	icon_move = loader->loadIcon( icon_name, TDEIcon::Small );

}

}

#include "kmfruleedit.moc"
