//
// $Id: AbsObjectCollector.cpp,v 1.11 2006/10/27 17:28:59 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2006, 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 "AbsObjectCollector.h"

//****************************************************************************************//
//							AbsObjectCollector Class									  //	
//****************************************************************************************//
AbsObjectCollector* AbsObjectCollector::instance = NULL;

AbsObjectCollector::AbsObjectCollector() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	// -----------------------------------------------------------------------
	
}

AbsObjectCollector::~AbsObjectCollector() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Nothing for now
	// -----------------------------------------------------------------------
}

AbsObjectCollector* AbsObjectCollector::Instance() { 
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	return the protectee statc instance variable.
	// -----------------------------------------------------------------------	

	return AbsObjectCollector::instance;
}
// ***************************************************************************************	//
//								Public members												//
// ***************************************************************************************	//
CollectedObject* AbsObjectCollector::Run(string objectId) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a collected object for the specified object id.
	//	Check the cache of all collected objects to make sure the specified
	//	object has not already been processed. 
	//	This interpreter will never create a collected object based on an
	//	object other than a set object that is flagged as incomplete.
	// -----------------------------------------------------------------------
	
	CollectedObject* collectedObject = CollectedObject::GetCollectedObject(objectId);

	// Check to make sure this object has not already been collected.
	if(collectedObject == NULL) {

		//Log::Debug("AbsObjectCollector::Run processing object id: " + objectId);				

		// Parse this object
		AbsObject* absObject = NULL;
		try {
			absObject = ObjectFactory::GetObjectById(objectId);
		} catch (VariableFactoryException ex) {
			collectedObject = CollectedObject::CreateError(objectId);
			collectedObject->SetFlag(ex.GetVariable()->GetFlag());
			
			// add all the messages reported wtih the AbsVariable
			StringVector::iterator iterator;
			for(iterator = ex.GetVariable()->GetMessages()->begin(); iterator != ex.GetVariable()->GetMessages()->end(); iterator++) {
				collectedObject->AppendOvalMessage(new OvalMessage((*iterator)));
			}
			
		} catch(Exception ex) {
			Log::Info("AbsObjectCollector::Run() - Error while parsing object: " + objectId + " " + ex.GetErrorMessage());
			collectedObject = CollectedObject::CreateError(objectId);
			collectedObject->AppendOvalMessage(new OvalMessage("AbsObjectCollector::Run() - Error while parsing object: " + objectId + " " + ex.GetErrorMessage()));
		} catch(...) {
			Log::Info("AbsObjectCollector::Run() - Error while parsing object: " + objectId + " Unkown error.");
			collectedObject = CollectedObject::CreateError(objectId);
			collectedObject->AppendOvalMessage(new OvalMessage("AbsObjectCollector::Run() - Error while parsing object: " + objectId + " Unkown error."));
		}

		if(collectedObject == NULL) {
	
			try {

				// Process the object
				collectedObject = this->Process(absObject);

			} catch(Exception ex) {
				if(collectedObject == NULL) 
					collectedObject = CollectedObject::CreateError(objectId);

				collectedObject->AppendOvalMessage(new OvalMessage(ex.GetErrorMessage(), OvalEnum::FATAL_LEVEL));
				collectedObject->SetFlag(OvalEnum::ERROR_FLAG);
				if(absObject != NULL) {
					delete absObject;
					absObject = NULL;
				}
				Log::Debug("Error while collecting data for object: " + collectedObject->GetId() + " " + ex.GetErrorMessage());
			} catch(...) {
				if(collectedObject == NULL) 
					collectedObject = CollectedObject::CreateError(objectId);

				collectedObject->AppendOvalMessage(new OvalMessage("An unknown error occured while collecting data." , OvalEnum::FATAL_LEVEL));
				if(absObject != NULL) {
					delete absObject;
					absObject = NULL;
				}
				Log::Debug("An unknown error occured while collecting data for object: " + collectedObject->GetId());
			} 				
		}
	}

	return collectedObject;
}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
ItemVector* AbsObjectCollector::ApplyFilters(ItemVector* items, AbsStateVector* filters) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	For Each Filter provided Loop through all the Items in the current set
	//	of items. Only add items to the result set of items if they do NOT 
	//	match all filters
	//
	// -----------------------------------------------------------------------

	ItemVector* tmpItems = new ItemVector();
	this->CopyItems(tmpItems, items);

	// loop through all filters
	AbsStateVector::iterator filterIterator;
	for(filterIterator = filters->begin(); filterIterator != filters->end(); filterIterator++) {
		Filter* filter = (Filter*)(*filterIterator);
		ItemVector* results = new ItemVector();

		// Now loop through all the Items. Add Matching Items to result Vector
		ItemVector::iterator itemIterator;
		for(itemIterator = tmpItems->begin(); itemIterator != tmpItems->end(); itemIterator++) {
			Item* item = (*itemIterator);
			if(!filter->Analyze(item)) {
				results->push_back(item);
			}
		}
		// reset the tmpItems vector
		delete tmpItems;
		tmpItems = NULL;
		tmpItems = results;
	}

	return tmpItems;
}

