//
// $Id: ProbeData.cpp,v 1.15 2005/08/05 20:19:16 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 "ProbeData.h"

//****************************************************************************************//
//								ProbeData Class											  //	
//****************************************************************************************//
int ProbeData::globalUniqueId = 1;
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *ProbeData::dataDocument = NULL;


ProbeData::ProbeData()
{
	// -----------------------------------------------------------------------
	//	ABSTRACT
	//
	//	Initialize the message and the object status.to default values
	//	Increment the unique id.
	// -----------------------------------------------------------------------
	this->msg = "";
	this->objectStatus = exists;
	this->testId = "";
	isPatternMatchObject = false;
}

ProbeData::~ProbeData()
{
	// -----------------------------------------------------------------------
	//	ABSTRACT
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}

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

void ProbeData::AddDataChildElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, DOMElement *parent, string nodeName, DataElement *data)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add a new DOMElement node to the parent data node. Use nodeName and 
	//	nodeValue to construct the new node. Add the data type and status 
	//	Attrributes if not the default values
	//	
	// -----------------------------------------------------------------------
	DOMText *tmpTextNode = NULL;
	DOMElement *newElem = NULL;
	string strDataType;
	string strStatus;

	//	Convert the datatype flag to a string.
	strDataType = SwitchDataType(data->dataType);
	if(strDataType.compare("exists") == 0)
		strDataType = "";

	// Convert the status flag to a string
	strStatus = SwitchStatusType(data->status);
	if(strStatus.compare("string") == 0)
		strStatus = "";

	newElem = doc->createElement(XMLString::transcode(nodeName.c_str()));

	// Add the attributes
	XmlCommon::AddAttribute(newElem, "datatype", strDataType);
	XmlCommon::AddAttribute(newElem, "status", strStatus);
	

	// Add the value
	if(data->value.compare("") != 0) {
		tmpTextNode = doc->createTextNode(XMLString::transcode(data->value.c_str()));
		newElem->appendChild(tmpTextNode);
	}

	
	parent->appendChild(newElem);
}

void ProbeData::AddObjectChildElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, DOMElement *parent, string nodeName, ObjectElement *object)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add a new DOMElement node to the parent object node. Use nodeName and 
	//	object to construct the new node. Add the data type if not the 
	//	default values
	//	
	// -----------------------------------------------------------------------
	DOMText *tmpTextNode = NULL;
	DOMElement *newElem = NULL;
	string strObjectType;

	// Create an element
	newElem = doc->createElement(XMLString::transcode(nodeName.c_str()));

	// Add the attributes
	//	Convert the type flag to a string.
	strObjectType = SwitchObjectType(object->type);
	if(strObjectType.compare("literal") != 0)
		XmlCommon::AddAttribute(newElem, "datatype", strObjectType);		

	// Add the value
	if(object->object.compare("") != 0) {
		tmpTextNode = doc->createTextNode(XMLString::transcode(object->object.c_str()));
		newElem->appendChild(tmpTextNode);
	}
	
	parent->appendChild(newElem);
}

DOMElement* ProbeData::CreateNewItemNode(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *dataDocument, string itemName)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new item node. Set the name to itemName. 
	//	Set the id for the item.
	//	Add the message element if there is a message
	//
	// -----------------------------------------------------------------------

	//	Create the new item node
	DOMElement *newItem = dataDocument->createElement(XMLString::transcode(itemName.c_str()));

	// Add the id attribute
	XmlCommon::AddAttribute(newItem, "id", Common::ToString(this->globalUniqueId++));

	// Add the message element if there is one
	if(msg.compare("") != 0) {
		XmlCommon::AddChildElement(dataDocument, newItem, "system_characteristics:message", msg);
	}

	return newItem;
}

string ProbeData::GetMessage()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the message
	// -----------------------------------------------------------------------
	return msg;
}

string ProbeData::GetXmlns()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the namespace
	// -----------------------------------------------------------------------
	return this->xmlns;
}

string ProbeData::GetXmlnsAlias()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the namespace alias
	// -----------------------------------------------------------------------
	return this->xmlnsAlias;
}

statusTypes ProbeData::GetStatus()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the status
	// -----------------------------------------------------------------------
	return objectStatus;
}

string ProbeData::GetSchemaLocation()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the message
	// -----------------------------------------------------------------------
	return this->schemaLocation;
}

string ProbeData::GetTestId()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the message
	// -----------------------------------------------------------------------
	return testId;
}

void ProbeData::InsertItem(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, DOMElement *item, string containerName)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the specified item to the container with the specified name.
	//  If the container is not found create it...
	// -----------------------------------------------------------------------

	DOMElement *containerElm = NULL;
	containerElm = (DOMElement*)XmlCommon::FindNode(doc, containerName);

	// If the container is not found create it
	if(containerElm == NULL) {
		//	Get the system_data node
		DOMNode *sysDataNode = XmlCommon::FindNode(doc, "system_data");

		// Create the new item container node
		containerElm = doc->createElement(XMLString::transcode(containerName.c_str()));
		sysDataNode->appendChild(containerElm);

		//	Add the namespace information
		XmlCommon::AddAttribute(containerElm, "xmlns", this->GetXmlns());

		// add the schema location to the document root
		this->UpdateSchemaLocation();

		// add the namespace to the document root
		this->UpdateXmlns();
	}

	containerElm->appendChild(item);
}

