//
// $Id: AbsEntity.cpp,v 1.22 2007/02/19 13:12:16 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2002-2007, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//

#include "AbsEntity.h"

//****************************************************************************************//
//								AbsEntity Class											  //	
//****************************************************************************************//
AbsEntity::AbsEntity(string name, string value, OvalEnum::Datatype datatype, bool isObjectEntity, OvalEnum::Operation operation, AbsVariable* varRef, OvalEnum::Check varCheck, bool nil) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a compelete AbsEntity object
	//
	// -----------------------------------------------------------------------

	this->SetName(name);
	this->SetValue(value);
	this->SetDatatype(datatype);
	this->SetIsObjectEntity(isObjectEntity);
	this->SetOperation(operation);
	this->SetVarCheck(varCheck);
	this->SetVarRef(NULL);
	this->SetNil(nil);
}

AbsEntity::~AbsEntity() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------
}

// ***************************************************************************************	//
//								 Public members												//
// ***************************************************************************************	//

string AbsEntity::GetName() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the name field's value
	//
	// -----------------------------------------------------------------------

	return this->name;
}

void AbsEntity::SetName(string name) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the name field's value
	//
	// -----------------------------------------------------------------------

	this->name = name;
}

string AbsEntity::GetValue() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the value field's value
	//
	// -----------------------------------------------------------------------

	return this->value;
}

void AbsEntity::SetValue(string value) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the value field's value
	//
	// -----------------------------------------------------------------------

	this->value = value;
}

OvalEnum::Datatype AbsEntity::GetDatatype() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the datatype field's value
	//
	// -----------------------------------------------------------------------

	return this->datatype;
}

void AbsEntity::SetDatatype(OvalEnum::Datatype datatype) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the datatype field's value
	//
	// -----------------------------------------------------------------------

	this->datatype = datatype;
}

bool AbsEntity::GetIsObjectEntity() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the isObjectEntity field's value
	//
	// -----------------------------------------------------------------------

	return this->isObjectEntity;
}

void AbsEntity::SetIsObjectEntity(bool isObjectEntity) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the isObjectEntity field's value
	//
	// -----------------------------------------------------------------------

	this->isObjectEntity = isObjectEntity;
}


OvalEnum::Check AbsEntity::GetVarCheck() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the varCheck field's value
	//
	// -----------------------------------------------------------------------

	return this->varCheck;
}

void AbsEntity::SetVarCheck(OvalEnum::Check varCheck) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the varCheck field's value
	//
	// -----------------------------------------------------------------------

	this->varCheck = varCheck;
}

bool AbsEntity::GetNil() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the nil field's value
	//
	// -----------------------------------------------------------------------

	return this->nil;
}

void AbsEntity::SetNil(bool nil) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the nil field's value
	//
	// -----------------------------------------------------------------------

	this->nil = nil;
}

OvalEnum::Operation AbsEntity::GetOperation() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the operation field's value
	// -----------------------------------------------------------------------

	return this->operation;
}

void AbsEntity::SetOperation(OvalEnum::Operation operation) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the operation field's value
	// -----------------------------------------------------------------------

	this->operation = operation;
}

AbsVariable* AbsEntity::GetVarRef() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the varRef field's value
	// -----------------------------------------------------------------------

	return this->varRef;
}

void AbsEntity::SetVarRef(AbsVariable* varRef) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the varRef field's value
	// -----------------------------------------------------------------------

	this->varRef = varRef;
}

VariableValueVector* AbsEntity::GetVariableValues() {

	VariableValueVector* varValues = new VariableValueVector();

	if(this->GetVarRef() != NULL) {
		AbsVariable* varRef = this->GetVarRef();

		// get the values of the variable
		VariableValueVector* values = varRef->GetValues();
		VariableValueVector::iterator varValueIt;
		for(varValueIt = values->begin(); varValueIt != values->end(); varValueIt ++) {
			varValues->push_back((*varValueIt));
		}
		// TODO - do i need this delete call here
		//delete values;
		//values = NULL;

		// get any variable values that were used for determinihng the value of this variable
		values = varRef->GetVariableValues();
		for(varValueIt = values->begin(); varValueIt != values->end(); varValueIt ++) {
			varValues->push_back((*varValueIt));
		}
		// TODO - do i need this delete call here
		//delete values;
		//values = NULL;
	}

	return varValues;
}