void AbsObjectCollector::CopyItems(ItemVector* dest, ItemVector* src) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Copy all items in the src vector to the dest vector
	//
	// -----------------------------------------------------------------------
	
	ItemVector::iterator iterator;
	for(iterator = src->begin(); iterator != src->end(); iterator++) {
		dest->push_back((*iterator));
	}
}	

bool AbsObjectCollector::ExistsInSet(ItemVector* itemSet, Item* item) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a true if the specified item exists in the specified set
	//	Comparing items based on their ids assumes that Item ids are only
	//	assigned to unique items. This is ensured when probes return Items.
	// -----------------------------------------------------------------------
	bool exists = false;
	
	ItemVector::iterator iterator;
	for(iterator = itemSet->begin(); iterator != itemSet->end(); iterator++) {
		if(item->GetId() == (*iterator)->GetId()) {
			exists = true;
			break;
		}
	}	

	return exists;
}
CollectedSet* AbsObjectCollector::Union(CollectedSet* collectedSet1, CollectedSet* collectedSet2) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a single set that contains all unique items in both sets
	// -----------------------------------------------------------------------
	
	ItemVector* resultItems = new ItemVector();

	ItemVector* itemSet1 = collectedSet1->GetItems();
	ItemVector* itemSet2 = collectedSet2->GetItems();

	ItemVector::iterator iterator;
	for(iterator = itemSet1->begin(); iterator != itemSet1->end(); iterator++) {
		if(!this->ExistsInSet(resultItems, (*iterator))) {
			resultItems->push_back((*iterator));
		}
	}

	for(iterator = itemSet2->begin(); iterator != itemSet2->end(); iterator++) {
		if(!this->ExistsInSet(resultItems, (*iterator))) {
			resultItems->push_back((*iterator));
		}
	}
	
	CollectedSet* result = new CollectedSet();
	result->SetItems(resultItems);

	return result;
}

CollectedSet* AbsObjectCollector::Intersection(CollectedSet* collectedSet1, CollectedSet* collectedSet2) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a set of items that exist only in one of the specified sets
	// -----------------------------------------------------------------------
	ItemVector* resultItems = new ItemVector();

	ItemVector* itemSet1 = collectedSet1->GetItems();
	ItemVector* itemSet2 = collectedSet2->GetItems();

	ItemVector::iterator iterator;
	for(iterator = itemSet1->begin(); iterator != itemSet1->end(); iterator++) {
		if(!this->ExistsInSet(itemSet2, (*iterator))) {
			resultItems->push_back((*iterator));
		}
	}

	for(iterator = itemSet2->begin(); iterator != itemSet2->end(); iterator++) {
		if(!this->ExistsInSet(itemSet1, (*iterator))) {
			resultItems->push_back((*iterator));
		}
	}

	CollectedSet* result = new CollectedSet();
	result->SetItems(resultItems);

	return result;
}

