//
// $Id: SimpleTestAnalyzer.cpp,v 1.27 2005/08/11 13:33:44 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, 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 "SimpleTestAnalyzer.h"

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

SimpleTestAnalyzer::SimpleTestAnalyzer() : Analyzer()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	
	// -----------------------------------------------------------------------

}

SimpleTestAnalyzer::~SimpleTestAnalyzer()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//
	// -----------------------------------------------------------------------
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

Analyzer* SimpleTestAnalyzer::Instance()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Force this class to be a singleton. Return an Instance of the 
	//	DefiitionAnalyzer
	//
	// -----------------------------------------------------------------------

	if(instance == NULL)
		instance = new SimpleTestAnalyzer();

	return instance;
}


Result SimpleTestAnalyzer::Run(DOMElement *test)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compute a result for the specified test in an oval definition. Ensure
	//	that the test and its results are added to the result document. 
	//		0- If already processed return existing result
	//		1- Write the test to the results document.
	//		2- Get the test id
	//		3- The check attribute value
	//		4- Get the test name
	//		5- Map the test name to an iten name and container in the sc file
	//		6- Search the sc file for matching objects
	//		7- Loop over matching items
	//			-a Get a result for each match
	//			-b Add each item's object with result to the result file
	//			-c Store the result for each item
	//		8- Combine item results based on check attribute
	//		9- Write combined result to test in results file
	//		10- Return the combined result
	// -----------------------------------------------------------------------

	Result testResult = unknown_result;

	// Get the test id
	currentTestId = XmlCommon::GetAttributeByName(test, "id");

	// Check if the test has already been processed.
	if(!Processed(currentTestId)) {

		iVector objectResults;

		// Get the check attribute
		string check = XmlCommon::GetAttributeByName(test, "check");

		// Add the test to the result doc	
		this->resultTest = this->resultWriter->AddTest((DOMElement*)test);

		// Must catch all exceptions here to ensure that some sort of
		// result is added to the test or invalid xml will be generated
		try {

			// Get a reference to the definition's object section
			DOMNode *definitionObject = XmlCommon::FindNodeNS(test, "object");

			// Get a reference to the definition's data section
			DOMNode *definitionData = XmlCommon::FindNodeNS(test, "data");
			
			// Get the test name
			string testName = XmlCommon::GetElementName(test);

			// Get the matching itmes in the sc file
			ElementVector items = GetMatchingItemNodes(testName, (DOMElement*)definitionObject);

			// Check to make sure that some items were found
			if(items.size() == 0) {

				this->resultWriter->AddTestMsg(this->resultTest, "Unable to locate matching item in the system characteristics file. An unknown result will be generated for this test.");

			} else {
				// Loop through all the items
				ElementVector::iterator item;
				for (item=items.begin(); item!=items.end(); item++) {
					DOMElement *itemElm = (DOMElement*)(*item);
					
					Result objectResult = unknown_result;

					// Get the item id
					string itemId = XmlCommon::GetAttributeByName(itemElm, "id");

					// Get a reference to the item's object section
					DOMElement *itemObj = XmlCommon::FindNode(itemElm, "object");
					
					// If the item has an object section 
					if(itemObj != NULL) {

						// Get the status of the object
						string itemObjectStatus = XmlCommon::GetAttributeByName(itemObj, "status");

						// Only analyze the data if the object existed on the system
						if(itemObjectStatus.compare("exists") == 0 || itemObjectStatus.compare("") == 0) {

							// Get a reference to the item's data section
							DOMNode *itemData = XmlCommon::FindNode(itemElm, "data");
							
							//	Analyze the item's data
							objectResult = AnalyzeItem((DOMElement*)definitionData, (DOMElement*)itemData);

						} else if(itemObjectStatus.compare("does not exist") == 0) {
							
							// Must handle a simple check for existance of an item on a system
							if(check.compare("none exist") == 0) {
								objectResult = true_result;
							} else {
								objectResult = false_result;
							}

						// Either error status or not collected.
						} else {
							objectResult = unknown_result;
						}

						// Copy the object section to the result document
						this->resultWriter->AddTestedObject(this->resultTest, (DOMElement*)itemObj, ResultToString(objectResult), itemId);
						
					// No object section in the item in the sc file
					} else {

						// Check if the definition has an object section
						if(definitionObject == NULL) {

							// Get a reference to the item's data section
							DOMNode *itemData = XmlCommon::FindNode(itemElm, "data");
							
							//	Analyze the item's data
							objectResult = AnalyzeItem((DOMElement*)definitionData, (DOMElement*)itemData);

							// Copy the object section to the result document
							this->resultWriter->AddTestedObject(this->resultTest, NULL, ResultToString(objectResult), itemId);

						// The test in the definition has an object section
						// It should not have matched an item in the data file with out
						// an object section
						} else {
							throw AnalyzerException("Error: Found an item in the data file with no object section and the test specifies an object section.\n");					
						}
					}
					
					// Add the result to the vector of results			 
					objectResults.push_back(objectResult);	
				} // end loop over items
			} // items.size() != 0

			//	Compute the combined result
			testResult = CombineResultsByCheck(&objectResults, check);

		} catch(Exception ex) {
			testResult = unknown_result;
			resultWriter->AddTestMsg(this->resultTest, "Error: While analyzing: " + currentTestId + " " + ex.GetErrorMessage());
			Log::WriteLog("Error: While analyzing: " + currentTestId + " " + ex.GetErrorMessage());

		} catch(...) {
			testResult = unknown_result;
			resultWriter->AddTestMsg(this->resultTest, "Error: An unknown error occured while analyzing: " + currentTestId);
			Log::WriteLog("Error: An unknown error occured while analyzing: " + currentTestId);
		}

		// Set the result for the test in the result document
		resultWriter->SetResult(this->resultTest, ResultToString(testResult));

		// Store the test id and result
		Store(currentTestId, testResult);

	} else {
		testResult = this->GetTestResult(currentTestId);
	}

	// reset the resultTest ptr to be safe
	this->resultTest = NULL;

	return testResult;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

