/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************

Author: Christian Hubinger <chubinger@irrsinnig.org>, (C) 2001-2004

*/
#include "kmyfirewall.h"

// QT includes
#include <tqmessagebox.h>
#include <tqtextstream.h>
#include <tqpixmap.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqwidgetstack.h>
#include <tqvaluelist.h>
#include <tqlayout.h>

// KDE includes
#include <kapplication.h>
#include <kaction.h>
#include <kaccel.h>
#include <kstdaction.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kprocess.h>
#include <kdebug.h>
#include <dcopclient.h>
#include <kstatusbar.h>
#include <kpopupmenu.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kstdguiitem.h>
#include <kcmdlineargs.h>
#include <kio/netaccess.h>
#include <kfileitem.h>
#include <klibloader.h>
#include <ktextedit.h>
#include <kparts/partmanager.h>
#include <kpushbutton.h>
#include <kedittoolbar.h>

// C includes
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>

// project includes
#include "kmfapp.h"
#include "core/kmfconfig.h"
#include "core/kmferror.h"
#include "core/kmferrorhandler.h"
#include "core/kmfdoc.h"
#include "core/kmfnetwork.h"
#include "core/kmftarget.h"
#include "core/kmftargetconfig.h"
#include "core/kmfiptdoc.h"
#include "core/kmfgenericdoc.h"
#include "core/kmfpluginfactory.h"
#include "core/kmfappstate.h"
#include "core/kmfprotocollibrary.h"
#include "core/xmlnames.h"

