/*
** SellaNMS
** $Id: format_statement_from_variable.cxx,v 1.8 2005/12/01 05:57:59 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static const char rcsid[] = "$Id: format_statement_from_variable.cxx,v 1.8 2005/12/01 05:57:59 sella Exp $";

#include "format_statement_from_variable.h"
#include <stdio.h>
#include <stl/vector>

/*
	The default constructor.
*/
FormatStatementFromVariable::FormatStatementFromVariable():required(false), type(0), function(0) {
	name = "unknown";
}

/*
	The default destructor.
*/
FormatStatementFromVariable::~FormatStatementFromVariable() {
}

string FormatStatementFromVariable::getName() {
	return this->name;
}

ACTION FormatStatementFromVariable::evaluate(variable_binding_t &input) {
	return 0;
}

/*
	Compile this variable.
	
	Parameters
		config:		the part of the configuration from the level "policy-options format-statement <format> term <term> from variable <variable>"

	Return Values
		SUCCESS:	if the variable was successfully compiled.
		FAILURE:	if the variable was unable to be compiled.
*/
RESULT FormatStatementFromVariable::compile(ConfigNode *config) {
	RESULT result = SUCCESS;

	ConfigNode		suffix_config;
	ConfigNode		dependency_config;

	string			value;
	vector<string>	values;

	Dependency		dependency;
	Suffix			suffix;

	if (config->assignValue("required", value)) {
		if (value.compare("yes") == 0) {
			this->required = true;
		} else if (value.compare("no") == 0) {
			this->required = false;
		} else {
			LMSG("Policy: invalid value (%s) for format-statement variable setting 'required'.", value.c_str()); 

			result = FAILURE;
		}
	} else {
		this->required = DEFAULT_REQUIRED;
	}

	if (config->assignValues("type", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			if (this->addType(*v) != SUCCESS) {
				LMSG("Policy: failed to add type %s.", v->c_str());

				result = FAILURE;
			}
		}
	} else {
		this->type = DEFAULT_TYPE;
	}

	if (config->assignValues("function", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			if (this->addFunction(*v) != SUCCESS) {
				LMSG("Policy: failed to add function %s.", v->c_str());

				result = FAILURE;
			}
		}
	} else {
		this->function = DEFAULT_FUNCTION;
	}

	if (config->assignValues("value", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			if (this->addValue(*v) != SUCCESS) {
				LMSG("Policy: failed to add value %s.", v->c_str());

				result = FAILURE;
			}
		}
	} else {
		this->values.clear();
	}

	if (config->assignValues("apply-map", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			if (this->addMapStatement(*v) != SUCCESS) {
				LMSG("Policy: failed to add map-statement %s.", v->c_str());

				result = FAILURE;
			}
		}
	} else {
		this->mapStatements.clear();
	}

	if (config->assignValues("suffix-modifier", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			suffix.setName(*v);
			if (config->assignNode("suffix-modifier " + *v, suffix_config)) {
				if (suffix.compile(&suffix_config) == SUCCESS) {
					if (this->addSuffix(suffix) != SUCCESS) {
						LMSG("Policy: failed to add suffix %s.", v->c_str());

						result = FAILURE;
					}
				} else {
					LMSG("Policy: failed to compile suffix %s.", v->c_str());

					result = FAILURE;
				}
			}
		}
	} else {
		this->suffixes.clear();
	}

	if (config->assignValues("dependency", values)) {
		for (vector<string>::iterator v = values.begin(); v != values.end(); ++v) {
			dependency.setName(*v);
			if (config->assignNode("dependency " + *v, dependency_config)) {
				if (dependency.compile(&dependency_config) == SUCCESS) {
					if (this->addDependency(dependency) != SUCCESS) {
						LMSG("Policy: failed to add dependency %s.", v->c_str());

						result = FAILURE;
					}
				} else {
					LMSG("Policy: failed to compile dependency %s.", v->c_str());

					result = FAILURE;
				}
			}
		}
	} else {
		this->dependencies.clear();
	}	
	return result;
}