CollectedSet* AbsObjectCollector::Compelement(CollectedSet* collectedSet1, CollectedSet* collectedSet2) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a set of unique items in set 1 but not in set 2, a relative 
	//	complement.
	// -----------------------------------------------------------------------
	ItemVector* resultItems = new ItemVector();

	ItemVector* itemSet1 = collectedSet1->GetItems();
	ItemVector* itemSet2 = collectedSet2->GetItems();

	ItemVector::iterator iterator;
	for(iterator = itemSet1->begin(); iterator != itemSet1->end(); iterator++) {
		if(!this->ExistsInSet(itemSet2, (*iterator))) {
			resultItems->push_back((*iterator));
		}
	}

	CollectedSet* result = new CollectedSet();
	result->SetItems(resultItems);

	return result;
}

CollectedObject* AbsObjectCollector::Process(AbsObject* absObject) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
   	//	Based on the type of object call the appropriate process method.
	// -----------------------------------------------------------------------

	CollectedObject* collectedObject = NULL;
	if(typeid(*absObject) == typeid(Object)) {
		collectedObject = this->ProcessObject((Object*)absObject);
	} else {
		collectedObject = this->ProcessSetObject((SetObject*)absObject);
	}

	return collectedObject;
}

CollectedObject* AbsObjectCollector::ProcessSetObject(SetObject* setObject) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	 - Copy the variable values from the specified object.
	//	 - Make call to process set to start the recursive processing of the set.
	//	 - Set the references based on the results of processing the set 
	//	 - Set the flag based on the results of processing the set
	//	 - Copy the variable values used to create the collected set
	// -----------------------------------------------------------------------

	
	CollectedSet* collectedSet = this->ProcessSet(setObject->GetSet());
	CollectedObject* collectedObject = CollectedObject::Create(setObject);	
	collectedObject->SetReferences(collectedSet->GetItems());
	collectedObject->SetFlag(collectedSet->GetFlag());
	collectedObject->AppendVariableValues(collectedSet->GetVariableValues());

	return collectedObject;
}

CollectedSet* AbsObjectCollector::ProcessSet(Set* set) {
	// -----------------------------------------------------------------------
	//	Abstract
	//	
	//	Either recursivley process each child set or Process each object 
	//	reference.
	//	
	// -----------------------------------------------------------------------

	CollectedSet* collectedSet1 = NULL;
	CollectedSet* collectedSet2 = NULL;

	if(!set->GetIsSimpleSet()) {		

		// make recursive call for each child set.
		if(set->GetSetOne() != NULL) {
			collectedSet1 = this->ProcessSet(set->GetSetOne());
		}

		if(set->GetSetTwo() != NULL) {
			collectedSet2 = this->ProcessSet(set->GetSetTwo());
		}

	} else {

		collectedSet1 = new CollectedSet();
		collectedSet2 = new CollectedSet();

		// Collect each referenced object using any supplied filters
		if(set->GetReferenceOne() != NULL) {
			CollectedObject* refOneCollectedObj = this->Run(set->GetReferenceOne()->GetId());
			ItemVector* itemSet1 = refOneCollectedObj->GetReferences();
			itemSet1 = this->ApplyFilters(itemSet1, set->GetFilters());
			VariableValueVector* set1Vars = refOneCollectedObj->GetVariableValues();
			collectedSet1->AppendVariableValues(set1Vars);
			collectedSet1->SetFlag(refOneCollectedObj->GetFlag());
			collectedSet1->SetItems(itemSet1);
		}

		if(set->GetReferenceTwo() != NULL) {
			CollectedObject* refTwoCollectedObj = this->Run(set->GetReferenceTwo()->GetId());
			ItemVector* itemSet2 = refTwoCollectedObj->GetReferences();
			itemSet2 = this->ApplyFilters(itemSet2, set->GetFilters());
			VariableValueVector* set2Vars = refTwoCollectedObj->GetVariableValues();
			collectedSet2->AppendVariableValues(set2Vars);
			collectedSet2->SetFlag(refTwoCollectedObj->GetFlag());
			collectedSet2->SetItems(itemSet2);
		}
	}

	// combine all sets by operator
	CollectedSet* combinedCollectedSet = NULL;
	if(set->GetReferenceTwo() != NULL) {
		if(set->GetSetOperator() == OvalEnum::UNION_SET_OPERATOR) {
			combinedCollectedSet = this->Union(collectedSet1, collectedSet2);
		} else if(set->GetSetOperator() == OvalEnum::COMPLEMENT_SET_OPERATOR) {
			combinedCollectedSet = this->Compelement(collectedSet1, collectedSet2);
		} else if(set->GetSetOperator() == OvalEnum::INTERSECTION_SET_OPERATOR) {
			combinedCollectedSet = this->Intersection(collectedSet1, collectedSet2);
		}

		// determine flag value
		OvalEnum::Flag resultFlag = this->CombineFlagBySetOperator(set->GetSetOperator(), collectedSet1->GetFlag(), collectedSet2->GetFlag());
		combinedCollectedSet->SetFlag(resultFlag);

		// maintain variable values used.
		combinedCollectedSet->AppendVariableValues(collectedSet1->GetVariableValues());
		combinedCollectedSet->AppendVariableValues(collectedSet2->GetVariableValues());

	} else {
		combinedCollectedSet = collectedSet1;
	}

	return combinedCollectedSet;
}