#include "kmfwidgets/kmfprocout.h"
#include "kmfwidgets/kmfnewdocdlg.h"
#include "kmfwidgets/kmfobjectinfo.h"
#include "kmfwidgets/kmftemplatechooser.h"
#include "kmfwidgets/kmfdocumentinfo.h"
#include "kmfwidgets/kmfselectinterface.h" 
#include "kmfwidgets/kmfselectactivetarget.h" 
#include "kmfwidgets/kmftransactionlog.h" 
#include "kmfconfigdialog.h"
namespace KMF {
KMyFirewall::KMyFirewall( TQWidget* parent, const char *name ) : KMFMainWindow( parent, name ) {
// 	// kdWarning() << "MyFirewall Starting up..." << endl;
	// Initialize the document
	parseCommandLineArgs();
	
	set_splash_status( i18n( "Load Protocol Definitions..." ) );
	KMFProtocolLibrary::instance();
	
	m_network = 0;
	set_splash_status( i18n( "Initialise Document..." ) );
	m_network = new KMFNetwork( 0, "KMFNetwork", this );
	
	set_splash_status( i18n( "Initialise Undo/Redo engine..." ) );
	KMFUndoEngine::instance()->setKMFInterface( this );
	KMFTransactionLog::instance();
	
/*	childproc = new KProcess();
	
	connect( childproc, TQT_SIGNAL( processExited( KProcess* ) ), TQT_TQOBJECT(this), TQT_SLOT( slotProcessExited( KProcess* ) ) ) ;
	
	connect( childproc, TQT_SIGNAL( receivedStdout( KProcess*, char*, int ) ), TQT_TQOBJECT(this), TQT_SLOT( slotReceivedOutput( KProcess*, char*, int ) ) );
	
	connect( childproc, TQT_SIGNAL( receivedStderr( KProcess*, char*, int ) ), TQT_TQOBJECT(this), TQT_SLOT( slotReceivedError( KProcess*, char*, int ) ) );*/
	
	
	
	//########################
	set_splash_status( i18n( "Loading Plugins..." ) );
	// Initialize the settings dialog
	m_configDlg = new KMFConfigDialog( this, "config" );
	m_configDlg->setNetwork( network() );	
	connect ( m_configDlg, TQT_SIGNAL( sigConfigChanged() ),
	          TQT_TQOBJECT(this), TQT_SLOT( slotConfigChanged() ) );

	// Initialize error object
	m_err = new KMFError();
	m_err_handler = new KMFErrorHandler( "KMyFirewall" );
	
	

	set_splash_status( i18n( "Init statusbar..." ) );
	initStatusBar();
	set_splash_status( i18n( "Init actions..." ) );
	initActions();
	set_splash_status( i18n( "Init GUI..." ) );
	initView();
	set_splash_status( i18n( "Read configuration..." ) );
	if ( checkRoot() ) {
		if ( ! KMFConfig::configurationConverted() ) {
			closeSplash();
			const TQString & msg = i18n( "<qt><><h4>Compatibility Warning!</h4><p>" 
										"Since KMyFirewall 1.1.0 the configuration handling has changed to allow multi target rulesets. Because of this change all installation target dependent settings (paths, interfaces etc.) are stored within the ruleset document itself.</p>"
										"<p>The file extention for the new configuration format is <b>*.kmfnet (KMyFirewall Network Configuration)</b>. To import your old configuration select <b>File -&gt; New -&gt; New Empty Configuration</b> and use the <b>File -&gt; Import... -&gt; Import Target Config</b> menu entry and select a <b>*.kmfrs (IPTables interface)</b>  or <b>*.kmfgrs (Generic interface)</b> file. If you allready defined several targets (e.g. different firewalled computers) in your configuration the application will show you a dialog to select the target that should use the configuration.</p>" 
										"<p>All configuration setting you have allready made for your local computer using an older version of KMyFirewall will be imported and applied  to the localhost target.</p>" 
										"</qt>" );
			KMessageBox::information( this, msg, i18n( "Warning" ), "configuration_not_converted_to_1.1.0_warning" );
		
			m_configDlg->convertConfig();
		}
		
		
		if ( KMFConfig::firstRun() ) {
			closeSplash();
			slotConfigureKMF();
			slotFileNew();
		} else {
			set_splash_status( i18n( "Restoring session..." ) );
			m_fileToOpen = KMFConfig::currentConfiguration();
			slotRestoreSession();
		}
		setActiveWindow(); // Make sure this window gets keyboard focus
		raise(); // Make sure the window is now on top of other windows
		statusBar() ->changeItem( "Ready", 0 );
		checkStatus();
	} else {
		close(); // User indicated an abort is needed, so close the main window
	}

	KMFAppState::setUpAndRunning( true );
	slotConfigChanged();
	KMFUndoEngine::instance()->clearStacks();
	updateCaption();
	statusBar() ->changeItem( "Ready", 0 );
}

KMyFirewall::~KMyFirewall() {}

//############ Parse CommandLine #####################
void KMyFirewall::parseCommandLineArgs() {
	kdDebug() << "############ Parse CommandLine ###############" << endl;
	KCmdLineArgs * args = KCmdLineArgs::parsedArgs();
	
	

	TQString curr = "";
	kdDebug() << "Args count: " << args->count() << endl;
	// kdDebug() << "Open File: " << args->arg( 0 ) << " passed from commandLine " << endl;
	if ( args->count() == 1 ) {
		curr = args->arg( 0 );
		kdDebug() << "Open File: " << curr << " passed from commandLine " << endl;
		KURL url( curr );
		if ( prepareForFileOpen( url ) ) {
			m_fileToOpen = curr;
		} else {
			closeSplash();
			const TQString & msg = i18n( "<qt><p>Open File %1 failed</p>" 
										"</qt>" ).arg( curr ) ;
			KMessageBox::error( this, msg, i18n( "Error" ) );
			// Show interface select if open file failed when requested
			if ( KMFConfig::showSelInterface() ) {
				closeSplash();
				slotSelectInterface();
			}
		}
	} else if ( args->isSet("i") ) {
		TQString interface = args->getOption("i");
		kdDebug() << "Found interface option: " << interface << endl;
		if ( interface == XML::IPTablesGUIInterface_Value ) {
			KMFConfig::setUseGenericInterface( false );
			KMFConfig::writeConfig();
			kdDebug() << "Start using iptables interface" << endl;
		} else if ( interface == XML::GenericGUIInterface_Value ) {
			KMFConfig::setUseGenericInterface( true );
			KMFConfig::writeConfig();
			kdDebug() << "Start using generic interface" << endl;
		} else {
// 			kdWarning() << "Unrecognized argument: " << interface << " for option i" <<  endl;
		}
	} else if ( ! args->isSet("i") && KMFConfig::showSelInterface() ) {
		closeSplash();
		slotSelectInterface();
	}
	kdDebug() << "############ Parse CommandLine Finished ###############" << endl;
}


//############ Start Init Methods ####################
void KMyFirewall::initView() {
	kdDebug() << "KMyFirewall::initView()" << endl;
	m_widgetStack = new TQWidgetStack( this, "stack" );
	setCentralWidget( m_widgetStack );
	// Load the main editor widget
	KParts::ReadWritePart* mainView = KMFPluginFactory::KMFMainView( this, m_err );
	if ( ! m_err_handler->showError( m_err ) ) {
		kapp->quit();
	}
	if ( ! mainView ) {
		KMessageBox::error( this, i18n( "KMFPluginFactory::KMFMainView( this, m_err ): returned a NULL pointer" ) );
		kapp->quit();
	}
	m_editorWidget = mainView->widget();
	m_widgetStack->addWidget( m_editorWidget );
	m_widgetStack->raiseWidget( m_editorWidget );
	createGUI( mainView );
	m_outputWidget = new TQWidget( this, "output" );
	m_widgetStack->addWidget( m_outputWidget );
	emit sigEnableActions( false );
}

void KMyFirewall::updateView() {
	updateCaption();
	
	KParts::ReadWritePart* mainView = KMFPluginFactory::KMFMainView( this, m_err );
	if ( ! m_err_handler->showError( m_err ) ) {
		kapp->quit();
	}
	if ( ! mainView ) {
		KMessageBox::error( this, i18n( "KMFPluginFactory::KMFMainView( this, m_err ): returned a NULL pointer" ) );
		kapp->quit();
	}
	m_editorWidget = mainView->widget();
	TQWidget* wid = m_widgetStack->widget( m_widgetStack->id( m_editorWidget ) );
	wid = m_editorWidget;

	createGUI( mainView );
	m_widgetStack->raiseWidget( m_editorWidget );
	emit sigEnableActions( false );
}

void KMyFirewall::showEditor() {
	m_widgetStack->raiseWidget( m_editorWidget );
}

void KMyFirewall::slotShowEditor() {
	showEditor();
	emit sigEnableActions( true );
}

void KMyFirewall::showOutput() {
	m_widgetStack->raiseWidget( m_outputWidget );
	emit sigEnableActions( false );
}

void KMyFirewall::slotShowTransactionLog() {
	kdDebug() << "KMyFirewall::slotShowTransactionLog();" << endl;
	KMFTransactionLog::instance()->show();
	KMFTransactionLog::instance()->raise();
}

void KMyFirewall::setOutputWidget( TQWidget* wid ) {
	m_widgetStack->removeWidget( m_outputWidget );
	TQWidget* widget = new TQWidget( this , "output" );
	TQGridLayout *layout = new TQGridLayout( widget, 1, 1 );
	wid->reparent( widget, ( unsigned int ) 0 , *( new TQPoint( 0, 0 ) ) );
	layout->addWidget( wid, 0, 0 );
	kdDebug() << "Adding outputwidget: " << wid->className() << endl;
	if ( strcmp(wid->className(), "KMFObjectInfo") ) {
		KPushButton * close = new KPushButton( i18n( "Return to Editor View" ), widget );
		connect( close, TQT_SIGNAL( clicked() ),
		         TQT_TQOBJECT(this), TQT_SLOT( slotShowEditor() ) );
		layout->addWidget( close, 1, 0 );
	}
	m_outputWidget = widget;
	m_widgetStack->addWidget( widget );
}

void KMyFirewall::initActions() {
	kdDebug() << "Init Actions..." << endl;
	// Custom Actions

	actionEditDocInfo = new KAction( i18n( "&Edit Document Information" ), "edit", 0 , TQT_TQOBJECT(this), TQT_SLOT( slotEditDocInfo() ), actionCollection(), "edit_doc_info" );

	// KStdAction
	actionNew = KStdAction::openNew( TQT_TQOBJECT(this), TQT_SLOT( slotFileNew() ),
	                                 actionCollection(), "new" );

	actionClose = KStdAction::close( TQT_TQOBJECT(this), TQT_SLOT( slotFileClose() ),
	                                 actionCollection(), "close" );

	actionOpen = KStdAction::open( TQT_TQOBJECT(this), TQT_SLOT( slotFileOpen() ),
	                               actionCollection(), "open" );

	actionSave = KStdAction::save( TQT_TQOBJECT(this), TQT_SLOT( slotFileSave() ),
	                               actionCollection(), "save" );

	actionSaveAs = KStdAction::saveAs( TQT_TQOBJECT(this), TQT_SLOT( slotFileSaveAs() ),
	                                   actionCollection(), "save_as" );
	actionSaveAs->setEnabled( false );

	actionQuit = KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( slotQuitApp() ),
	                               actionCollection(), "quit" );