RESULT FormatStatementFromVariable::compileInherited(ConfigNode *config, bool required, unsigned long type, unsigned long function, slist<string> &mapStatements) {
	RESULT result = this->compile(config);

	if (!config->isNode("required")) {
		this->required = required;
	}
	if (!config->isNode("type")) {
		this->type = type;
	}
	if (!config->isNode("function")) {
		this->function = function;
	}
	if (!config->isNode("apply-map")) {
		this->mapStatements = mapStatements;
	}
	return result;
}

RESULT FormatStatementFromVariable::getAppliedMapStatements(slist<string> &map_names) {
	for (slist<string>::iterator m = this->mapStatements.begin(); m != this->mapStatements.end(); ++m) {
		map_names.push_front(*m);
	}
	return SUCCESS;
}

/*
	Set the name of this variable.

	Parameters
		name:		the name to set for this variable.

	Return Values
		SUCCESS:	if the name of the variable was successfully set.
		FAILURE:	if the name of the variable was unable to be set.
*/
RESULT FormatStatementFromVariable::setName(string &name) {
	this->name = name;

	return SUCCESS;
}

/*
	Add an accepted value for this variable.

	Parameters
		value:		the accepted value to add to this variable.

	Return Values
		SUCCESS:	if the new value of the variable was successfully added.
		FAILURE:	if the new value of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addValue(string &value) {
	this->values[value] = true;

	return SUCCESS;
}

/*
	Add a type for this variable.

	Parameters
		type:		the type to be added to this variable.

	Return Values
		SUCCESS:	if the new type of the variable was successfully added.
		FAILURE:	if the new type of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addType(string &type) {
	RESULT result = SUCCESS;

	if (type.compare("string") == 0) {
		this->type |= TYPE_STR;
	} else if (type.compare("regex") == 0) {
		this->type |= TYPE_REG;
	} else if (type.compare("integer") == 0) {
		this->type |= TYPE_INT;
	} else if (type.compare("date") == 0) {
		this->type |= TYPE_DTE;
	} else if (type.compare("time") == 0) {
		this->type |= TYPE_TME;
	} else if (type.compare("day") == 0) {
		this->type |= TYPE_DAY;
	} else if (type.compare("prefix") == 0) {
		this->type |= TYPE_PFX;
	} else {
		LMSG("Policy: unknown type (%s) specified for format-statement variable.", type.c_str());

		result = FAILURE;
	}
	return result;
}

/*
	Add a function to use for evaluation of this variable.

	Parameters
		function:	the function to be added to this variable.

	Return Values
		SUCCESS:	if the new evaluation function of the variable was successfully added.
		FAILURE:	if the new evaluation function of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addFunction(string &function) {
	RESULT result = SUCCESS;

	if (function.compare("equal-to") == 0) {
		this->function |= FUNCTION_EQ;
	} else if (function.compare("not-equal") == 0) {
		this->function |= FUNCTION_NE;
	} else if (function.compare("less-than") == 0) {
		this->function |= FUNCTION_LT;
	} else if (function.compare("at-most") == 0) {
		this->function |= FUNCTION_LE;
	} else if (function.compare("at-least") == 0) {
		this->function |= FUNCTION_GE;
	} else if (function.compare("more-than") == 0) {
		this->function |= FUNCTION_GT;
	} else {
		LMSG("Policy: unknown function (%s) specified for format-statement variable.", function.c_str());
		abort();

		result = FAILURE;
	}
	return result;
}

/*
	Add a map-statement to evaluate before performing any functions on this variable.

	Parameters
		map_name:	the name of the map-statement to add.
	
	Return Values
		SUCCESS:	if the new map-statement of the variable was successfully added.
		FAILURE:	if the new map-statement of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addMapStatement(string &map_name) {
	this->mapStatements.insert(this->mapStatements.end(), map_name);
	
	return SUCCESS;
}

/*
	Add a valid suffix which can be used on this variable.

	Parameters
		suffix:	the suffix to add.
	
	Return Values
		SUCCESS:	if the new suffix of the variable was successfully added.
		FAILURE:	if the new suffix of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addSuffix(Suffix &suffix) {
	this->suffixes[suffix.getName()] = suffix;
	
	return SUCCESS;
}

/*
	Add a dependency for this variable.

	Parameters
		dependency:	the dependency to add.
	
	Return Values
		SUCCESS:	if the new dependency of the variable was successfully added.
		FAILURE:	if the new dependency of the variable was unable to be added.
*/
RESULT FormatStatementFromVariable::addDependency(Dependency &dependency) {
	this->dependencies[dependency.getName()] = dependency;
	
	return SUCCESS;
}