Result SimpleTestAnalyzer::AnalyzeItem(DOMElement *definitionData, DOMElement *itemData)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the two data sections provided. Use the data type and operator
	//	from the definition data elements while doing the comparison. Get the
	//	operator value from the deffinition data element and use is to combine 
	//	the result values for each element in the data section.
	// -----------------------------------------------------------------------

	// If the definition does not specify a data element then return a true result
	if(definitionData == NULL) {
		return true_result;
	}

	// Get the operator attribute value from thje definition element
	string defDataOperator = XmlCommon::GetAttributeByName(definitionData, "operator");
	if(defDataOperator.compare("") == 0) {
		defDataOperator = "AND";
	}

	// Loop through all the children of the data element
	// get the matching children in the item's data element
	// and call the appropriate DataComparison method. Store the
	// result of each call in a vector of results. 
	iVector results;
	Result childResult = unknown_result;

	// Loop through all child items		
	DOMNode *defChild = NULL;
	for (defChild = definitionData->getFirstChild(); defChild != NULL; defChild=defChild->getNextSibling()) {
		if(defChild->getNodeType() == DOMNode::ELEMENT_NODE) {
			DOMElement *defChildElm = (DOMElement*)defChild;

			// Get the name of the def data element child
			string defDataElmChildName = XmlCommon::GetElementName(defChildElm);

			// Get all the matching nodes in the item's data section
			DOMNodeList *matchingDataItmesList = itemData->getElementsByTagName(XMLString::transcode(defDataElmChildName.c_str()));
			unsigned int childIndex = 0;

			// While looping if no matches are found use default result of unknown
			// 
			// if a true is found -- true
			// if no trues are found -- false
			iVector childResults;
			Result tmpResult = unknown_result;
			while(childIndex < matchingDataItmesList->getLength()) {
				DOMNode *dataChild = matchingDataItmesList->item(childIndex++);
				//	Only process ELEMENT_NODES
				if(dataChild->getNodeType() == DOMNode::ELEMENT_NODE) {
					DOMElement *dataChildElm = (DOMElement*)dataChild;
					tmpResult = CompareData(defChildElm, dataChildElm);
					childResults.push_back(tmpResult);
				}
			}

			// Combine the results. Note taht if there are no results in the vector
			// the result is set to unknown_result
			childResult = CombineResultsByOperation(&childResults, "OR");

			results.push_back(childResult);
		}
	}

	//	Compute the combined result
	Result combinedResult = CombineResultsByOperation(&results, defDataOperator);

	return combinedResult;
}