	actionUndo = KStdAction::undo( TQT_TQOBJECT(this), TQT_SLOT( slotUndo() ),
	                               actionCollection(), "undo" );

	actionRedo = KStdAction::redo( TQT_TQOBJECT(this), TQT_SLOT( slotRedo() ),
	                               actionCollection(), "redo" );

	actionExportTargetConfig = new KAction( i18n( "&Export Target Configuration..." ), "wizard", 0 , TQT_TQOBJECT(this), TQT_SLOT( slotExportTargetConfig() ),
	                                  actionCollection(), "export_tagret_config" );
	
	actionImportTargetConfig = new KAction( i18n( "&Import Target Configuration..." ), "wizard", 0 , TQT_TQOBJECT(this), TQT_SLOT( slotImportTargetConfig() ), 
	                                  actionCollection(), "import_tagret_config" );
	
	actionShowTransactionLog = new KAction( i18n( "&Show Transaction Log..." ), "wizard", 0 , TQT_TQOBJECT(this), TQT_SLOT( slotShowTransactionLog() ),
	                                  actionCollection(), "show_transaction_log" );
	
	actionLoadTemplate = new KAction( i18n( "&Load Template..." ), "wizard", 0 , TQT_TQOBJECT(this), TQT_SLOT( slotLoadTemplate() ),
	                                  actionCollection(), "load_template" );
	                                  
//	KStdAction::showToolbar( TQT_TQOBJECT(this), TQT_SLOT( toggleToolBar() ) , actionCollection() );
	KStdAction::showStatusbar( TQT_TQOBJECT(this), TQT_SLOT( toggleStatusBar() ), actionCollection() );
	KStdAction::preferences( TQT_TQOBJECT(this), TQT_SLOT( slotConfigureKMF() ), actionCollection() );
	KStdAction::configureToolbars( TQT_TQOBJECT(this), TQT_SLOT( slotConfigureToolbars() ), actionCollection() );
}


//############ End Init Methods ####################

void KMyFirewall::slotExportTargetConfig() {
	kdDebug() << "KMyFirewall::slotExportTargetConfig()" << endl;
	KMFTarget* tg = KMFSelectActiveTarget::selectTarget( network(), i18n("<qt><p>Please select the Targetfrom which the configuration should be exported.</p></qt>") );
	if ( ! tg ) {
		return;	
	}
	TQString s = tg->doc()->getXMLRuleset();
	kdDebug() << "Got XML: " << s << endl;
	tg->doc()->exportXMLRuleset( true, false );
}

void KMyFirewall::slotConfigureToolbars() {
	saveMainWindowSettings( KGlobal::config(), "KMyFirewall" );
	KEditToolbar dlg( factory() );
	connect( &dlg, TQT_SIGNAL( newToolbarConfig() ), TQT_TQOBJECT(this), TQT_SLOT( slotNewToolbarConfig() ) );
	dlg.exec();
}

void KMyFirewall::slotNewToolbarConfig() {
	applyMainWindowSettings( KGlobal::config(), "KMyFirewall" );
}

//check for the uid etc...
bool KMyFirewall::checkRoot() {
	// Is application started as root?
	if ( getuid() != 0 ) {
		closeSplash();
		const TQString & msg = i18n( "<qt><p><b>KMyFirewall was not started as user <i>root</i>.</b><br>"
		                            "You will be prompted for the root password when you try to do something that requires root access.</p>"
		                            "<p><b>Do you still want to continue?</b></p></qt>" );
		int choise = KMessageBox::warningYesNo( NULL, msg, i18n( "Warning" ), KStdGuiItem::yes(), KStdGuiItem::no(), "not_root_warning" );
		switch ( choise ) {
		case 4:
			kdDebug() << "Clicked NO" << endl;
			return false; // Abort and prevent application continuing from here
		case 3:
			kdDebug() << "Clicked Yes" << endl;
			break;
		default:
			return false; // Any action but pressing 'yes' will abort application
		}
	}
		
	const TQString& msg = i18n( "<qt><b>Compatibility Warning</b>.<p> "
"As the file format used to save the rulesets has changed, "
"rulesets created with KMyFirewall &lt; 1.0beta1 <b>WILL NOT</b> work, don't even try it!"
		"</p></qt>" );
	KConfig* _config = kapp->config();
	_config->setGroup( "Notification Messages" );
	TQString warn = "";
	warn = _config->readEntry( "compatibility_warning" );
	if ( warn != "false" )
		closeSplash();
	KMessageBox::information( NULL, msg, i18n( "Warning - File format change" ), "compatibility_warning", 0 );
	return true;
}