RESULT FormatStatementFromVariable::setVariableType(unsigned long &type, string &variable) {
	RESULT result = FAILURE;

	if (this->name.compare(variable) == 0) {
		/* Return types for this variable. */
		type = this->type;
		
		result = SUCCESS;
	}
	return result;
}

RESULT FormatStatementFromVariable::setVariableFunction(unsigned long &function, string &variable) {
	RESULT result = FAILURE;

	if (this->name.compare(variable) == 0) {
		/* Return functions for this variable. */
		function = this->function;
		
		result = SUCCESS;
	}
	return result;
}

/* ADDED */
RESULT FormatStatementFromVariable::setVariableMap(slist<string> &mapStatements, string &variable) {
	RESULT result = FAILURE;

	if (this->name.compare(variable) == 0) {
		/* Return applied map statements for this variable. */
		mapStatements = this->mapStatements;
		
		result = SUCCESS;
	}
	return result;
}

/*
	Print the information about this variable.
	
	Return Values
		SUCCESS:	if the variable was successfully printed.
		FAILURE:	if the variable was unable to be printed.
*/
RESULT FormatStatementFromVariable::print(unsigned long depth) {
	string	tab = "", str;
	for (unsigned long i = 0; i < depth; i++) {
		tab.append("   ");
	}

	LMSG("%svariable %s {", tab.c_str(), this->name.c_str());
	LMSG("%s   required     %s;", tab.c_str(), this->required ? "yes" : "no");
	LMSG("%s   type         0x%x;", tab.c_str(), this->type);
	LMSG("%s   function     0x%x;", tab.c_str(), this->function);
	LMSG("");
	
	if (!this->values.empty()) {
		str.erase();
		for (hash_map<string, bool>::iterator value = this->values.begin(); value != this->values.end(); ++value) {
			str.append(" " + value->first);
		}
		LMSG("%s   valid-values [%s ];", tab.c_str(), str.c_str());
	}
	if (!this->mapStatements.empty()) {
		str.erase();
		LMSG("");
		for (slist<string>::iterator mapStatement = this->mapStatements.begin(); mapStatement != this->mapStatements.end(); ++mapStatement) {
			str.append(" " + *mapStatement);
		}
		LMSG("%s   apply-map [%s ];", tab.c_str(), str.c_str());
	}
	if (!this->suffixes.empty()) {
		LMSG("");
		for (hash_map<string, Suffix>::iterator suffix = this->suffixes.begin(); suffix != this->suffixes.end(); ++suffix) {
			suffix->second.print(depth + 1);
		}
	}
	if (!this->dependencies.empty()) {
		LMSG("");
		for (hash_map<string, Dependency>::iterator dep = this->dependencies.begin(); dep != this->dependencies.end(); ++dep) {
			dep->second.print(depth + 1);
		}
	}
	LMSG("%s}", tab.c_str());

	return SUCCESS;
}

/*
	Clear the information about this variable.
	
	Return Values
		SUCCESS:	if the variable was successfully cleared.
		FAILURE:	if the variable was unable to be cleared.
*/
RESULT FormatStatementFromVariable::clear() {
	this->required = DEFAULT_REQUIRED;
	this->type = 0;
	this->function = 0;
	this->name = "unknown";
	this->values.clear();
	this->mapStatements.clear();
	this->dependencies.clear();
	this->suffixes.clear();

	return SUCCESS;
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3 sts=3
*/