string SimpleTestAnalyzer::CombineComponents(DOMElement *parent)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Combine the componets under the provided parent node into one 
	//	literal string.
	//
	//	NOTE: This function assumes that the only types of a component are:
	//		- literal - for all platforms
	//		- environment_variable - for windows only
	//		- registry_value - for windows only
	//	If new component types are added this code must be changed.
	//	If new platforms are added this code must be changed
	// -----------------------------------------------------------------------

	// Validate taht the specified element is of xsi type 
	const DOMTypeInfo* objTypeInfo = parent->getTypeInfo();
	string xsiType = XmlCommon::ToString(objTypeInfo->getName());
	if(xsiType.compare("componentType") != 0) 
		throw AnalyzerException("Error: CombineComponents() only compares elements with an xsi type of componentType. Found: " + xsiType);			

	string combinedComponents = "";

	for (DOMNode *tmpNode = parent->getFirstChild(); tmpNode != NULL; tmpNode=tmpNode->getNextSibling()) {
		if(tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
			DOMElement *component = (DOMElement*)tmpNode;
			// Get the type attribute of the component
			string typeAttr = XmlCommon::GetAttributeByName(component, "type");

			// Get the value of the component
			string value = XmlCommon::GetDataNodeValue(component); 

			// Based on type convert the value of component to a literal
			#ifdef WIN32

				if(typeAttr.compare("literal") == 0) {
					// simply combine the strings
					combinedComponents.append(value);

				} else if(typeAttr.compare("environment_variable") == 0) {

					// Get the value of the environment variable
					string envValue = "";
					try {

						envValue = GetEnvironmentVariableValue(value);

					} catch(Exception ex) {

						// Check if in Verbose mode
						if(Log::verboseMode) {
							cout << "NOTICE: while getting an environment variable component for test: " << currentTestId << " " << ex.GetErrorMessage() << endl;
							Log::WriteLog("NOTICE: while getting an environment variable component for test: " +  currentTestId + " " +  ex.GetErrorMessage() + "\n");
						}
						throw ex;
					}

					// Now combine the strings
					combinedComponents.append(envValue);

				} else if(typeAttr.compare("registry_value") == 0) {
					
					// Get the value of the registry key
					string regValue = "";
					try {

						regValue = GetRegistryKeyValue(value);

					} catch(Exception ex) {

						// Check if in Verbose mode
						if(Log::verboseMode) {
							cout << "NOTICE: while getting a registry component for test: " << currentTestId << " " << ex.GetErrorMessage() << endl;
							Log::WriteLog("NOTICE: while getting a registry component for test: " +  currentTestId + " " +  ex.GetErrorMessage() + "\n");
						}
						throw ex;
					}

					// Now combine the strings
					combinedComponents.append(regValue);
				} else {

					// Do I want to throw an exception? - no schem validation will handle this.
				}

			#endif
			
			#ifdef REDHAT
				if(typeAttr.compare("literal") == 0) {
					// simply combine the strings
					combinedComponents.append(value);
				} else {

					// Do I want to throw an exception? - no schema validation will handle this.
				}

			#endif

			#ifdef SOLARIS
				if(typeAttr.compare("literal") == 0) {
					// simply combine the strings
					combinedComponents.append(value);
				} else {

					// Do I want to throw an exception? - no schem validation will handle this.
				}
			#endif
		}
	}

	return combinedComponents;
}

Result SimpleTestAnalyzer::CompareBinaryData(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//
	//	Currently only support equals and not equal
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	//	Check to ensure only 1's and 0's in the string
	REGEX *myMatcher = new REGEX();
	if(!myMatcher->IsMatch("^[1|0]+$", dataValue.c_str()))
		throw AnalyzerException("Error: Non binary data found when data type indicated binary data."); 

	delete myMatcher;

	// Process accepted operators
	if(op.compare("equals") == 0 || op.compare("not equal") == 0)
	{
		result = CompareStringData(op, defValue, dataValue);

	}else
	{
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified for binary data: " + op);
	}

	return result;
}

Result SimpleTestAnalyzer::CompareBooleanData(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	//	Check to ensure only boolean data
	if(dataValue.compare("0") != 0 && dataValue.compare("1") != 0 && strnicmp(dataValue.c_str(), "true", 4) != 0 && strnicmp(dataValue.c_str(), "false", 4)) 
		throw AnalyzerException("Error: Non boolean data found when data type indicated boolean data."); 

	// Convert the values to the same format
	int iDataValue = 0;
	if(strnicmp(dataValue.c_str(), "true", 4) == 0 || dataValue.compare("1") == 0) {
		iDataValue = 1;
	}
	int iDefValue = 0;
	if(strnicmp(defValue.c_str(), "true", 4) == 0 || defValue.compare("1") == 0) {
		iDefValue = 1;
	}

	// Process accepted operators
	if(op.compare("equals") == 0) {
		if(iDataValue == iDefValue)
			result = true_result;
		else
			result = false_result;

	} else if(op.compare("not equal") == 0) {
		if(iDataValue != iDefValue)
			result = true_result;
		else
			result = false_result;

	} else {
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified for boolean data: " + op);
	}

	return result;
}

bool SimpleTestAnalyzer::CompareObjectValues(string objVal, string dataVal, string comparisonType)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Based on the specified comparison type return the result
	//	of comparing the object value and the data value.
	// -----------------------------------------------------------------------

	bool result = false;
	if(comparisonType.compare("literal") == 0 ) {
		if(objVal.compare(dataVal) == 0)
			result = true;

	} else {
		REGEX myRegex;
		result = myRegex.IsMatch(objVal.c_str(), dataVal.c_str());
	}

	return result;
}

