/*
** SellaNMS
** $Id: statement.cxx,v 1.9 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: statement.cxx,v 1.9 2005/12/01 05:57:59 sella Exp $";

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

/*
	The default constructor.
*/
Statement::Statement() {
	this->type = "unknown";
	this->name = "unknown";

#if 0
	statementDebugging = 0;
#endif
}

Statement::Statement(Statement const &src) {
	/* Utilize operator=(). */
	*this = src;
}

Statement const& Statement::operator=(Statement const &src) {
	Term	*term;

	/* Clear destination Statement. */
	this->clear();

	/* Copy type and name. */
	this->type = src.type;
	this->name = src.name;

	/* Allocate new terms and copy. */
	for (slist<Term *>::const_iterator t = src.terms.begin(); t != src.terms.end(); ++t) {
		term = src.getNewStatementTerm();
		*term = **t;

		this->terms.insert(this->terms.end(), term);
	}

	return *this;
}

/*
	The default destructor.
*/
Statement::~Statement() {
	/* NOTE: Could also call this->clear() here. */
	for (slist<Term *>::iterator term = this->terms.begin(); term != this->terms.end(); ++term) {
		SAFE_DELETE(*term);
	}
	this->terms.clear();
}

/*
	Get a new instance of a term for this statement type.

	Return Values
		A new instance of a term (allocated via the new operator) for this statement type.
*/
Term *Statement::getNewStatementTerm() const {
	LMSG("Statement::getNewStatementTerm() - Returned NULL");
	return NULL;
}

/*
	Evaluate all terms of this statement.

	Parameters
		input:	the variables to evaluate for this statement; will hold any return values for this evaluation.

	Return Values
		ACTION_NEXT_INPUT:		the caller should call this function with their next input.
		ACTION_NEXT_STATEMENT:	the caller should call this function on the next statement with the same input.
*/
ACTION Statement::evaluate(variable_binding_t &input) {
	for (slist<Term *>::iterator term = this->terms.begin(); term != this->terms.end(); ++term) {
		switch ((*term)->evaluate(input)) {
			case ACTION_NEXT_INPUT:
				return ACTION_NEXT_INPUT;

			case ACTION_NEXT_STATEMENT:
				return ACTION_NEXT_STATEMENT;

			case ACTION_ACCEPT:
				return ACTION_ACCEPT;

			case ACTION_REJECT:
				return ACTION_REJECT;

			case ACTION_FAILURE:
				return ACTION_FAILURE;
		}
	}
	
	return ACTION_NEXT_STATEMENT;
}

/*
	Compile all terms of this statement.

	Parameters
		config:	the section of the configuration from the level "policy-options <statement-type> <statement-name>"

	Return Values
		SUCCESS:	if the policy-statement was successfully compiled.
		FAILURE: if the policy-statement failed to compile.
*/
RESULT Statement::compile(ConfigNode *config) {
	RESULT result = SUCCESS;
	
	Term						*term;
	ConfigNode				term_config;
	vector<string>			term_names;
	string					applied_format;

	if (config->assignValues("term", term_names)) {
		for (vector<string>::iterator term_name = term_names.begin(); term_name != term_names.end(); ++term_name) {
			if (config->assignNode("term " + *term_name, term_config)) {
				term = this->getNewStatementTerm();

				if (term != NULL) {
					term->setName(*term_name);
					term->setStorage(this->storage);
					term->compile(&term_config);

					this->appendTerm(term);
				} else {
					LMSG("Policy: getNewStatementTerm returned NULL.");

					result = FAILURE;
				}
			} else {
				result = FAILURE;
			}
		}
	}
	return result;
}

/*
	Print all information from this statement.
	
	Return Values
		SUCCESS:	if the statement was successfully printed.
		FAILURE: if the statement failed to print.
*/
RESULT Statement::print(unsigned long depth) {
	RESULT result = SUCCESS;

	string	tab = "";
	for (unsigned long i = 0; i < depth; i++) {
		tab.append("   ");
	}

	LMSG("%s%s %s {", tab.c_str(), this->type.c_str(), this->name.c_str());
	for (slist<Term *>::iterator term = this->terms.begin(); term != this->terms.end(); ++term) {
		(*term)->print(depth + 1);
	}
	LMSG("%s}", tab.c_str());
	
	return result;
}
  
/*
	Clear all information from this statement.
	
	Return Values
		SUCCESS:	if the statement was successfully cleared.
		FAILURE: if the statement failed to clear.
*/
RESULT Statement::clear() {
	RESULT result = SUCCESS;

	this->type.erase();
	this->name.erase();

	for (slist<Term *>::iterator term = this->terms.begin(); term != this->terms.end(); ++term) {
		SAFE_DELETE(*term);
	}
	this->terms.clear();

	return result;
}

/*
	Set the type of this statement.

	Parameters
		type:		the new type of this statement.

	Return Values
		SUCCESS:	if the statement type was successfully changed to <type>.
		FAILURE: if the statement type failed to change to <type>.
*/
RESULT Statement::setType(const string &type) {
	RESULT result = SUCCESS;

	this->type = type;

	if (this->type.compare(type) != 0) {
		result = FAILURE;
	}
	return result;
}

/*
	Set the name of this statement.

	Parameters
		name:		the new name of this statement.

	Return Values
		SUCCESS:	if the statement name was successfully changed to <name>.
		FAILURE: if the statement name failed to change to <name>.
*/
RESULT Statement::setName(const string &name) {
	RESULT result = SUCCESS;

	this->name = name;

#if 0
	if (this->name.compare(this->debugStatement) == 0) {
		LMSG("DEBUG: debugging %s %s.", this->type.c_str(), this->name.c_str());

		statementDebugging = 1;
	}
#endif

	if (this->name.compare(name) != 0) {
		result = FAILURE;
	}
	return result;
}

/*
	Get the name of this statement.

	Return Values
		Returns the value of this->name.
*/
string Statement::getName() {
	return this->name;
}

/*
	Append a term to this statement.

	Parameters
		term:		the term to append to this statement.

	Return Values
		SUCCESS:	if the term was successfully appended.
		FAILURE: if the term failed to append.
*/
RESULT Statement::appendTerm(Term *term) {
	RESULT result = SUCCESS;

	this->terms.insert(this->terms.end(), term);

	return result;
}

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