CollectedObject* AbsObjectCollector::ProcessObject(Object* object) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	 - make sure the object is supported and applicable
	//	 - copy any variable values from the object
	//	 - Get the probe for the object
	//	 - Run the probe with the object
	//	 - Set the matching collected items for the collected object
	//	 - Set the flag value for the collected object.
	// -----------------------------------------------------------------------

	CollectedObject* collectedObject = NULL;

	// Handle objects that are not applicable 
	if(this->IsApplicable(object) == false) {
		collectedObject = CollectedObject::CreateNotApplicable(object);
		collectedObject->SetVariableValues(object->GetVariableValues());
	} else {

		// handle objects that are not supported
		if(this->IsSupported(object) == false) {
			collectedObject = CollectedObject::CreateNotSupported(object);
			collectedObject->SetVariableValues(object->GetVariableValues());
		} else {

			

			ItemVector* items = NULL;
			AbsProbe* probe = this->GetProbe(object);
			if(probe != NULL) {
				items = probe->Run(object);

				// only create collected object if the pribe succeeds
				collectedObject = CollectedObject::Create(object);
				collectedObject->AppendVariableValues(object->GetVariableValues());
				collectedObject->AppendReferences(items);
			} else {
				throw AbsObjectCollectorException("Error: Unable to locate a probe for the specified object.", ERROR_FATAL);
			}

			// set the flag corerctly
			if(collectedObject->GetReferences()->size() == 0) {
				collectedObject->SetFlag(OvalEnum::DOES_NOT_EXIST_FLAG);
			} else {
				collectedObject->SetFlag(OvalEnum::COMPLETE_FLAG);
			}
		}
	}

	return collectedObject;
}