bool KMyFirewall::saveQuit() {
	if ( ! KMFUndoEngine::instance()->isSaved() && !network()->currentDoc()->isEmpty() ) {
		const TQString & msg = i18n( "<p>Do you want to save the changes before you quit?" );
		const TQString& title = i18n( "Quit" );
		int doit = KMessageBox::questionYesNoCancel ( this , msg, title );
		kdDebug() << "Message Box returned: " << doit << endl;
		if ( doit == 3 ) { // OK clicked
			slotFileSave();
			return true;
		}
		if ( doit == 2 ) { // Cancel clicked
			return false;
		}
		if ( doit == 4 ) { // No clicked
			return true;
		}
		return false;
	}
	return true;
}

void KMyFirewall::slotQuitApp() {
	bool quit = saveQuit();
	if ( quit ) {
		KMFConfig::self() ->writeConfig();
		kapp->quit();
	}
}

KMFNetwork*  KMyFirewall::network() {
	return m_network;
}

void KMyFirewall::closeEvent( TQCloseEvent* ) {
	slotQuitApp();
}

void KMyFirewall::toggleToolBar() {
	if ( toolBar() ->isVisible() )
		toolBar() ->hide();
	else
		toolBar() ->show();
}
void KMyFirewall::toggleStatusBar() {
	if ( statusBar() ->isVisible() )
		statusBar() ->hide();
	else
		statusBar() ->show();
}

void KMyFirewall::initStatusBar() {
	kdDebug() << "KMyFirewall::initStatusBar()" << endl;
	statusBar() ->insertItem( i18n( "Starting Up" ), 0, true );
	statusBar() ->insertItem( "", 1, true );
}

void KMyFirewall::slotConfigChanged() {
	kdDebug() << "KMyFirewall::slotConfigChanged()" << endl;
	KMFUndoEngine::instance()->setMaxUndo( KMFConfig::maxUndo() );
	
	
	updateCaption();	
	// FIXME: enable dynamicly interface changeing
	//updateView();
	emit sigUpdateView();
}

void KMyFirewall::updateCaption(){
 	if ( ! network() || ! network()->currentTarget() ) {
 		return;
 	}
	TQString s = network()->url().fileName() + i18n(" Configuring Target %1").arg( network()->currentTarget()->toFriendlyString() );
	if ( ! KMFUndoEngine::instance()->isSaved() ) {
		s += i18n( "[modified]" );
	}
	setCaption( s );
}


void KMyFirewall::slotEnableSave() {
	actionSave->setEnabled( true );
}

void KMyFirewall::slotEditDocInfo() {
	KMFDocumentInfo * dlg = new KMFDocumentInfo( this, "KMFObjectInfo", true );
	dlg->loadDoc( network()->currentDoc() );
	connect( dlg,TQT_SIGNAL( sigSaveAsTemplate() ) , TQT_TQOBJECT(this), TQT_SLOT( slotFileSaveAsTemplate() )  );
	dlg->exec();
}

void KMyFirewall::slotSelectInterface() {
	KMFSelectInterface * m_sel = new KMFSelectInterface( 0, "KMFSelectInterface", true, TQWidget::WDestructiveClose | TQWidget::WStyle_Customize | TQWidget::WStyle_NoBorder );
	closeSplash();
	if ( m_sel->exec() == TQDialog::Rejected ) {
		kdDebug() << "Wante to exit now..." << endl;
		kapp->quit();
		; // FIXME: Doe not work - kapp->quit();
	}
	showSplash();
}

void KMyFirewall::slotUndo() {
	kdDebug() << "KMyFirewall::slotUndo()" << endl;
	TQValueList< NetfilterObject* >& aff = KMFUndoEngine::instance()->undo();
	
	TQValueList< NetfilterObject* >::iterator it;
	for ( it = aff.begin(); it != aff.end(); ++it ) {
		emit sigUpdateView( *it );
	}
}

void KMyFirewall::slotRedo() {
	kdDebug() << "KMyFirewall::slotRedo()" << endl;
	TQValueList< NetfilterObject* >& aff = KMFUndoEngine::instance()->redo();
	
	TQValueList< NetfilterObject* >::iterator it;
	for ( it = aff.begin(); it != aff.end(); ++it ) {
		emit sigUpdateView( *it );
	}
}



void KMyFirewall::slotFileOpen() {
	kdDebug() << "KMyFirewall::slotFileOpen()" << endl;
	KURL url;
	url = KFileDialog::getOpenURL( ":", TQString( "%1" ).arg( network()->getFileDialogFilter() ) );
	
	TQString xmlfile = url.path();
	if ( url.path().isEmpty() ) {
		return ;
	} 
	slotLoadFile( xmlfile );

/*	statusBar() ->message( i18n( "Open file: " ) + url.path() , 5000 );
	m_err = parseDocument( url );
	m_err_handler->showError( m_err );
	updateCaption();
	emit sigUpdateView();*/
}