Result SimpleTestAnalyzer::CompareData(DOMElement *ovalNode, DOMElement *dataNode)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the oval node to the data node using the operator specified 
	//	on the oval node. Preform the comparison by calling the correct datatype 
	//	specific comparison function. Handle existance tests. Note that with
	//	every comparison there is an implicit existance test except for when the
	//	specified operator is "does not exist"
	//
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	//	Get data node's status flag
	string dataStatus = XmlCommon::GetAttributeByName(dataNode, "status");
	if(dataStatus.compare("") == 0)
		dataStatus = "exists";

	//	Check that the data node existed
	if(dataStatus.compare("exists") != 0) {	

		result = unknown_result;
	
	} else {

		//	Get the operator on the oval node
		//	Default to equals
		string op = XmlCommon::GetAttributeByName(ovalNode, "operator");
		if(op.compare("") == 0)
			op = "equals";
			
		//	Get the data type on the oval node
		//	Defualt to string
		string datatype = XmlCommon::GetAttributeByName(ovalNode, "datatype");
		if(datatype.compare("") == 0)
			datatype = "string";
		
		// Get the element's xsi type
		const DOMTypeInfo* objTypeInfo = ((DOMElement*)ovalNode)->getTypeInfo();
		string xsiType = XmlCommon::ToString(objTypeInfo->getName());

		//	Call the correct data type specific comparison fuction to get the result
		if(xsiType.compare("subtestFileVersionType") == 0) {
			// debug 
			string ovalName = XmlCommon::GetElementName((DOMElement*)ovalNode);
			string dataName = XmlCommon::GetElementName((DOMElement*)dataNode);
			// end debug
			result = CompareVersionData(ovalNode, dataNode);
		
		} else {

			// debug 
			//string ovalName = XmlCommon::GetElementName((DOMElement*)ovalNode);
			//string dataName = XmlCommon::GetElementName((DOMElement*)dataNode);
			// end debug

			//	Get the value of the oval node
			string defValue = XmlCommon::GetDataNodeValue(ovalNode);

			//	Get the value of the data node
			string dataValue = XmlCommon::GetDataNodeValue(dataNode);

			//	Make call for remaining datatypes
			if(datatype.compare("binary") == 0)
				result = CompareBinaryData(op, defValue, dataValue);
			else if(datatype.compare("float") == 0)
				result = CompareFloatData(op, defValue, dataValue);
			else if(datatype.compare("int") == 0)
				result = CompareIntData(op, defValue, dataValue);
			else if(datatype.compare("string") == 0)
				result = CompareStringData(op, defValue, dataValue);
			else if(datatype.compare("boolean") == 0)
				result = CompareBooleanData(op, defValue, dataValue);
		}
	}

	return result;
}