OvalEnum::Flag AbsObjectCollector::CombineFlagBySetOperator(OvalEnum::SetOperator setOp, OvalEnum::Flag set1Flag, OvalEnum::Flag set2Flag) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Combine the 
	// -----------------------------------------------------------------------

	OvalEnum::Flag result = OvalEnum::ERROR_FLAG;

	if(setOp == OvalEnum::COMPLEMENT_SET_OPERATOR) {

		if(set1Flag == OvalEnum::ERROR_FLAG) {
			
			result = OvalEnum::ERROR_FLAG;

		} else if(set1Flag == OvalEnum::COMPLETE_FLAG) {

			if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG || set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				// i differ here i think this is error drew thinks this is incomplete
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				// i differ here i think this is error drew thinks this is not collected
				result = OvalEnum::ERROR_FLAG;
			}

		} else if(set1Flag == OvalEnum::INCOMPLETE_FLAG) {

			if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG || set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				// i differ here i think this is error drew thinks this is not collected
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				// i differ here i think this is error drew thinks this is incomplete
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			}

		} else if(set1Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {

			if(set2Flag != OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;	
			} else {
				result = OvalEnum::ERROR_FLAG;
			}

		} else if(set1Flag == OvalEnum::NOT_COLLECTED_FLAG) {
			
			if(set2Flag != OvalEnum::NOT_APPLICABLE_FLAG && set2Flag != OvalEnum::ERROR_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;	
			} else {
				result = OvalEnum::ERROR_FLAG;
			}

		} else if(set1Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
			result = OvalEnum::ERROR_FLAG;
		}

	} else if(setOp == OvalEnum::INTERSECTION_SET_OPERATOR) {

		if(set1Flag == OvalEnum::ERROR_FLAG) {
			result = OvalEnum::ERROR_FLAG;
		} else if(set1Flag == OvalEnum::COMPLETE_FLAG) {

			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;
			}

		} else if(set1Flag == OvalEnum::INCOMPLETE_FLAG) {
			
			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			} else if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::NOT_APPLICABLE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG || set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			}

		} else if(set1Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
			result = OvalEnum::DOES_NOT_EXIST_FLAG;
		} else if(set1Flag == OvalEnum::NOT_COLLECTED_FLAG) {
			
			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::INCOMPLETE_FLAG || set2Flag == OvalEnum::NOT_APPLICABLE_FLAG || set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;
			}

		} else if(set1Flag == OvalEnum::NOT_APPLICABLE_FLAG) {

			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::NOT_APPLICABLE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;
			}
		}

	} else if(setOp == OvalEnum::UNION_SET_OPERATOR) {
		
		if(set1Flag == OvalEnum::ERROR_FLAG) {

			result = OvalEnum::ERROR_FLAG;

		} else if(set1Flag == OvalEnum::COMPLETE_FLAG) {

			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;	
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG || set2Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG || set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			}

		} else if(set1Flag == OvalEnum::INCOMPLETE_FLAG) {
			
			if(set2Flag != OvalEnum::ERROR_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;	
			} else {
				result = OvalEnum::ERROR_FLAG;
			}

		} else if(set1Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
			
			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;	
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG || set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG || set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			}

		} else if(set1Flag == OvalEnum::NOT_COLLECTED_FLAG) {
			
			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;	
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG || set2Flag == OvalEnum::INCOMPLETE_FLAG || set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG || set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;
			}

		} else if(set1Flag == OvalEnum::NOT_APPLICABLE_FLAG) {

			if(set2Flag == OvalEnum::ERROR_FLAG) {
				result = OvalEnum::ERROR_FLAG;	
			} else if(set2Flag == OvalEnum::COMPLETE_FLAG) {
				result = OvalEnum::COMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::INCOMPLETE_FLAG) {
				result = OvalEnum::INCOMPLETE_FLAG;
			} else if(set2Flag == OvalEnum::NOT_APPLICABLE_FLAG) {
				result = OvalEnum::NOT_APPLICABLE_FLAG;
			} else if(set2Flag == OvalEnum::DOES_NOT_EXIST_FLAG) {
				result = OvalEnum::DOES_NOT_EXIST_FLAG;
			} else if(set2Flag == OvalEnum::NOT_COLLECTED_FLAG) {
				result = OvalEnum::NOT_COLLECTED_FLAG;
			}

		}

	}

	return result;
}

//****************************************************************************************//
//						AbsObjectCollectorException Class								  //	
//****************************************************************************************//
AbsObjectCollectorException::AbsObjectCollectorException(string errMsgIn, int severity, Exception* ex) : Exception(errMsgIn, severity, ex) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

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

}