OvalEnum::ResultEnumeration AbsEntity::Analyze(ItemEntity* scElement) {

	OvalEnum::ResultEnumeration result = OvalEnum::ERROR_RESULT;
	try {

		// check the status on the sc element
		if(scElement->GetStatus() == OvalEnum::ERROR_STATUS) {
			return OvalEnum::ERROR_RESULT;
		} else if(scElement->GetStatus() == OvalEnum::NOT_COLLECTED_STATUS) {
			return OvalEnum::ERROR_RESULT;
		} else if(scElement->GetStatus() == OvalEnum::DOES_NOT_EXIST_STATUS) {
			return OvalEnum::FALSE_RESULT;
		}

		// based on data type call the appropriate comparison method
		if(this->GetVarRef() == NULL) {

			if(this->GetDatatype() == OvalEnum::BINARY_TYPE) {
				result = EntityComparator::CompareBinary(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::BOOLEAN_TYPE) {
				result = EntityComparator::CompareBoolean(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::EVR_STRING_TYPE) {
				result = EntityComparator::CompareEvrString(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::FLOAT_TYPE) {
				result = EntityComparator::CompareFloat(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::INTEGER_TYPE) {
				result = EntityComparator::CompareInteger(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::IOS_VERSION_TYPE) {
				result = EntityComparator::CompareIosVersion(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::STRING_TYPE) {
				result = EntityComparator::CompareString(this->GetOperation(), this->GetValue(), scElement->GetValue());
			} else if(this->GetDatatype() == OvalEnum::VERSION_TYPE) {
				result = EntityComparator::CompareVersion(this->GetOperation(), this->GetValue(), scElement->GetValue());
			}

		} else {

			// loop over each variable value
			IntVector results;
			// check the flag on the variable
			if(this->GetVarRef()->GetFlag() == OvalEnum::COMPLETE_FLAG) { 
				VariableValueVector* values = this->GetVarRef()->GetValues();
				VariableValueVector::iterator iterator;
				for(iterator = values->begin(); iterator != values->end(); iterator++) {
					OvalEnum::ResultEnumeration tmp = OvalEnum::ERROR_RESULT;
					if(this->GetDatatype() == OvalEnum::BINARY_TYPE) {
						tmp = EntityComparator::CompareBinary(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::BOOLEAN_TYPE) {
						tmp = EntityComparator::CompareBoolean(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::EVR_STRING_TYPE) {
						tmp = EntityComparator::CompareEvrString(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::FLOAT_TYPE) {
						tmp = EntityComparator::CompareFloat(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::INTEGER_TYPE) {
						tmp = EntityComparator::CompareInteger(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::IOS_VERSION_TYPE) {
						tmp = EntityComparator::CompareIosVersion(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::STRING_TYPE) {
						tmp = EntityComparator::CompareString(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					} else if(this->GetDatatype() == OvalEnum::VERSION_TYPE) {
						tmp = EntityComparator::CompareVersion(this->GetOperation(), (*iterator)->GetValue(), scElement->GetValue());
					}

					results.push_back(tmp);
				}
				result = OvalEnum::CombineResultsByCheck(&results, this->GetVarCheck());
			} else {
				
				result = OvalEnum::ERROR_RESULT;
			}
		}

	} catch (Exception ex) {
		result = OvalEnum::ERROR_RESULT;
		Log::Debug("An error occured while Analyzing an entity. " + ex.GetErrorMessage());
	} catch (...) {
		result = OvalEnum::ERROR_RESULT;
		Log::Debug("An unexpected error occured while Analyzing an entity.");
	}

	return result;
}

//****************************************************************************************//
//							AbsEntityException Class									  //	
//****************************************************************************************//
AbsEntityException::AbsEntityException(string errMsgIn, int severity, Exception* ex) : Exception(errMsgIn, severity, ex) {

}

AbsEntityException::~AbsEntityException() {

}

