/***************************************************************************
begin                : Mon Feb 4 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 "iptruleoption.h"
// KDE
#include <kdebug.h>
#include <klocale.h>


// QT
#include <tqdom.h>

// PROJECT
#include "kmfdoc.h"
#include "kmfiptdoc.h"
#include "iptchain.h"
#include "iptable.h"
#include "xmlnames.h"

namespace KMF {

//############# Initialise static members
TQDict<TQStringList>* IPTRuleOption::m_dict_option_strings = new TQDict<TQStringList>;
TQDict<TQStringList>* IPTRuleOption::m_dict_gui_strings = new TQDict<TQStringList>;
TQDict<TQString>* IPTRuleOption::m_dict_option_names = new TQDict<TQString>;
TQPtrList<TQString>* IPTRuleOption::m_known_types = new TQPtrList<TQString>;
bool IPTRuleOption::m_created_dict = false;

IPTRuleOption::IPTRuleOption( IPTRule* rule, const char* name  ) : NetfilterObject( rule, name ) {
	if ( rule == 0 ) {
		kdDebug() << "ERROR: IPTRuleOption rule == 0" << endl;
		return;
	}
	
	// 		kdDebug() << "IPTRuleOption::IPTRuleOption(..): Creating new IPTRuleOption" << endl;
	// m_object_type = NetfilterObject::RULEOPTION;
	m_rule = rule;
	m_option_type = XML::Undefined_Value;
	m_target_option = false;
	m_dict_option_strings->setAutoDelete( true );
	m_known_types->setAutoDelete( true );
	for ( int i = 0; i < MAXOPTNUM;i++ )
		m_values[ i ] = XML::Undefined_Value;

	if ( ! m_created_dict ) {
		// Initialise Dict on first use
		m_rule->chain()->table()->kmfDoc()->registerRuleOptions();
		m_created_dict = true;
	}

	
}

IPTRuleOption::~IPTRuleOption() {}

int IPTRuleOption::type() {
// 	kdDebug() << "IPTRuleOption::type()" << endl;
	return NetfilterObject::RULEOPTION;
}

void IPTRuleOption::clear() {
}

void IPTRuleOption::setOptionType( const TQString& type ) {
	if ( type.isNull() ) {
		return;
	}
	m_option_type = type;
}

const TQString& IPTRuleOption::guiName() const {
	return *m_dict_option_names->find( m_option_type );
}

void IPTRuleOption::setTargetOption( bool is_tg_opt ) {
	m_target_option = is_tg_opt;
}

void IPTRuleOption::reset() {
	for ( int i = 0; i < MAXOPTNUM;i++ )
		m_values[ i ] = XML::BoolOff_Value;
	changed();
}

bool IPTRuleOption::isEmpty() {
	for ( int i = 0; i < MAXOPTNUM ;i++ ) {
		// 		kdDebug() << "Curr opt: " << m_values[ i ] << endl;
		if ( ! m_values[ i ].isEmpty() && m_values[ i ] != XML::Undefined_Value && m_values[ i ] != XML::BoolOff_Value && m_values[ i ] != " " ) {
			// 			kdDebug() << "Curr opt: " << getOptionType() << " is not empty found Value: "<< m_values[ i ]  << endl;
			return false;
		}
	}
	// 	kdDebug() << "Curr opt: " << getOptionType() << " is empty!" << endl;
	return true;
}

void IPTRuleOption::loadXML( const TQDomDocument& doc, TQStringList& errors ) {
	kdDebug() << "void IPTRuleOption::loadXML( const TQDomDocument& )" << endl;
 	TQDomElement root = doc.documentElement();
 	loadXML( root, errors );
}
void IPTRuleOption::loadXML( TQDomNode root, TQStringList& errors ) {
	NetfilterObject::loadUuid( root, errors );

	TQString new_opt_type = root.toElement().attribute( XML::Type_Attribute );
	if ( m_option_type == XML::BoolOff_Value ) {
		m_option_type = new_opt_type;
	}
	if ( m_option_type == new_opt_type )
		kdDebug() << "Found Option Type: " << m_option_type << endl;

	TQString tmp = root.toElement().attribute( XML::TargetOption_Attribute );
	if ( tmp == XML::Yes_Value ) 
		setTargetOption( true );
	else
		setTargetOption( false );

	TQDomNode curr = root.firstChild();
	while ( !curr.isNull() ) {
		if ( curr.isElement() ) {
			if ( curr.nodeName() == XML::RuleOptionValue_Element ) {
				for ( int i = 0; i < MAXOPTNUM;i++ ) {
					TQDomText textChild = curr.firstChild().toText();
					TQString attrib = TQString( "value%1" ).arg( i );
					TQString val = curr.toElement().attribute( attrib );

					if ( !val.isEmpty() && val != XML::Undefined_Value ) {
						m_values[ i ] = val;
						//            kdDebug() << "Found Option Value: " << m_values[i] << endl;
					}
				}
			}
		}
		curr = curr.nextSibling();
	}
	changed();
}

void IPTRuleOption::loadValues( TQStringList args ) {
	for ( uint i = 0; i < MAXOPTNUM; i++ )
		m_values[ i ] = XML::BoolOff_Value;

	int i = 0;
	for ( TQStringList::Iterator it = args.begin(); it != args.end(); ++it ) {
		m_values[ i ] = *it;
		kdDebug() << "+ Inserted Option Argument Nr: " << i << " value: " << m_values[ i ] << endl;
		i++;
	}
	changed();
}

const TQStringList& IPTRuleOption::getValues() {
	// 	kdDebug() << "const TQStringList& IPTRuleOption::getValues()" << endl;
	TQStringList vals;
	for ( uint i = 0; i < MAXOPTNUM; i++ ) {
		TQString val = m_values[ i ];
		// 		kdDebug() << "Append Value: "  <<  val << endl;
		vals << val;
	}
	return *( new TQStringList( vals ) );
}


const TQDomDocument& IPTRuleOption::getDOMTree() {
	// 	kdDebug() << "const TQString& IPTRuleOption::getDOMTree( )" << endl;
	TQDomDocument doc;
	if ( isEmpty() )
		return * ( new TQDomDocument( doc ) );

	bool found = false;
	for ( uint i = 0; i < MAXOPTNUM; i++ )
		if ( !m_values[ i ].isEmpty() && m_values[ i ] != XML::Undefined_Value )
			found = true;
	if ( true ) {
		TQDomElement root = doc.createElement( XML::RuleOption_Element );
		NetfilterObject::saveUuid( root );
		root.setAttribute( XML::Type_Attribute, m_option_type );
		if ( m_target_option ) {
			root.setAttribute( XML::TargetOption_Attribute, XML::Yes_Value );
		} else {
			root.setAttribute( XML::TargetOption_Attribute, XML::No_Value );
		}

		doc.appendChild( root );
		for ( uint i = 0; i < MAXOPTNUM; i++ ) {
			TQString val = m_values[ i ];
			if ( !val.isEmpty() && val != XML::Undefined_Value ) {
				TQDomElement tag = doc.createElement( XML::RuleOptionValue_Element );
				tag.setTagName( XML::RuleOptionValue_Element );
				//			kdDebug() << "Writing Attribute: value" << i << " val: " << val << endl;
				TQString attrib = TQString( "value%1" ).arg( i );
				tag.setAttribute( attrib, val );
				root.appendChild( tag );
			}
		}
	}
	// 	kdDebug() << "XML:\n " << doc.toString() << endl;
	return *( new TQDomDocument( doc ) );
}


const TQString& IPTRuleOption::toString() {
	// 	kdDebug() << "const TQString& IPTRuleOption::toString()" << endl;

	TQStringList * commandStrings;
	commandStrings = m_dict_option_strings->find( m_option_type );
	TQString s = "";
	TQTextStream str( &s, IO_WriteOnly );
	TQString ws = " ";
	// 	kdDebug() << "Option: " << m_option_type << " defined " << used << endl;
	if ( ! isEmpty() && commandStrings && ! commandStrings->isEmpty() ) {
		// 		str << *commandStrings->at( 0 );
		str << ws;
		// 		bool was_modifier = false;
		for ( uint i = 0; i < commandStrings->count(); i++ ) {
			TQString command = *commandStrings->at( i );
			TQString val = m_values[ i ];
			TQStringList* guiStrings = m_dict_gui_strings->find( m_option_type );
			TQString guiName = *guiStrings->at( i );

			if (! val.isNull() &&
			        ! val.isEmpty() &&
			        val != XML::Undefined_Value &&
			        val != XML::BoolOff_Value ) {
				if ( val == XML::BoolOn_Value ) {
					val = "";
				}
//				kdDebug() << "Create option Name: " << guiName << endl;
//				kdDebug() << "Create option string: " << command <<  " " << val << endl;
				str << command;
				str << ws;
				str << val;
				str << ws;
			}
		}
	}
	// 	kdDebug() << "Returning String: " << s << endl;

	return *( new TQString( s.simplifyWhiteSpace() ) );
}

//############ static members ####################//
TQDict<TQStringList>* IPTRuleOption::getOptionStringDict() {
	return m_dict_option_strings;
}

TQDict<TQStringList>* IPTRuleOption::getGUIStringDict() {
	return m_dict_gui_strings;
}

TQPtrList<TQString>* IPTRuleOption::getAvailableOptionTypes() {
	return m_known_types;
}

void IPTRuleOption::readRuleOptionDefinition( const TQDomDocument& doc ) {
	TQDomElement root = doc.documentElement();
	TQDomNode curr = root.firstChild();
	bool inOption = false;
	TQString name = "";
	TQString guiName = "";
	TQStringList *vals = 0;
	TQStringList *gui = 0;
	while ( !curr.isNull() ) {
		//		kdDebug() << "IPTRuleOption: Parsing Node: " << curr.nodeName() << endl;
		if ( curr.isElement() && curr.nodeName() == "ruleoptiondefinition" ) {
			name = curr.toElement().attribute(  XML::Name_Attribute );
			guiName = curr.toElement().attribute( XML::GUIName_Attribute );
			//	version = root.toElement().attribute( XML::Version_Attribute );
			vals = new TQStringList();
			gui = new TQStringList();
			kdDebug() << "+ Register Rule Option: " << name << " " <<  guiName << endl;
			inOption = true;
			readRuleOptionDefinitionNode( curr, vals, gui );
			m_dict_option_strings->insert( name, vals );
			m_dict_gui_strings->insert( name, gui );
			m_dict_option_names->insert( name, new TQString( guiName ) );
			m_known_types->append( ( new TQString( name ) ) );

			kdDebug() << "+ Testing Key: " << name << endl;
			TQStringList* list;
			list = m_dict_option_strings->find( name );
			if ( list ) {
				for ( uint i = 0; i < list->count(); i ++ ) {
					TQString s = *list->at( i );
					kdDebug() << "---+ Found Option String:  " << s << endl;
					s = "";
				}
			} else {
				kdDebug() << "!!!!Couldn't fetch TQStringList with key: " << name << endl;
			}
		}
		curr = curr.nextSibling();
	}
}


void IPTRuleOption::readRuleOptionDefinitionNode( const TQDomNode& currNode, TQStringList* vals, TQStringList* gui ) {
	TQDomNode curr = currNode;
	curr = curr.firstChild();
	while ( !curr.isNull() ) {
		kdDebug() << "IPTRuleOption: Parsing Node: " << curr.nodeName() << endl;
		if ( curr.isElement() && curr.nodeName() == "option" ) {
			TQString cmd = curr.toElement().attribute( "command" );
			TQString guiName = curr.toElement().attribute( XML::GUIName_Attribute );

			cmd.simplifyWhiteSpace();
			vals->append( cmd );
			kdDebug() << "---+ Registering Option String:  " << cmd << endl;

			guiName.simplifyWhiteSpace();
			gui->append( guiName );
			kdDebug() << "---+ Registering GUI String:  " << guiName << endl;

		}
		curr = curr.nextSibling();
	}
}

}