void KMyFirewall::slotLoadFile( const TQString& file ) {
	kdDebug() << "void KMyFirewall::slotLoadFile( const TQString& " << file << " )" << endl;
	
	KURL url( file );
	
	statusBar() ->message( i18n( "Open file: " ) + url.path() , 5000 );
	m_err = parseDocument( url );
	m_err_handler->showError( m_err );
	updateCaption();	
	emit sigUpdateView();
}

void KMyFirewall::slotImportTargetConfig() {
	kdDebug() << "KMyFirewall::slotImportTragetConfig()" << endl;
	KURL url;
	url = KFileDialog::getOpenURL( ":", TQString( "%1" ).arg( network()->currentDoc()->getFileDialogFilter() ) );
	
	TQString xmlfile = url.path();
	if ( url.path().isEmpty() ) {
		return ;
	} 

	statusBar() ->message( i18n( "Imported file: " ) + url.path() , 5000 );
	m_err = parseDocument( url );
	m_err_handler->showError( m_err );
	updateCaption();
	emit sigUpdateView();
}

void KMyFirewall::slotLoadTemplate() {
	KMFTemplateChooser * dlg = new KMFTemplateChooser( 0 , "KMyFirewall - Load Template", true, TQWidget::WDestructiveClose | TQWidget::WStyle_Customize | TQWidget::WStyle_NoBorder );
	
	// dlg->parseTemplates();
	connect( dlg, TQT_SIGNAL( sigLoadTemplate( const TQString& ) ),
	         TQT_TQOBJECT(this), TQT_SLOT( slotLoadFile( const TQString& ) ) );
/*	connect( dlg, TQT_SIGNAL( sigLoadEmptyDocument() ),
	         TQT_TQOBJECT(this), TQT_SLOT( slotLoadFile( const TQString& ) ) );*/
	dlg->exec();
}

void KMyFirewall::slotFileClose() {
	kdDebug() << "KMyFirewall::slotFileClose()" << endl;
	bool choose_save = false;
	if ( KMFAppState::upAndRunning() && ! KMFUndoEngine::instance()->isSaved() /*&& ! network()->isEmpty()*/ /*&& KMFAppState::hasOpenDoc()*/ ) {
		
		switch ( TQMessageBox::warning( this, i18n( "Save Changed Data?" ),
		                               i18n( "This firewall configuration has been changed since it was last saved.\n\n"
		                                     "What do you want to do with these changes?\n" ),
		                               i18n( "&Cancel" ), i18n( "&Discard" ), i18n( "&Save" ),
		                               2, 3 ) ) {

		case 0:
			kdDebug() << "Clicked Cancel" << endl;
			return ;
		case 1:
			kdDebug() << "Clicked Discard" << endl;
			break;
		case 2:
			kdDebug() << "Clicked Save" << endl;
			choose_save = true;
			slotFileSave();
			break;
		}
	}
	if ( ! choose_save ) {
		network()->clear();
		KMFConfig::setCurrentConfiguration( "" );
		actionSave->setEnabled( false );
		updateCaption();	
		toggleActions( false );
		emit sigUpdateView();
	}
	emit sigUpdateView();
}