Result SimpleTestAnalyzer::CompareFloatData(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Only handle comparisons that are logical for a float.
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	// convert the two strings to doubles
	double fltDefValue = atof(defValue.c_str());
	double fltDataValue = atof(dataValue.c_str());

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0 )
	{
		if(fltDefValue == fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("not equal") == 0 )
	{
		if(fltDefValue != fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than") == 0 )
	{
		if(fltDefValue < fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than") == 0 )
	{
		if(fltDefValue > fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than or equal") == 0 )
	{
		if(fltDefValue <= fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than or equal") == 0 )
	{
		if(fltDefValue >= fltDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("pattern match") == 0  || op.compare("bitwise and") == 0 ||
			 op.compare("bitwise or") == 0)
	{
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw AnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;
}

Result SimpleTestAnalyzer::CompareIntData(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Only handle compairisons that are logical for an int
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	// Convert the two strings to ints
	int intDefValue = atoi(defValue.c_str());
	int intDataValue = atoi(dataValue.c_str());

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0 )
	{
		if(intDefValue == intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("not equal") == 0 )
	{
		if(intDefValue != intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than") == 0 )
	{
		if(intDefValue < intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than") == 0 )
	{
		if(intDefValue > intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than or equal") == 0 )
	{
		if(intDefValue <= intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than or equal") == 0 )
	{
		if(intDefValue >= intDataValue)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("pattern match") == 0)
	{		
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified: " + op);	
		
	}else if(op.compare("bitwise and") == 0)
	{
		if((intDataValue & intDefValue) == intDefValue)
			result = true_result;
		else
			result = false_result;		
	
	}else if(op.compare("bitwise or") == 0)
	{
		if((intDataValue | intDefValue) == intDefValue)
			result = true_result;
		else
			result = false_result;	

	}else 
	{
		//	Unknown operator
		throw AnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;

}

bool SimpleTestAnalyzer::CompareObjectElements(DOMElement *definitionElm, DOMElement *dataObjectElm, string comparisonType, bool considerDataType)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return true if the two elements match. This function is recursive
	//	If an element has child elements those child elements are compared 
	//	to determine the overall result.
	// -----------------------------------------------------------------------

#ifdef _DEBUG
	string defElmName = XmlCommon::GetElementName(definitionElm);
#endif

	bool result = false;
	bool tmpResult = true;

	//	If the dataObjectElm is NULL the result is always false
	if(dataObjectElm == NULL)
		return false;

	// Get the type attribute of the definitionElm
	// default it to literal. Must also consider the comparisonType parameter.
	// If the comparisonType paramater is "pattern match" set the defElm Type
	// to pattern match. Otherwise get the type attribute of the element and
	// use that value as the defElmType
	string defElmType = "";
	if(comparisonType.compare("pattern match") == 0) {
		defElmType = "pattern match";
	} else {
		// get the value of the operator attribute
		defElmType = XmlCommon::GetAttributeByName(definitionElm, "operator");
		if(defElmType.compare("pattern match") != 0)
			defElmType = "literal";
	}

	//	check for child nodes of the definition node
	if(XmlCommon::HasChildElements(definitionElm)) {

		//	Loop through the child nodes
		DOMNodeList *definitionElmChildList = definitionElm->getChildNodes();
		unsigned int index = 0;
		while(index < definitionElmChildList->getLength())
		{
			DOMNode *child = definitionElmChildList->item(index++);

			//	Only process ELEMENT_NODES
			if(child->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement *definitionChild = (DOMElement*)child;

				//	Get the child node's name
				string myCurChildName = XmlCommon::GetElementName(definitionChild);

				//	Ignore the notes element
				if(myCurChildName.compare("notes") == 0)
					continue;

				//////////////////////////////////////////////////////////////////
				// Make recursive call
				// Originally I made the following call:
				// tmpResult = CompareObjectElements(definitionChild, (DOMElement*)XmlCommon::FindNode(dataElm, myCurChildName), defElmType);								
				// 
				// This call does not work if there are multiple elements in the object
				// section of a test with the same name. I have changed this to return the 
				// complete set of nodes with the same name as the current child. The next
				// step will be to loop through all the nodes in the set
				//		- make a recursive call
				//		- if any of them result in true from the recursive call stop
				//		  looping and set the result to true
				//		- if none of the items result in true stop looping and return false
				// 
				//////////////////////////////////////////////////////////////////
				bool childResult = false;
				DOMNodeList *dataChildList = dataObjectElm->getElementsByTagName(XMLString::transcode(myCurChildName.c_str()));
				unsigned int childIndex = 0;
				while(childIndex < dataChildList->getLength())
				{
					DOMNode *dataChild = dataChildList->item(childIndex++);
					//	Only process ELEMENT_NODES
					if(dataChild->getNodeType() == DOMNode::ELEMENT_NODE) {
						DOMElement *dataChildElm = (DOMElement*)dataChild;

						// make recursive call
						childResult = CompareObjectElements(definitionChild, dataChildElm, defElmType, considerDataType);	
						
						// Check result
						if(childResult) {
							break;
						}
					}
				}
				// Set the tmp result
				tmpResult = childResult;
				/* end new code */

				//	Stop looping if a false is found
				if(!tmpResult)
					break;
			}
		}

		result = tmpResult;
	//	No children, compute the result
	} else {	
		//	Call the compare function to get the result
		if(considerDataType) {
			//////////////////////////////////////////////////////////////////
			// Must check the datatype on the data element if the datatype is
			// pattern match. The result should always be false. This avoids 
			// attempting to match a regular expression in the definition
			// against a regular expression in the object section of a record
			// in the sc file.
			//////////////////////////////////////////////////////////////////
			string dataElmDataType = XmlCommon::GetAttributeByName(dataObjectElm, "datatype");
			if(dataElmDataType == "pattern match") {
				result = false;
			} else {
				result = CompareObjectValues(XmlCommon::GetDataNodeValue(definitionElm), XmlCommon::GetDataNodeValue(dataObjectElm), defElmType);		
			}
		} else {
			result = CompareObjectValues(XmlCommon::GetDataNodeValue(definitionElm), XmlCommon::GetDataNodeValue(dataObjectElm), "literal");		
		}
	}

	return result;
}

Result SimpleTestAnalyzer::CompareStringData(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Only handle compairisons that are logical for a string
	//
	// -----------------------------------------------------------------------
	
	//	Defualt to unknown result
	Result result = unknown_result;

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0)
	{
		if(defValue.compare(dataValue) == 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("not equal") == 0)
	{
		if(defValue.compare(dataValue) != 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than or equal") == 0)
	{
		if(defValue.compare(dataValue) >= 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than or equal") == 0)
	{
		if(defValue.compare(dataValue) <= 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("greater than") == 0)
	{
		if(defValue.compare(dataValue) > 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("less than") == 0)
	{
		if(defValue.compare(dataValue) < 0)
			result = true_result;
		else
			result = false_result;
	}else if(op.compare("pattern match") == 0)
	{
		REGEX *myMatcher = new REGEX();
		
		if(myMatcher->IsMatch(defValue.c_str(), dataValue.c_str()))
			result = true_result;
		else
			result = false_result;

		delete myMatcher;

	}else if(op.compare("bitwise and") == 0 || op.compare("bitwise or") == 0)
	{
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw AnalyzerException("Error: Unsupported operator specified: " + op);	
	}

	return result;
}

Result SimpleTestAnalyzer::CompareVersionData(DOMElement *ovalNode, DOMElement *dataNode)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	Result result = unknown_result;

	//	Ensure that the xsi type on the oval node is file_versionType
	// Get the element's xsi type
	const DOMTypeInfo* objTypeInfo = ((DOMElement*)ovalNode)->getTypeInfo();
	string xsiType = XmlCommon::ToString(objTypeInfo->getName());
	if(xsiType.compare("subtestFileVersionType") != 0) 
		throw AnalyzerException("Error: CompareVersion() only compares elements with an xsi type of subtestFileVersionType. Found: " + xsiType);		
	
	//	Get the operator from the oval node
	string op = XmlCommon::GetAttributeByName(ovalNode, "operator");
	if(op.compare("") == 0)
		op = "exists";

	//	Get the value of the major, minor, private, and built elements
	//	for both the oval node and the data node
	DOMElement *tmpVersionComponent = NULL;
	int ovalVersion[4];
	int dataVersion[4];

	//	Get the oval version componets
	tmpVersionComponent = XmlCommon::FindNode(ovalNode, "major");
	ovalVersion[0] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(ovalNode, "minor");
	ovalVersion[1] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(ovalNode, "build");
	ovalVersion[2] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(ovalNode, "private");
	ovalVersion[3] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	
	//	Get the data version componets
	tmpVersionComponent = XmlCommon::FindNode(dataNode, "major");
	dataVersion[0] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(dataNode, "minor");
	dataVersion[1] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(dataNode, "build");
	dataVersion[2] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = XmlCommon::FindNode(dataNode, "private");
	dataVersion[3] = atoi(XmlCommon::GetDataNodeValue(tmpVersionComponent).c_str());	

	
	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0)
	{
		if( ovalVersion[0] == dataVersion[0] && 
			ovalVersion[1] == dataVersion[1] &&
			ovalVersion[2] == dataVersion[2] &&
			ovalVersion[3] == dataVersion[3])
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("not equal") == 0)
	{
		if( ovalVersion[0] != dataVersion[0] || 
			ovalVersion[1] != dataVersion[1] ||
			ovalVersion[2] != dataVersion[2] ||
			ovalVersion[3] != dataVersion[3])
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("greater than or equal") == 0)
	{
		if( (ovalVersion[0] < dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] < dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] < dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] <= dataVersion[3]))
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("less than or equal") == 0)
	{
		if( (ovalVersion[0] > dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] > dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] > dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] >= dataVersion[3]))
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("greater than") == 0)
	{
		if( (ovalVersion[0] < dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] < dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] < dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] < dataVersion[3]))
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("less than") == 0)
	{
		if( (ovalVersion[0] > dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] > dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] > dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] > dataVersion[3]))
		{
			result = true_result;

		}else
			result = false_result;

	}else if(op.compare("bitwise and") == 0 || op.compare("bitwise or") == 0 || op.compare("pattern match") == 0)
	{
		//	Unsupported operator
		throw AnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw AnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;
}

#ifdef WIN32
	string SimpleTestAnalyzer::GetEnvironmentVariableValue(string env)
	{
		// -----------------------------------------------------------------------
		//	Abstract
		//
		//	Get the value of the specifed environment variable from the data file
		//	if the variable is not found report the error 
		// -----------------------------------------------------------------------


		string envValue = "";
		bool foundEnv = false;

		// Search the data document for the environment variable
		DOMNode *itemsNode = XmlCommon::FindNode(dataDoc, "environmentvariable_items");

		DOMNode *item = NULL;
		for (item = itemsNode->getFirstChild(); item != NULL; item=item->getNextSibling()) {
			if(item->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement* itemElm = (DOMElement*)(item);
			
				// Get the name element
				DOMElement *name = XmlCommon::FindNode(itemElm, "name");

				// Get the value of the name element
				string nameValue = XmlCommon::GetDataNodeValue(name);
				
				// If the name is a match get the value elements value
				// Record that a match was found.
				if(nameValue.compare(env) == 0) {
				
					// First check the status of the object element
					DOMElement *objectElement = XmlCommon::FindNode(itemElm, "object");
					string objStatus = XmlCommon::GetAttributeByName(objectElement, "status");

					// Only get the value if the object exists
					if(objStatus.compare("exists") == 0 || objStatus.compare("") == 0) {
						
						DOMElement *value = XmlCommon::FindNode(itemElm, "value");
						envValue = XmlCommon::GetDataNodeValue(value);

					} else if (objStatus.compare("does not exist") == 0) {
						
						throw AnalyzerException("The specified environment variable does not exist.", ERROR_NOTICE);

					} else {

						// Get the message for the item
						DOMElement *itemMsgNode = XmlCommon::FindNode(itemElm, "message");
						if(itemMsgNode != NULL) {
							string msg = XmlCommon::GetDataNodeValue(itemMsgNode);
							throw AnalyzerException("An error was reported on the specifed environment variable in the data file. The data file provided the following message: " + msg, ERROR_NOTICE);
						} else {
							throw AnalyzerException("An error was reported on the specifed environment variable in the data file.", ERROR_NOTICE);
						}	
					}

					foundEnv = true;
					break;
				}
			}
		}

		if(!foundEnv)
			throw AnalyzerException("Unable to locate the specified environment variable in the data file. env: " + env , ERROR_NOTICE);

		return envValue;
	}

	string SimpleTestAnalyzer::GetRegistryKeyValue(string regKey)
	{
		// -----------------------------------------------------------------------
		//	Abstract
		//
		//	Get the value of the specifed registry key from the data file
		//	if the value is not found report the error.
		// -----------------------------------------------------------------------

		string regValue = "";
		bool foundRegKey = false;

		// Search the data document for the key
		DOMNode *itemsNode = XmlCommon::FindNode(dataDoc, "registry_items");

		DOMNode *item = NULL;
		for (item = itemsNode->getFirstChild(); item != NULL; item=item->getNextSibling()) {
			if(item->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement* itemElm = (DOMElement*)(item);

				// Get the value of the hive element
				DOMElement *hive = XmlCommon::FindNode(itemElm, "hive");
				string hiveValue = XmlCommon::GetDataNodeValue(hive);

				// Get the value of the name element
				DOMElement *name = XmlCommon::FindNode(itemElm, "name");
				string nameValue = XmlCommon::GetDataNodeValue(name);

				// Get the value of the key element
				DOMElement *key = XmlCommon::FindNode(itemElm, "key");
				string keyValue = XmlCommon::GetDataNodeValue(key);

				// Concatentate the values
				string dataRegKey = hiveValue + "\\" + keyValue + "\\" + nameValue;

				// If the concatentate string is a match get the value elements value
				// Record that a match was found.
				if(dataRegKey.compare(regKey) == 0) {
				
					// First check the status of the object element
					DOMElement *objectElement = XmlCommon::FindNode(itemElm, "object");
					string objStatus = XmlCommon::GetAttributeByName(objectElement, "status");

					// Only get the value if the object exists
					if(objStatus.compare("exists") == 0 || objStatus.compare("") == 0) {
						
						DOMElement *value = XmlCommon::FindNode(itemElm, "value");
						regValue = XmlCommon::GetDataNodeValue(value);

					} else if (objStatus.compare("does not exist") == 0) {

						throw AnalyzerException("The specified registry key does not exist.", ERROR_NOTICE);						

					} else {

						// Get the message for the item
						DOMElement *itemMsgNode = XmlCommon::FindNode(itemElm, "message");
						if(itemMsgNode != NULL) {
							string msg = XmlCommon::GetDataNodeValue(itemMsgNode);
							throw AnalyzerException("An error was reported on the specifed registry key in the data file. The data file provided the following message: " + msg, ERROR_NOTICE);
						} else {
							
							throw AnalyzerException("An error was reported on the specifed registry key in the data file.", ERROR_NOTICE);
						}	
					}

					foundRegKey = true;
					break;
				}
			}
		}

		if(!foundRegKey)
			throw AnalyzerException("Unable to locate the specified registry key in the data file. key: " + regKey , ERROR_NOTICE);

		return regValue;
	}
#endif

ElementVector SimpleTestAnalyzer::GetMatchingItemNodes(string testName, DOMElement *definitionObject)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a NodeVector of the matching items in the data file
	//	for the sepecified object in the definition file.
	//
	// -----------------------------------------------------------------------

	// a flag to indicate if the object has an children that are pattern matches
	bool foundPatternMatch = false;

	// Get the name of the corresponding sc item and sc item container
	string scItemContainer = "";
	string scItemName = "";
	MapTestToItem(&scItemContainer, &scItemName, testName);

	// Create a vector to store the matching nodes in.
	ElementVector items;

	if(definitionObject != NULL) {

		//////////////////////////////////////////////////////////////////
		// Get the xsi type of the object's child elements.				//
		// If any of the child elements are of type component combine	//
		// all the components based on their type. Then replace the		//
		// child element with an element that has only a literal value. //
		//																//
		// Also, while looping over child nodes check for node with an	//
		// operator of pattern match.									//
		//////////////////////////////////////////////////////////////////
		for (DOMNode *tmpNode = definitionObject->getFirstChild(); tmpNode != NULL; tmpNode=tmpNode->getNextSibling()) {
			if(tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement *objectChild = (DOMElement*)tmpNode;

				// Get the operator attribute
				string objectChildOp = XmlCommon::GetAttributeByName(objectChild, "operator");
				if(objectChildOp.compare("pattern match") == 0)
					foundPatternMatch = true;

				// Get the xsi type as a string
				const DOMTypeInfo* objTypeInfo = objectChild->getTypeInfo();
				string xsiType = XmlCommon::ToString(objTypeInfo->getName());
				string componentLiteral = "";

				// If of type component get the nodes child elements 
				// and construct a literal string
				if(xsiType.compare("componentType") == 0) {
					componentLiteral = CombineComponents(objectChild);

					// Get the name of the element
					string elementName = XmlCommon::GetElementName(objectChild);

					// Create a new element to represent the combined values
					DOMElement *newObjChild = XmlCommon::CreateElement(ovalDoc, elementName, componentLiteral);

					// Add the operator attribute
					XmlCommon::AddAttribute(newObjChild, "operator", objectChildOp);

					// replace the object child element with the new element
					objectChild =  (DOMElement*)definitionObject->replaceChild(newObjChild, objectChild);
				}
			}
		}

		//////////////////////////////////////////////////////////////////
		// If thare are any pattern matches specified on elements in the//
		// object section first search the data file for the results of	//
		// the pattern match on the system. If the pattern is found  in	//
		// the data file and the status is exists search for matching	//
		// items in the sc file. Add each matching item to the vector of// 
		// items. If the pattern is found in the data file and the		//
		// status status is not "exists" add the item to the vector and	//
		// return. If the pattern match is not found in the data file	//
		// return an empty vector.										//
		// If no pattern matches are found simply search the data file	//
		// for matching items. Add them to the return vector.			//
		//////////////////////////////////////////////////////////////////
		
		if(foundPatternMatch) {

			// Attempt to locate an item in the sc file for the pattern as 
			// a literal
			 DOMElement *patternItem = GetLiteralItemMatch(definitionObject, scItemContainer, false);

			if(patternItem != NULL) {

				// Get the status of the item's object section
				DOMElement *objectElement = XmlCommon::FindNode(patternItem, "object");
				string objStatus = XmlCommon::GetAttributeByName(objectElement, "status");

				// Only search for matches if the status is exists.
				if(objStatus.compare("exists") == 0 || objStatus.compare("") == 0) {
					
					ElementVector regexItems = GetRegexItemMatches(definitionObject, scItemContainer);
					return regexItems;

				} else {
					// Return the pattern item 
					items.push_back(patternItem);
					return items;
				}

			// No matches for the pattern were found in the data file
			} else {
				items.clear();
				return items;
			}
			
		} else {

			// No regular expression. only need to return one item
			DOMElement *literalItem = GetLiteralItemMatch(definitionObject, scItemContainer);
			if(literalItem != NULL)
				items.push_back(literalItem);
		}

	} else {

		//////////////////////////////////////////////////////////////////
		// Object section is NULL. This only happens if a test			//
		// does not have an object. In this case all the items			//
		// of the specified type should be added to the return vector	//
		//																//
		//////////////////////////////////////////////////////////////////

		// Get a reference to the item container in the data file
		DOMElement *itemContainer = XmlCommon::FindNode(dataDoc, scItemContainer);

		if(itemContainer != NULL) {

			// Loop through all child items	and add each one to the list of matches	
			DOMNode *item = NULL;
			for (item = itemContainer->getFirstChild(); item != NULL; item=item->getNextSibling()) {
				if(item->getNodeType() == DOMNode::ELEMENT_NODE) {
					items.push_back((DOMElement*)item);
				}
			}
		} 
	}

	return items;
}

DOMElement* SimpleTestAnalyzer::GetLiteralItemMatch(DOMElement *definitionObject, string scItemContainer, bool considerDataType)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a NodeVector of items that match the provided definition item
	//	Use a string compare for matching
	// -----------------------------------------------------------------------

	DOMElement *matchingItem = NULL;

	// Get a reference to the item container in the data file
	DOMNode *itemContainer = XmlCommon::FindNode(dataDoc, scItemContainer);

	if(itemContainer != NULL) {
		// Loop through all child items		
		DOMNode *item = NULL;
		for (item = itemContainer->getFirstChild(); item != NULL; item=item->getNextSibling()) {
			if(item->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement* itemElm = (DOMElement*)item;

				// Get the object section of the item
				DOMNode *itemObj = XmlCommon::FindNode(itemElm, "object");

				if(itemObj != NULL) {
					// Now compare the two object sections.
					if(CompareObjectElements(definitionObject, (DOMElement*)itemObj, "literal", considerDataType)) {
						matchingItem = (DOMElement*)item;
						break;
					}
				}
			}
		}
	} else {
		// The item container does not exist just return NULL;
		matchingItem = NULL;
	}

	return matchingItem;
}

ElementVector SimpleTestAnalyzer::GetRegexItemMatches(DOMElement *definitionObject, string scItemContainer)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a NodeVector of items that match the provided definition item
	//	Use regular expressions for matching
	// -----------------------------------------------------------------------

	ElementVector matches;

	// Get a reference to the item container in the data file
	DOMElement *itemContainer = XmlCommon::FindNode(dataDoc, scItemContainer);

	if(itemContainer != NULL) {
		// Loop through all child items		
		for (DOMNode* tmpNode = itemContainer->getFirstChild(); tmpNode != NULL; tmpNode=tmpNode->getNextSibling()) {
			if(tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement* item = (DOMElement*)tmpNode;

				// Get the object section of the item
				DOMElement *itemObj = XmlCommon::FindNode(item, "object");

				if(itemObj != NULL) {
					// Now compare the two object sections.
					if(CompareObjectElements(definitionObject, itemObj)) {
						matches.push_back(item);
					}
				}
			}
		}
	} 

	return matches;
}

void SimpleTestAnalyzer::MapTestToItem(string *itemContainer, string *itemName, string testName)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Force this class to be a singleton. Return an Instance of the 
	//	DefiitionAnalyzer
	//
	// -----------------------------------------------------------------------
	
	// Get the mapping element for this specifiec test
	DOMElement *container = XmlCommon::FindNode(mappingDoc, Analyzer::family);
	DOMElement *mapping = XmlCommon::FindNode((DOMElement*)container, "mapping", "oval_test", testName);

	(*itemContainer) = XmlCommon::GetAttributeByName(mapping, "sc_container");
	(*itemName) = XmlCommon::GetAttributeByName(mapping, "sc_item");
}