void ProbeData::SetDataDoc(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the data doc
	// -----------------------------------------------------------------------
	dataDocument = doc;
}

void ProbeData::SetXmlns(string ns)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the namespace
	// -----------------------------------------------------------------------
	this->xmlns = ns;
}

void ProbeData::SetXmlnsAlias(string alias)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the namespace alias
	// -----------------------------------------------------------------------
	this->xmlnsAlias = alias;
}

void ProbeData::SetMessage(string msgIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the message
	// -----------------------------------------------------------------------
	msg = msgIn;
}

void ProbeData::SetSchemaLocation(string location)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the message
	// -----------------------------------------------------------------------
	this->schemaLocation = location;
}

void ProbeData::SetStatus(statusTypes status)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	set the status
	// -----------------------------------------------------------------------
	objectStatus = status;
}

string ProbeData::SwitchDataType(dataTypes type)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Convert the data type enum values to strings..
	// -----------------------------------------------------------------------
	string strDataType = "";

	switch (type)
	{
		case stringType: 
			strDataType = "string";
			break;
		case integerType:
			strDataType = "int";
			break;
		case binaryType:
			strDataType = "binary";
			break;
		case booleanType:
			strDataType = "boolean";
			break;
		case floatType:
			strDataType = "float";
			break;
		case versionType:
			strDataType = "version";
			break;
		default:
			throw ProbeDataException("Error: SwitchDataType() Unsupported datatype specified.");
			break;
	}

	return strDataType;

}

string ProbeData::SwitchObjectType(objectTypes type)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Convert the object type enum values to strings..
	// -----------------------------------------------------------------------
	string strObjectType = "";

	switch (type)
	{
		case pattern_match: 
			strObjectType = "pattern match";
			break;
		case literal:
			strObjectType = "literal";
			break;
		default:
			throw ProbeDataException("Error: SwitchObjectType() Unsupported objectTypes specified.");
			break;
	}

	return strObjectType;
}

string ProbeData::SwitchStatusType(statusTypes status)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Convert the status type enum values to strings..
	// -----------------------------------------------------------------------
	string strStatus = "";
	
	switch (status)
	{
		case error:
			strStatus = "error";
			break;
		case exists:
			strStatus = "exists";
			break;
		case doesNotExist:
			strStatus = "does not exist";
			break;
		case notCollected:
			strStatus = "not collected";
			break;
		default:
			throw ProbeDataException("Error: SwitchStatusType() Unsupported status specified.");
			break;
	}

	return strStatus;
}

void ProbeData::UpdateSchemaLocation()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the specified location to the schema location attribute on 
	//	the sc document
	// -----------------------------------------------------------------------

	DOMElement *scDocNode = XmlCommon::FindNode(this->dataDocument, "system_characteristics");
	string currentSchemaLocation = XmlCommon::GetAttributeByName(scDocNode, "xsi:schemaLocation");

	// determine if the specifed location exists already
	if(strstr(currentSchemaLocation.c_str(), this->GetSchemaLocation().c_str()) == NULL) {
		XmlCommon::AddAttribute((DOMElement*)scDocNode, "xsi:schemaLocation", currentSchemaLocation + " " + this->GetSchemaLocation());
	}
}

void ProbeData::UpdateXmlns()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the specified Xmlns to the document root if it does not already 
	//	exist
	// -----------------------------------------------------------------------

	DOMElement *scDocNode = XmlCommon::FindNode(this->dataDocument, "system_characteristics");
	if(XmlCommon::GetAttributeByName(scDocNode, "xmlns:" + this->GetXmlnsAlias()).compare("") == 0) {
		XmlCommon::AddAttribute((DOMElement*)scDocNode, "xmlns:" + this->GetXmlnsAlias(), this->GetXmlns());
	}
}

bool ProbeData::WroteItem(sVector *objs, string item)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	if the item is in the vector return true.
	//	else add the item and return false
	// -----------------------------------------------------------------------

	bool foundItem = false;

	sVector::iterator sIterator;
	for (sIterator=objs->begin(); sIterator!=objs->end(); sIterator++) {

		if(sIterator->compare(item) == 0) {
			foundItem = true;
			break;
		}
	}

	if(!foundItem)
		objs->push_back(item);

	return foundItem;
}

//****************************************************************************************//
//							ProbeDataException Class									  //	
//****************************************************************************************//

ProbeDataException::ProbeDataException(string errMsgIn, int severity) : Exception(errMsgIn, severity)
{
	// -----------------------------------------------------------------------
	//	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.
	//
	// -----------------------------------------------------------------------

}

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

}