bool KMyFirewall::prepareForFileOpen( const KURL& url ) {
	kdDebug() << "void KMyFirewall::prepareForFileOpen( const KURL&" << url.fileName() << " )" << endl;
	TQString xmlfile;
	if ( KMFAppState::upAndRunning() ) {
		kdDebug() << "ERROR: calling KMyFirewall::prepareForFileOpen(--) after application startup" << endl;
		return false;
	}
	
	if ( ! KIO::NetAccess::download( url, xmlfile, KApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "Could not download file." << endl;
		return false;
	}

	if ( !xmlfile.isEmpty() ) {
		TQFile kmfrsFile( xmlfile );
		
		if ( !kmfrsFile.open( IO_ReadOnly ) ) {
			return false;
		}
		
		TQDomDocument doc;
		if ( !doc.setContent( &kmfrsFile ) ) {
			kmfrsFile.close();
			return false;
		}
		kmfrsFile.close();
		TQDomElement root = doc.documentElement();
		
		TQString version = "";
		TQString minVersion = "";
		TQString maxVersion = "";
		TQString interface = "";
		
		if ( root.hasAttribute( XML::Version_Attribute ) ) {
			version = root.attribute( XML::Version_Attribute );
		}
		
		if ( root.hasAttribute( XML::MinVersion_Attribute ) ) {
			minVersion = root.attribute( XML::MinVersion_Attribute );
		}

		if ( root.hasAttribute( XML::MaxVersion_Attribute ) ) {
			maxVersion = root.attribute( XML::MaxVersion_Attribute );
		}
		
		if ( root.nodeName() == XML::GenericDoc_DocumentElement ) {
			kdDebug() << "Got kmfgrs doc" << endl;
			kdDebug() << "Startup Using Generic Interfafce" << endl;
			KMFConfig::setUseGenericInterface( true );
			KMFConfig::writeConfig();
			return true;
		} else if ( root.nodeName() == XML::IPTDoc_DocumentElement ) {
			kdDebug() << "Got kmfrs doc" << endl;
			kdDebug() << "Startup Using IPTables Interfafce" << endl;
			KMFConfig::setUseGenericInterface( false );
			KMFConfig::writeConfig();
			return true;
		} else if ( root.nodeName() == XML::KMFNetwork_DocumentElement ) {
			kdDebug() << "Got kmfnet doc" << endl;
			if ( root.hasAttribute( XML::Interface_Attribute ) ) {
				interface = root.attribute( XML::Interface_Attribute );
				if ( interface == XML::IPTablesGUIInterface_Value ) {
					KMFConfig::setUseGenericInterface( false );
					KMFConfig::writeConfig();
					kdDebug() << "Startup Using IPTables Interfafce" << endl;
				} else {
					KMFConfig::setUseGenericInterface( true );
					KMFConfig::writeConfig();
					kdDebug() << "Startup Using Generic Interfafce" << endl;
				}
				return true;
			} else {
				kdDebug() << "No interface attribute found!" << endl;
			}
		}
		return false;
	}
	return false;
}

KMFDoc* KMyFirewall::getDocumentLoaderForUrl( const KURL& url, KMFError* err ) {
	kdDebug() << "void KMyFirewall::getDocumentLoaderForUrl( const KURL&" << url.fileName() << " )" << endl;
	err->setErrType( KMFError::OK );
	TQString xmlfile;
	if ( ! KIO::NetAccess::download( url, xmlfile, KApplication::kApplication()->mainWidget() ) ) {
		kdDebug() << "Could not download file." << endl;
		err->setErrType( KMFError::NORMAL );
		err->setErrMsg( i18n( "<qt>Could not download file %1</qt>" ).arg( url.url() ) );
		return 0;
	}

	if ( !xmlfile.isEmpty() ) {
		TQFile kmfrsFile( xmlfile );
		
		if ( !kmfrsFile.open( IO_ReadOnly ) ) {
			err->setErrType( KMFError::NORMAL );
			err->setErrMsg( i18n( "<qt>Could not read file %1.</qt>" ).arg( url.url() ) );
			return 0;
		}
		
		TQDomDocument doc;
		if ( !doc.setContent( &kmfrsFile ) ) {
			kmfrsFile.close();
			err->setErrType( KMFError::NORMAL );
			err->setErrMsg( i18n( "<qt>File %1 in not a vaild XML file.</qt>" ).arg( url.url() ) );
			return 0;
		}
		kmfrsFile.close();


		kdDebug() << "Find Opener For file: " << xmlfile << endl;
		TQDomElement root = doc.documentElement();
		
		TQString version = "";
		TQString minVersion = "";
		TQString maxVersion = "";
		
		if ( root.hasAttribute( XML::Version_Attribute ) ) {
			version = root.attribute( XML::Version_Attribute );
		}
		
		if ( root.hasAttribute( XML::MinVersion_Attribute ) ) {
			minVersion = root.attribute( XML::MinVersion_Attribute );
		}

		if ( root.hasAttribute( XML::MaxVersion_Attribute ) ) {
			maxVersion = root.attribute( XML::MaxVersion_Attribute );
		}
		
		TQPtrList<KMFTarget> *list = new TQPtrList<KMFTarget>;
		network()->netzone()->getAllTargets( network()->netzone(), list );
		
		const TQString& selTargetDialogMessage = i18n("<qt><p>Please select the Target host that should load the selected configuration.</p></qt>");
		if ( root.nodeName() == XML::IPTDoc_DocumentElement ) {
			if ( ! KMFConfig::useGenericInterface() ) {
					KMFTarget* tg = KMFSelectActiveTarget::selectTarget( network(), selTargetDialogMessage );
					if ( ! tg ) {
					err->setErrType( KMFError::NORMAL );
					err->setErrMsg( i18n( "<qt>No target found to load document.</qt>" ) );
						return 0;
					}
					network()->setCurrentTarget( tg );
					updateCaption();
				kdDebug() << "Returned IPT Doc for target: " << network()->currentTarget()->guiName() << endl;
				KIO::NetAccess::removeTempFile( xmlfile );
				return network()->currentDocAsIPTDoc();
			}
		} else if ( root.nodeName() == XML::GenericDoc_DocumentElement ) {
			if ( KMFConfig::useGenericInterface() ) {
					KMFTarget* tg = KMFSelectActiveTarget::selectTarget( network(), selTargetDialogMessage );
					if ( ! tg ) {
						err->setErrType( KMFError::NORMAL );
 						err->setErrMsg( i18n( "<qt>No target found to load document.</qt>" ) );
						return 0;
					}
					network()->setCurrentTarget( tg );
					updateCaption();
				kdDebug() << "Returned GEneric Doc for target: " << network()->currentTarget()->guiName() << endl;
				KIO::NetAccess::removeTempFile( xmlfile );
				return network()->currentDocAsGenericDoc();
			}
		} else if ( root.nodeName() == XML::KMFNetwork_DocumentElement ) {
			TQString	interface = root.attribute( XML::Interface_Attribute );
			if (  interface == XML::GenericGUIInterface_Value && ! KMFConfig::useGenericInterface() )  {
				kdDebug() << "Invalid Document type: " << interface << " found " << endl;
				err->setErrType( KMFError::NORMAL );
				err->setErrMsg( i18n( "<qt>You are running KMyFirewall with the <b>IPTables Interface</b> but the document was created using the <b>Generic Interface</b>.</qt>" ) );
				return 0;	
			} 
			if ( interface == XML::IPTablesGUIInterface_Value && KMFConfig::useGenericInterface() ) {
				kdDebug() << "Invalid Document type: " << interface << " found " << endl;
				err->setErrType( KMFError::NORMAL );
				err->setErrMsg( i18n( "<qt>You are running KMyFirewall with the <b>Generic Interface</b> but the document was created using the <b>IPTables Interface</b>.</qt>" ) );
				return 0;	
			} 	
				
			
			kdDebug() << "Returned KMFNetwork " << network()->currentTarget()->guiName() << endl;
			KIO::NetAccess::removeTempFile( xmlfile );
			return network();
		}
		KIO::NetAccess::removeTempFile( xmlfile );
		kdDebug() << "ERROR: No Loader Found!" << endl;
		err->setErrType( KMFError::NORMAL );
		err->setErrMsg( i18n( "<qt>The document is not a valid KMyFirewall document.</qt>" ) );
		return 0;
	}
	KIO::NetAccess::removeTempFile( xmlfile );
	err->setErrType( KMFError::NORMAL );
	err->setErrMsg( i18n( "<qt>Could not download file %1.</qt>" ).arg( url.url() ) );
	return 0;
}

KMFError* KMyFirewall::parseDocument( const KURL& url ) {
	kdDebug() << "void KMyFirewall::parseDocument(TQString& file)" << endl;
	KIO::UDSEntry f_props;
	
	if ( ! KIO::NetAccess::stat( url , f_props, KApplication::kApplication()->mainWidget() ) ) {
		closeSplash();
		const TQString msg = i18n( "<qt><p>The file <b>%1</b> could not be loaded.</p>"
		                          "<p>If you are working with files stored on remote computers "
		                          "make sure that the network is up and the fileserver running.</qt>" ).arg( url.url() );
		m_err->setErrType( KMFError::NORMAL );
		m_err->setErrMsg( msg );
		return m_err;
	}
	KFileItem *props = new KFileItem( f_props, url );
	kdDebug() << "Found file permissions: " << props->permissionsString() << endl;
	if ( !props->isReadable() ) {
		const TQString msg = i18n( "<qt><p>You don't have the permissions to read file: <b>%1</b></p></qt>" ).arg( url.url() );
		m_err->setErrType( KMFError::NORMAL );
		m_err->setErrMsg( msg );
		return m_err;
	}
	
	KMFDoc* loader = getDocumentLoaderForUrl( url, m_err );
	if ( m_err->errType() != KMFError::OK &&  m_err->errType() != KMFError::HINT ) {
		return m_err;
	}
	
	if ( ! loader ) {
		const TQString msg = i18n( "<qt><p>No loader found for file: <b>%1</b></p></qt>" ).arg( url.url() );
		m_err->setErrType( KMFError::NORMAL );
		m_err->setErrMsg( msg );
		return m_err;
	}
	if ( loader == m_network ) {
		slotFileClose();
	}
	
	TQStringList *errors = new TQStringList();
	loader->parseDocument( url, *errors );
	
	if ( loader == m_network ) {
		KMFConfig::setCurrentConfiguration( url.url() );
	}
	
	KMFError *err = KMFError::parseErrors( *errors );
	if ( err->errType() != KMFError::OK &&  err->errType() != KMFError::HINT ) {
		return err;
	}
	
	
	slotEnableRedo( false );
	if ( network()->currentDoc() == 0 ) {
		kdDebug() << "void KMyFirewall::parseDocument(TQString& file)\nkmfdoc == 0" << endl;
		KMFConfig::setCurrentConfiguration( "" );
		network()->currentDoc()->clear();
		m_err->setErrType( KMFError::NORMAL );
		const TQString msg = i18n( "<qt>Unable to load file %1.</qt>" ).arg( url.url() );
		m_err->setErrMsg( msg );
		return m_err;
	}
	
	const TQString filename = url.fileName();
	
	
	toggleActions( true );
	actionSave->setEnabled( true );
	checkStatus();
	updateCaption();
	m_err->setErrType( KMFError::OK );
	const TQString msg = "";
	m_err->setErrMsg( msg );
	return m_err;
}


void KMyFirewall::slotRestoreSession() {
	kdDebug() << "############## RestoreSession #############" << endl;
	
	bool worked = true;
	if ( ! KMFConfig::currentConfiguration().isNull() && !  KMFConfig::currentConfiguration().isEmpty() ) {
		KURL url( KMFConfig::currentConfiguration() );
		m_err = parseDocument( url );
		if ( ! m_err_handler->showError( m_err ) ) {
			updateCaption();
			slotEnableUndo( false );
			slotEnableUndo( false );
			worked = false;
		}
		
		checkStatus();
		if ( ! worked ) {
			KMFConfig::setCurrentConfiguration( "" );
		}
	}
	kdDebug() << "############## Restore Session FINISHED #############" << endl;
}


void KMyFirewall::slotFileNew() {
	kdDebug() << "KMyFirewall::slotFileNew()" << endl;
	slotFileClose();
	KMFNewDocDlg *dlg = new KMFNewDocDlg( 0, "KMyFirewall - New Document", TQWidget::WDestructiveClose | TQWidget::WStyle_Customize | TQWidget::WStyle_NoBorder );
	dlg->show() ;
	dlg->raise();
	connect( dlg, TQT_SIGNAL( sigNewDocLoadTemplate() ), TQT_TQOBJECT(this), TQT_SLOT( slotLoadTemplate() ) );
	connect( dlg, TQT_SIGNAL( sigNewDocLoadEmpty() ), TQT_TQOBJECT(this), TQT_SLOT( slotLoadEmptyRuleset() ) );
	connect( dlg, TQT_SIGNAL( sigNewDocLoadSaved() ), TQT_TQOBJECT(this), TQT_SLOT( slotFileOpen() ) );
}

void KMyFirewall::slotLoadEmptyRuleset() {
	kdDebug() << "slotLoadEmptyRuleset()" << endl;
	network()->clear();
	// slotLoadDocument( network() );
	toggleActions( true );
	actionSave->setEnabled( true );
	checkStatus();
	toggleActions( true );
//	m_configDlg->slotAutoConf();
	
	updateCaption();
	emit sigUpdateView();
}


//############# Save Stuff #################//

void KMyFirewall::slotFileSaveAs() {
	kdDebug() << "KMyFirewallMainView::slotFileSaveAs()" << endl;
	KURL url;
	saveDocument( true, false );
}

void KMyFirewall::slotFileSaveAsTemplate() {
	kdDebug() << "KMyFirewallMainView::slotFileSaveAsTemplate()" << endl;
	// KURL url;
	saveDocument( true, true );
}



void KMyFirewall::slotFileSave() {
	// FIXME: reenable after generic doc works
	/*	if ( kmfdoc->isSaved() ) {
			statusBar() ->message( i18n( "No changes to save." ) , 5000 );
			// 		actionSave->setEnabled( false );
			return ;
		}*/
	m_err = saveDocument( false, false );
	kdDebug() <<  "m_err" + m_err->errNum() << endl;
	if ( m_err_handler->showError( m_err ) ) {
		kdDebug() << "Wrote file: " << network()->url().path() << endl;
//		network()->saved();
		statusBar() ->message( i18n( "Wrote file: " ) + network()->url().fileName(), 5000 );
		updateCaption();
	}
}

KMFError* KMyFirewall::saveDocument( bool promptURL, bool asTemplate  ) {
	kdDebug() << "void KMyFirewall::saveDocument( promptURL " << promptURL << " , bool asTemplate " << asTemplate << " )" << endl;
	

	m_err = network()->exportXMLRuleset( promptURL, asTemplate );
	if ( m_err->errType() != KMFError::OK ) {
		return m_err;
	}
		
	// network()->url().set;
	KMFConfig::setCurrentConfiguration( network()->url().url() );

	kdDebug() << "Wrote URL: " << network()->url() << endl;
	updateCaption();		
	m_err -> setErrType( KMFError::OK );
	m_err -> setErrMsg( "" );
	return m_err;
}


//#############################################//

void KMyFirewall::slotConfigureKMF() {
	closeSplash();
	m_configDlg->slotReadConfig();
	m_configDlg->exec();
}

//################ Check Status #############//
// FIXME: Implement iptables active check

void KMyFirewall::checkStatus() {
	kdDebug() << "checkStatus()" << endl;
	bool isInstalled = false;
	
	if ( network()->currentTarget()->isLocalExecuteTarget() ) {
		FILE *sbin1;
		sbin1 = fopen( "/etc/kmyfirewall", "r" );
		if ( sbin1 != NULL ) {
			kdDebug() << "Firewall is installed" << endl;
			isInstalled = true;
			fclose( sbin1 );
		} 
	} else {
		if ( KIO::NetAccess::exists( network()->currentTarget()->getFishUrl() + "/etc/kmyfirewall", true, KApplication::kApplication()->mainWidget() ) ) {
			kdDebug() << "Firewall is installed" << endl;
			isInstalled = true;
		}
	}
	
	
	
	if ( isInstalled ) {
		statusBar() ->changeItem( i18n( "Firewall is installed on %1" ).arg( network()->currentTarget() ->toFriendlyString() ), 1 );
	} else {
		statusBar() ->changeItem( i18n( "Firewall is not installed on %1" ).arg(  network()->currentTarget() ->toFriendlyString() ), 1 );
	}
	
	
	
}


//############# UNDO ###################// 
void KMyFirewall::enableUndo( bool onoff ) {
	kdDebug() << "void KMyFirewall::enableUndo( bool " << onoff << " )" << endl;
	if ( ! KMFUndoEngine::instance()->maxUndo() ) {
		actionUndo->setEnabled( false );
		return ;
	}
	actionUndo->setEnabled( onoff );
}

void KMyFirewall::enableRedo( bool onoff ) {
	kdDebug() << "void KMyFirewall::enableRedo( bool " << onoff << " )" << endl;
	if ( ! KMFUndoEngine::instance()->maxUndo() ) {
		actionRedo->setEnabled( false );
		return ;
	}
	actionRedo->setEnabled( onoff );
}

void KMyFirewall::slotEnableUndo( bool onoff ) {
	kdDebug() << "void KMyFirewall::slotEnableUndo( bool " << onoff << " )" << endl;
	enableUndo( onoff );
}

void KMyFirewall::slotEnableRedo( bool onoff ) {
	kdDebug() << "void KMyFirewall::slotEnableUndo( bool " << onoff << " )" << endl;
	enableRedo( onoff );
}
//########### ACTION TOGGLES ################//
/** toggle the available actions  */
void KMyFirewall::toggleActions( bool ) {
// 	if ( on ) {
		// actionClose->setEnabled( true );
		actionSave->setEnabled( true );
		actionSaveAs->setEnabled( true );
		actionEditDocInfo->setEnabled( true );

		// diable new and open file
		actionNew->setEnabled( true );
		actionOpen->setEnabled( true );
		actionUndo->setEnabled( false );
		actionRedo->setEnabled( false );
		// emit /*sigHasDoc*/( true );
		emit sigEnableActions( true );
// 	} else {
// 		actionClose->setEnabled( false );
// 		actionSave->setEnabled( false );
// 		actionSaveAs->setEnabled( false );
// 		actionEditDocInfo->setEnabled( false );
// 		actionUndo->setEnabled( false );
// 		actionRedo->setEnabled( false );
// 
// 		// enable new and open file
// 		actionNew->setEnabled( true );
// 		actionOpen->setEnabled( true );
// // 		emit sigHasDoc( false );
// 		emit sigEnableActions( false );
// 	}
}

// // bool KMyFirewall::hasOpenDoc() {
// // 	return KMFAppState::hasOpenDoc();
// // }

bool KMyFirewall::isTemplate() {
	if ( ( network()->currentDoc()->url().fileName().endsWith( "tkmfrs" ) || network()->currentDoc()->url().fileName().endsWith( "tkmfgrs" ) ) ) {
		return true;
	}
	return false;
}

}

#include "kmyfirewall.moc"
