//---------------------------------------------------------------------------------
// <copyright file="EventPropertyValue.cpp" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
// 	Implementation of EventPropertyValue class, which wraps a CORBA Any instance to
//  store one of several basic types and which interoperates with STL vector and
//  STL string.
// </summary>
//
// <owner>Mike Cookson</owner>
//---------------------------------------------------------------------------------

#include "EventPropertyValue.h"
#include "EventPropertyValue-inline.h"
#include "EPVFormatConfig.h"
#include "nsextend.h"
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;
using namespace boost::serialization;
using namespace ::CORBA;
using namespace ::LiquidRobotics::EventLibIDL;
using namespace ::LiquidRobotics::SMACFramework;
using namespace ::LiquidRobotics::SMACFramework::XmlDOM;
using namespace pugi;

namespace LiquidRobotics {
namespace EventLib {

static const struct st_table_entry { EventPropertyValue::StorageType stype; string str; } st_table[] =
{
		{	EventPropertyValue::ST_UINT8,				"UINT8"						},
		{	EventPropertyValue::ST_INT8,				"INT8"						},
		{	EventPropertyValue::ST_UINT16,				"UINT16"					},
		{	EventPropertyValue::ST_INT16,				"INT16"						},
		{	EventPropertyValue::ST_UINT32,				"UINT32"					},
		{	EventPropertyValue::ST_INT32,				"INT32"						},
		{	EventPropertyValue::ST_SINGLE_FLOAT,		"SINGLE_FLOAT"				},
		{	EventPropertyValue::ST_DOUBLE_FLOAT,		"DOUBLE_FLOAT"				},
		{	EventPropertyValue::ST_STRING,				"STRING"					},
		{	EventPropertyValue::ST_BOOLEAN,				"BOOLEAN"					},
		{	EventPropertyValue::ST_NULL,				"NULL"						},
		{	EventPropertyValue::ST_UNSUPPORTED,			"UNSUPPORTED"				},
		{	EventPropertyValue::ST_UINT8_VECTOR,		"UINT8_VECTOR"				},
		{	EventPropertyValue::ST_INT8_VECTOR,			"INT8_VECTOR"				},
		{	EventPropertyValue::ST_UINT16_VECTOR,		"UINT16_VECTOR"				},
		{	EventPropertyValue::ST_INT16_VECTOR,		"INT16_VECTOR"				},
		{	EventPropertyValue::ST_UINT32_VECTOR,		"UINT32_VECTOR"				},
		{	EventPropertyValue::ST_INT32_VECTOR,		"INT32_VECTOR"				},
		{	EventPropertyValue::ST_SINGLE_FLOAT_VECTOR,	"SINGLE_FLOAT_VECTOR"		},
		{	EventPropertyValue::ST_DOUBLE_FLOAT_VECTOR,	"DOUBLE_FLOAT_VECTOR"		},
		{	EventPropertyValue::ST_STRING_VECTOR,		"STRING_VECTOR"				},
		{	EventPropertyValue::ST_BOOLEAN_VECTOR,		"BOOLEAN_VECTOR"			},
};

void EventPropertyValue::FromString(const string& str, StorageType& result)
{
	BOOST_FOREACH(const st_table_entry& te, st_table)
		if (!str.compare(te.str))
		{
			result = te.stype;
			return;
		}

	stringstream msg;
	msg << "No EventPropertValue::StorageType match for " << str;
	throw invalid_argument(msg.str());
}

string EventPropertyValue::ToString(const StorageType& stype)
{
	BOOST_FOREACH(const st_table_entry& te, st_table)
		if (te.stype == stype)
			return te.str;

	stringstream msg;
	msg << "No EventPropertValue::StorageType match for " << ((int) stype);
	throw invalid_argument(msg.str());
}

IMPLEMENT_INNER_EXCEPTION(EventPropertyValue,ExtractionFailed,std::runtime_error);

static EventPropertyValue::StorageType GetStorageType(const ::CORBA::Any& item, size_t* numElems = NULL);

EventPropertyValue::EventPropertyValue(IObjectBroker& _broker)
: broker(_broker)
{
	theValue = new Any();
	theValue.inout().type(_tc_null);
}

EventPropertyValue::EventPropertyValue(const EventPropertyValue& other)
: broker(other.broker)
{
	Copy(theValue, other.theValue.in());
}

EventPropertyValue::EventPropertyValue(const Any_var& anyVar, IObjectBroker& _broker)
: broker(_broker)
{
	Copy(theValue, anyVar.in());
}

EventPropertyValue::EventPropertyValue(const Any& any, IObjectBroker& _broker)
: broker(_broker)
{
	Copy(theValue, any);
}

template<typename PTR>
void DescribeNumeric(ostream& stm, PTR vectptr)
{
	typedef typename PTR::element_type VECT;

	if (vectptr)
	{
		stm << vectptr->size() << " items {";
		unsigned counter = 0;
		for (typename VECT::const_iterator ci = vectptr->begin(); (counter < 100) && (ci != vectptr->end()); ++ci, ++counter)
		{
			stm << " ";
			if (sizeof(*ci) == 1)
				stm << utos((unsigned char) *ci, 16, 2);
			else
				stm << *ci;
		}
		stm << " }";
	}
	else
		stm << "nil";
}

static void DescribeStringArray(ostream& stm, EventPropertyValue::StringVectorPtr data)
{
	if (data)
	{
		stm << data->size() << " items { ";
		unsigned counter = 0;
		for (EventPropertyValue::StringVector::const_iterator ci = data->begin(); (counter < 100) && (ci != data->end()); ++ci, ++counter)
			stm << " '" << *ci << "'";
		stm << " }";
	}
	else
		stm << "nil";
}

ostream& EventPropertyValue::Describe(ostream& stm, bool verbose) const
{
	StorageType sType = GetStorageType();
	const string sep = "/";

	stm << DescribeStorageType(sType);

	if (sType == ST_UINT8)
	{
		const unsigned u = GetUInt8();
		char c = (char) u;
		if (!isprint(c) || iscntrl(c)) c = '.';
		stm << sep << c << "(" << u << ")";
	}
	else if (sType == ST_INT8)
	{
		const int i = GetInt8();
		char c = (char) i;
		if (!isprint(c) || iscntrl(c)) c = '.';
		stm << sep << c << "(" << i << ")";
	}
	else
	switch(sType)
	{
	case ST_UINT16:					stm << sep << GetUInt16();													break;
	case ST_INT16:					stm << sep << GetInt16();													break;
	case ST_UINT32:					stm << sep << GetUInt32();													break;
	case ST_INT32:					stm << sep << GetInt32();													break;
	case ST_SINGLE_FLOAT:			stm << sep << GetSingleFloat();												break;
	case ST_DOUBLE_FLOAT:			stm << sep << GetDoubleFloat();												break;
	case ST_STRING:					stm << sep << "'" << GetString() << "'";									break;
	case ST_BOOLEAN:				stm << sep << (GetBoolean() ? "true" : "false");							break;
	case ST_UINT8_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetUInt8Vector()); }		break;
	case ST_INT8_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetInt8Vector()); }			break;
	case ST_UINT16_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetUInt16Vector()); }		break;
	case ST_INT16_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetInt16Vector()); }		break;
	case ST_UINT32_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetUInt32Vector()); }		break;
	case ST_INT32_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetInt32Vector()); }		break;
	case ST_SINGLE_FLOAT_VECTOR:	if (verbose) { stm << sep; DescribeNumeric(stm, GetSingleFloatVector()); }	break;
	case ST_DOUBLE_FLOAT_VECTOR:	if (verbose) { stm << sep; DescribeNumeric(stm, GetDoubleFloatVector()); }	break;
	case ST_STRING_VECTOR:			if (verbose) { stm << sep; DescribeStringArray(stm, GetStringVector());	}	break;
	case ST_BOOLEAN_VECTOR:			if (verbose) { stm << sep; DescribeNumeric(stm, GetBooleanVector()); }		break;
	default:																									break;
	}

	return stm;
}


string EventPropertyValue::DescribeStorageType() const
{
	return DescribeStorageType(GetStorageType());
}

string EventPropertyValue::DescribeStorageType(StorageType storageType)
{
	try
	{
		return ToString(storageType);
	}
	catch(invalid_argument& ex)
	{
		stringstream stm;
		stm << (int) storageType << "?";
		return stm.str();
	}
}

EventPropertyValue& EventPropertyValue::operator=(const EventPropertyValue& other)
{
	if (this != &other)
		Copy(theValue, other.theValue.in());

	return *this;
}

EventPropertyValue& EventPropertyValue::operator=(const Any_var& anyVar)
{
	if (&theValue != &anyVar)
		Copy(theValue, anyVar.in());

	return *this;
}

EventPropertyValue& EventPropertyValue::operator=(const Any& any)
{
	if (&theValue.in() != &any)
		Copy(theValue, any);

	return *this;
}

template<typename T> bool VectorsEqual(const T& v1, const T& v2)
{
	bool result;

	if (v1.size() != v2.size())
		result = false;
	else
	{
		const typename T::value_type& f1 = v1.front();
		const typename T::value_type& f2 = v2.front();
		result = !memcmp(&f1, &f2, v1.size()*sizeof(typename T::value_type));
	}

	return result;
}

bool EventPropertyValue::operator==(const EventPropertyValue& other) const
{
	const StorageType stype = GetStorageType();
	const StorageType stype2 = other.GetStorageType();
	bool result;

	if ((stype != stype2) || (stype == ST_UNSUPPORTED))
		result = false;

	else
	{
		switch(stype)
		{
		case ST_UINT8:				result = (GetUInt8() == other.GetUInt8());					break;
		case ST_INT8:				result = (GetInt8() == other.GetInt8());					break;
		case ST_UINT16:				result = (GetUInt16() == other.GetUInt16());				break;
		case ST_INT16:				result = (GetInt16() == other.GetInt16());					break;
		case ST_UINT32:				result = (GetUInt32() == other.GetUInt32());				break;
		case ST_INT32:				result = (GetInt32() == other.GetInt32());					break;
		case ST_SINGLE_FLOAT:		result = (GetSingleFloat() == other.GetSingleFloat());		break;
		case ST_DOUBLE_FLOAT:		result = (GetDoubleFloat() == other.GetDoubleFloat());		break;

		case ST_STRING:
		{
			const string s1 = GetString();
			const string s2 = other.GetString();
			result = !s1.compare(s2);
			break;
		}

		case ST_BOOLEAN:			result = (GetBoolean() == other.GetBoolean());				break;
		case ST_NULL:				result = true;												break;

		case ST_UINT8_VECTOR:
		{
			UInt8VectorPtr p1 = GetUInt8Vector();
			UInt8VectorPtr p2 = other.GetUInt8Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_INT8_VECTOR:
		{
			Int8VectorPtr p1 = GetInt8Vector();
			Int8VectorPtr p2 = other.GetInt8Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_UINT16_VECTOR:
		{
			UInt16VectorPtr p1 = GetUInt16Vector();
			UInt16VectorPtr p2 = other.GetUInt16Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_INT16_VECTOR:
		{
			Int16VectorPtr p1 = GetInt16Vector();
			Int16VectorPtr p2 = other.GetInt16Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_UINT32_VECTOR:
		{
			UInt32VectorPtr p1 = GetUInt32Vector();
			UInt32VectorPtr p2 = other.GetUInt32Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_INT32_VECTOR:
		{
			Int32VectorPtr p1 = GetInt32Vector();
			Int32VectorPtr p2 = other.GetInt32Vector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_SINGLE_FLOAT_VECTOR:
		{
			SingleFloatVectorPtr p1 = GetSingleFloatVector();
			SingleFloatVectorPtr p2 = other.GetSingleFloatVector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_DOUBLE_FLOAT_VECTOR:
		{
			DoubleFloatVectorPtr p1 = GetDoubleFloatVector();
			DoubleFloatVectorPtr p2 = other.GetDoubleFloatVector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		case ST_STRING_VECTOR:
		{
			StringVectorPtr p1 = GetStringVector();
			StringVectorPtr p2 = other.GetStringVector();
			StringVector::size_type s1 = p1->size();

			result = (s1 == p2->size());

			if (result && s1)
			{
				StringVector::const_iterator ci2 = p2->begin();

				BOOST_FOREACH(const string& str, *p1)
					if (str.compare(*ci2++))
					{
						result = false;
						break;
					}
			}

			break;
		}

		case ST_BOOLEAN_VECTOR:
		{
			BooleanVectorPtr p1 = GetBooleanVector();
			BooleanVectorPtr p2 = other.GetBooleanVector();

			result = VectorsEqual(*p1, *p2);
			break;
		}

		default:
		{
			stringstream msg;
			msg << __FILE__ << "(" << __LINE__ << ") Unexpected storage type " << (int) stype;
			throw runtime_error(msg.str());
		}


		}
	}

	return result;

}

void EventPropertyValue::CopyOut(Any& any) const
{
	if (&theValue.in() != &any)
		any = theValue.in();
}

EventPropertyValue::StorageType EventPropertyValue::GetStorageType() const
{
	return LiquidRobotics::EventLib::GetStorageType(theValue.in());
}

static EventPropertyValue::StorageType GetStorageType(const ::CORBA::Any& item, size_t* numElems)
{
	size_t localNumElems;

	if (!numElems)
		numElems = &localNumElems;

	TypeCode_var typeCode;
	typeCode = item.type();
	const TCKind kind = typeCode->kind();

	TypeCode_var contentCode;
	TCKind contentKind = tk_null;

	if ((kind == tk_array) || (kind == tk_sequence))
	{
		contentCode = typeCode->content_type();
		contentKind = contentCode->kind();
	}

	EventPropertyValue::StorageType result;

	if (typeCode->equivalent(_tc_EvLib_Int8))
		result = EventPropertyValue::ST_INT8,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_UInt8))
		result = EventPropertyValue::ST_UINT8,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_Int16))
		result = EventPropertyValue::ST_INT16,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_UInt16))
		result = EventPropertyValue::ST_UINT16,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_Int32))
		result = EventPropertyValue::ST_INT32,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_UInt32))
		result = EventPropertyValue::ST_UINT32,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_SingleFloat))
		result = EventPropertyValue::ST_SINGLE_FLOAT,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_DoubleFloat))
		result = EventPropertyValue::ST_DOUBLE_FLOAT,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_EvLib_String))
		result = EventPropertyValue::ST_STRING,
		*numElems = typeCode->length();
	else if (typeCode->equivalent(_tc_EvLib_Boolean))
		result = EventPropertyValue::ST_BOOLEAN,
		*numElems = 1;
	else if (typeCode->equivalent(_tc_null))
		result = EventPropertyValue::ST_NULL,
		*numElems = 0;
	else if ((kind == tk_array) && (contentKind == tk_char))
		result = EventPropertyValue::ST_INT8_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_octet))
		result = EventPropertyValue::ST_UINT8_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_short))
		result = EventPropertyValue::ST_INT16_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_ushort))
		result = EventPropertyValue::ST_UINT16_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_long))
		result = EventPropertyValue::ST_INT32_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_ulong))
		result = EventPropertyValue::ST_UINT32_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_float))
		result = EventPropertyValue::ST_SINGLE_FLOAT_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_double))
		result = EventPropertyValue::ST_DOUBLE_FLOAT_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_string))
		result = EventPropertyValue::ST_STRING_VECTOR,
		*numElems = typeCode->length();
	else if ((kind == tk_array) && (contentKind == tk_boolean))
		result = EventPropertyValue::ST_BOOLEAN_VECTOR,
		*numElems = typeCode->length();
	else
		result = EventPropertyValue::ST_UNSUPPORTED,
		*numElems = 0;

	return result;
}

template<typename VECTOR_TYPE>
boost::shared_ptr<VECTOR_TYPE> EventPropertyValue::GetVector() const
{
	typedef boost::shared_ptr<VECTOR_TYPE> VECTOR_PTR;

	VECTOR_PTR result;
	result.reset(new VECTOR_TYPE);

	broker.AnyToCppVector(*result, theValue.in());
	return result;
}

template<typename VECTOR_TYPE>
void EventPropertyValue::SetVector(const VECTOR_TYPE& newValue, TypeCode_ptr resultType)
{
	theValue = broker.CppVectorToAny<VECTOR_TYPE>(newValue, resultType);
}

template<typename CPP_TYPE>
void EventPropertyValue::SetVector(const CPP_TYPE* pStart, size_type length, TypeCode_ptr resultType)
{
	theValue = broker.CppVectorToAny<CPP_TYPE>(pStart, length, resultType);
}

EventPropertyValue::Int8 EventPropertyValue::GetInt8() const					{ return GetScalar<Int8, Char, Any::to_char>(ST_INT8); }
EventPropertyValue::Int8VectorPtr EventPropertyValue::GetInt8Vector() const		{ return GetVector<Int8Vector>(); }
void EventPropertyValue::SetInt8(Int8 newValue)									{ SetScalar<Int8, Char, Any::from_char>(newValue); }
void EventPropertyValue::SetInt8Vector(const Int8* pStart, size_type length)	{ SetVector<Int8>(pStart, length, _tc_char); }
void EventPropertyValue::SetInt8Vector(const Int8Vector& newValue) 				{ SetVector<Int8Vector>(newValue, _tc_char); }

EventPropertyValue::UInt8 EventPropertyValue::GetUInt8() const					{ return GetScalar<UInt8, Octet, Any::to_octet>(ST_UINT8); }
EventPropertyValue::UInt8VectorPtr EventPropertyValue::GetUInt8Vector() const	{ return GetVector<UInt8Vector>(); }
void EventPropertyValue::SetUInt8(UInt8 newValue)								{ SetScalar<UInt8, Octet, Any::from_octet>(newValue); }
void EventPropertyValue::SetUInt8Vector(const UInt8* pStart, size_type length)	{ SetVector<UInt8>(pStart, length, _tc_octet); }
void EventPropertyValue::SetUInt8Vector(const UInt8Vector& newValue)			{ SetVector<UInt8Vector>(newValue, _tc_octet); }

EventPropertyValue::ByteArrayPtr EventPropertyValue::GetByteArray() const		{ return GetVector<ByteArray>(); }
void EventPropertyValue::SetByteArray(const ByteArray& newValue)				{ SetVector<ByteArray>(newValue, _tc_octet); }

EventPropertyValue::Int16 EventPropertyValue::GetInt16() const					{ return GetScalar<Int16, Short>(ST_INT16); }
EventPropertyValue::Int16VectorPtr EventPropertyValue::GetInt16Vector() const	{ return GetVector<Int16Vector>(); }
void EventPropertyValue::SetInt16(Int16 newValue)								{ SetScalar<Int16, Short>(newValue); }
void EventPropertyValue::SetInt16Vector(const Int16* pStart, size_type length)	{ SetVector<Int16>(pStart, length, _tc_short); }
void EventPropertyValue::SetInt16Vector(const Int16Vector& newValue)			{ SetVector<Int16Vector>(newValue, _tc_short); }

EventPropertyValue::UInt16 EventPropertyValue::GetUInt16() const				{ return GetScalar<UInt16, UShort>(ST_UINT16); }
EventPropertyValue::UInt16VectorPtr EventPropertyValue::GetUInt16Vector() const	{ return GetVector<UInt16Vector>(); }
void EventPropertyValue::SetUInt16(UInt16 newValue)								{ SetScalar<UInt16, UShort>(newValue); }
void EventPropertyValue::SetUInt16Vector(const UInt16* pStart, size_type length) { SetVector<UInt16>(pStart, length, _tc_ushort); }
void EventPropertyValue::SetUInt16Vector(const UInt16Vector& newValue)			{ SetVector<UInt16Vector>(newValue, _tc_ushort); }

EventPropertyValue::Int32 EventPropertyValue::GetInt32() const					{ return GetScalar<Int32, Long>(ST_INT32); }
EventPropertyValue::Int32VectorPtr EventPropertyValue::GetInt32Vector() const	{ return GetVector<Int32Vector>(); }
void EventPropertyValue::SetInt32(Int32 newValue)								{ SetScalar<Int32, Long>(newValue); }
void EventPropertyValue::SetInt32Vector(const Int32* pStart, size_type length)	{ SetVector<Int32>(pStart, length, _tc_long); }
void EventPropertyValue::SetInt32Vector(const Int32Vector& newValue)			{ SetVector<Int32Vector>(newValue, _tc_long); }

EventPropertyValue::UInt32 EventPropertyValue::GetUInt32() const				{ return GetScalar<UInt32, ULong>(ST_UINT32); }
EventPropertyValue::UInt32VectorPtr EventPropertyValue::GetUInt32Vector() const { return GetVector<UInt32Vector>(); }
void EventPropertyValue::SetUInt32(UInt32 newValue)								{ SetScalar<UInt32, ULong>(newValue); }
void EventPropertyValue::SetUInt32Vector(const UInt32* pStart, size_type length) { SetVector<UInt32>(pStart, length, _tc_ulong); }
void EventPropertyValue::SetUInt32Vector(const UInt32Vector& newValue)			{ SetVector<UInt32Vector>(newValue, _tc_ulong); }

EventPropertyValue::SingleFloat EventPropertyValue::GetSingleFloat() const		{ return GetScalar<SingleFloat, Float>(ST_SINGLE_FLOAT); }
EventPropertyValue::SingleFloatVectorPtr EventPropertyValue::GetSingleFloatVector() const
																				{ return GetVector<SingleFloatVector>(); }
void EventPropertyValue::SetSingleFloat(SingleFloat newValue)					{ SetScalar<SingleFloat, Float>(newValue); }
void EventPropertyValue::SetSingleFloatVector(const SingleFloat* pStart, size_type length)
																				{ SetVector<SingleFloat>(pStart, length, _tc_float); }
void EventPropertyValue::SetSingleFloatVector(const SingleFloatVector& newValue) { SetVector<SingleFloatVector>(newValue, _tc_float); }

EventPropertyValue::DoubleFloat EventPropertyValue::GetDoubleFloat() const		{ return GetScalar<DoubleFloat, Double>(ST_DOUBLE_FLOAT); }
EventPropertyValue::DoubleFloatVectorPtr EventPropertyValue::GetDoubleFloatVector() const
																				{ return GetVector<DoubleFloatVector>(); }
void EventPropertyValue::SetDoubleFloat(DoubleFloat newValue)					{ SetScalar<DoubleFloat, Double>(newValue); }
void EventPropertyValue::SetDoubleFloatVector(const DoubleFloat* pStart, size_type length)
																				{ SetVector<DoubleFloat>(pStart, length, _tc_double); }
void EventPropertyValue::SetDoubleFloatVector(const DoubleFloatVector& newValue) { SetVector<DoubleFloatVector>(newValue, _tc_double); }

EventPropertyValue::String EventPropertyValue::GetString() const
{
	const StorageType storageType = ST_STRING;
	const char* temp;
	bool extractionOK = (theValue >>= temp);

	if (!extractionOK)
	{
		stringstream stm;

		stm << "GetScalar: failed to extract type " << DescribeStorageType(storageType)
			<< " from property containing type " << DescribeStorageType();

		throw ExtractionFailed(stm.str());
	}

	return String(temp);
}

EventPropertyValue::StringVectorPtr EventPropertyValue::GetStringVector() const //{ return GetVector<String, EvLib_StringSeq>(ST_STRING); }
{
	EventPropertyValue::StringVectorPtr result;
	result.reset(new StringVector);

	broker.AnyToStringVector(*result, theValue.in());

	return result;
}

void EventPropertyValue::SetString(String newValue)								//{ SetScalar<String, EvLib_String, Any::from_string>(newValue); }
{
	theValue = new ::CORBA::Any;
	theValue <<= newValue.c_str();
}
void EventPropertyValue::SetStringVector(const String* pStart, size_type length) //{ SetVector<String, EvLib_StringSeq>(pStart, length); }
{
	theValue = broker.StringVectorToAny(pStart, length);
}
void EventPropertyValue::SetStringVector(const StringVector& newValue)			//{ SetVector<String, EvLib_StringSeq>(newValue); }
{
	theValue = broker.StringVectorToAny(newValue);
}

EventPropertyValue::String EventPropertyValue::GetStringVariant() const
{
	ByteArrayPtr bap;

	try
	{
		 bap = EventPropertyValue::GetByteArray();
	}
	catch(...)
	{
	}

	String result;

	if (bap)
		result = bap->ToASCIIString();
	else
		result = GetString();

	return result;
}
void EventPropertyValue::SetStringVariant(String newValue)
{
	if (newValue.find('\0') == String::npos)
		SetString(newValue);
	else
	{
		const ByteArray::byte* pStart = (const ByteArray::byte*) newValue.data();
		ByteArray ba(pStart,pStart+newValue.length());
		SetByteArray(ba);
	}
}

EventPropertyValue::Boolean EventPropertyValue::GetBoolean() const				{ return GetScalar<Boolean, EvLib_Boolean, Any::to_boolean>(ST_BOOLEAN); }
EventPropertyValue::BooleanVectorPtr EventPropertyValue::GetBooleanVector() const { return /*BooleanVectorPtr(); */GetVector<BooleanVector>(); }
void EventPropertyValue::SetBoolean(Boolean newValue)							{ SetScalar<Boolean, EvLib_Boolean, Any::from_boolean>(newValue); }
void EventPropertyValue::SetBooleanVector(const Boolean* pStart, size_type length) { SetVector<Boolean>(pStart, length, _tc_boolean); }
void EventPropertyValue::SetBooleanVector(const BooleanVector& newValue)		{ SetVector<BooleanVector>(newValue, _tc_boolean); }

void EventPropertyValue::Copy(Any_var& to, const Any& from)
{
	if (!&from)
		throw invalid_argument("EventPropertyValue::Copy cannot copy a null item");

	if (!&to)
		throw invalid_argument("EventPropertyValue::Copy cannot copy to a null destination");

	StorageType stype = LiquidRobotics::EventLib::GetStorageType(from);

	switch(stype)
	{
	case ST_UNSUPPORTED:

		throw invalid_argument("EventPropertyValue::Copy cannot copy an unsupported type");

	default:

		to = new Any(from);
		break;
	}

}

void ScalarToBinary(const string& val, ByteArray& result)
{
	const ByteArray::byte* pData = (const ByteArray::byte*) val.data();
	result.insert(result.end(), pData, pData+val.length());
}

void ScalarToBinary(const string& val, const EPVFormatConfig& fmt, ByteArray& result)
{
	const size_t length = val.length();
	size_t newLength = length;

	if (fmt.PaddingEnabled() && (newLength < fmt.GetFieldPadding()))
		newLength = fmt.GetFieldPadding();

	if (fmt.TruncationEnabled() && (newLength > fmt.GetFieldTruncation()))
		newLength = fmt.GetFieldTruncation();

	const ByteArray::byte* pData = (const ByteArray::byte*) val.data();

	if (newLength)
	{
		if (newLength <= length)
			result.insert(result.end(), pData, pData+newLength);
		else
			result.insert(result.end(), pData, pData+length);

		if (newLength > length)
			result.insert(result.end(), newLength-length, fmt.GetFieldPaddingValue());
	}
}

template<typename T> void ScalarToBinary(T tval, ByteArray& result)
{
	const ByteArray::byte* pData = (const ByteArray::byte*) &tval;
	result.insert(result.end(), pData, pData+sizeof(T));
}

template<typename T> void ScalarToBinary(T tval, const EPVFormatConfig& fmt, ByteArray& result)
{
	EPVFormatConfig::Endianness endianness = fmt.GetEndianness();

	if ((endianness == EPVFormatConfig::ENDIAN_DFLT) || (endianness == EPVFormatConfig::DetectEndianness()))
		ScalarToBinary<T>(tval, result);
	else
	{
		const ByteArray::byte* pData = ((const ByteArray::byte*) &tval)+sizeof(T);
		size_t ctr = sizeof(T);

		while(ctr--)
			result.push_back(*--pData);
	}
}

template<typename T> void VectorToBinary(boost::shared_ptr< std::vector<T> > tval, ByteArray& result)
{
	BOOST_FOREACH(const T& item, *tval)
		ScalarToBinary<T>(item, result);
}

template<typename T> void VectorToBinary(boost::shared_ptr< std::vector<T> > tval, const EPVFormatConfig& fmt, ByteArray& result)
{
	const EPVFormatConfig::Endianness endianness = fmt.GetEndianness();

	if ((endianness == EPVFormatConfig::ENDIAN_DFLT) && !fmt.TruncationEnabled() && !fmt.PaddingEnabled())
		VectorToBinary<T>(tval, result);

	else
	{
		EPVFormatConfig fmt2(fmt);
		fmt2.ClearPadding();
		fmt2.ClearTruncation();

		const size_t elementSize = (typeid(T) == typeid(EventPropertyValue::String)) ? sizeof(char) : sizeof(T);
		const size_t size0 = result.size();
		const size_t length = tval->size();
		size_t newLength = length;

		if (fmt.TruncationEnabled() && (newLength > fmt.GetFieldTruncation()*elementSize))
			newLength = fmt.GetFieldTruncation()/elementSize;

		for (size_t idx = 0; idx < newLength; ++idx)
			ScalarToBinary<T>(tval->at(idx), fmt2, result);

		const size_t delta  = result.size()-size0;

		if (fmt.PaddingEnabled() && (delta < fmt.GetFieldPadding()))
			result.insert(result.end(), fmt.GetFieldPadding()-delta, fmt.GetFieldPaddingValue());
	}
}

void EventPropertyValue::ToBinary(ByteArray& result, bool append) const
{
	const StorageType stype = GetStorageType();

	if (!append)
		result.resize(0);

	switch(stype)
	{
	case ST_UINT8:						ScalarToBinary<UInt8>(GetUInt8(), result);					break;
	case ST_INT8:						ScalarToBinary<Int8>(GetInt8(), result);					break;
	case ST_UINT16:						ScalarToBinary<UInt16>(GetUInt16(), result);				break;
	case ST_INT16:						ScalarToBinary<Int16>(GetInt16(), result);					break;
	case ST_UINT32:						ScalarToBinary<UInt32>(GetUInt32(), result);				break;
	case ST_INT32:						ScalarToBinary<Int32>(GetInt32(), result);					break;
	case ST_SINGLE_FLOAT:				ScalarToBinary<SingleFloat>(GetSingleFloat(), result);		break;
	case ST_DOUBLE_FLOAT:				ScalarToBinary<DoubleFloat>(GetDoubleFloat(), result);		break;
	case ST_STRING:						{ String val = GetString(); ScalarToBinary(val, result);	break; }
	case ST_BOOLEAN:					ScalarToBinary<Boolean>(GetBoolean(), result);				break;
	case ST_NULL:																					break;
	case ST_UINT8_VECTOR:				VectorToBinary(GetUInt8Vector(), result);					break;
	case ST_INT8_VECTOR:				VectorToBinary(GetInt8Vector(), result);					break;
	case ST_UINT16_VECTOR:				VectorToBinary(GetUInt16Vector(), result);					break;
	case ST_INT16_VECTOR:				VectorToBinary(GetInt16Vector(), result);					break;
	case ST_UINT32_VECTOR:				VectorToBinary(GetUInt32Vector(), result);					break;
	case ST_INT32_VECTOR:				VectorToBinary(GetInt32Vector(), result);					break;
	case ST_SINGLE_FLOAT_VECTOR:		VectorToBinary(GetSingleFloatVector(), result);				break;
	case ST_DOUBLE_FLOAT_VECTOR:		VectorToBinary(GetDoubleFloatVector(), result);				break;
	case ST_STRING_VECTOR:				VectorToBinary(GetStringVector(), result);					break;
	case ST_BOOLEAN_VECTOR:				VectorToBinary(GetBooleanVector(), result);					break;

	case ST_UNSUPPORTED:
	default:
	{
		stringstream msg;
		msg << "Cannot convert type " << DescribeStorageType(stype) << " to binary";
		throw runtime_error(msg.str());
	}

	}
}

template<typename TU, typename TS>
void EventPropertyValue::ToBinaryWithLength(ByteArray& result, const EPVFormatConfig& fmt, bool append, const StorageType stype) const
{
	bool u = false;
	TU tu = 0;
	TS ts = 0;

	switch(stype)
	{
	case ST_UINT8:		tu = (TU) GetUInt8(); u = true; break;
	case ST_INT8:		ts = (TS) GetInt8(); break;
	case ST_UINT16:		tu = (TU) GetUInt16(); u = true; break;
	case ST_INT16:		ts = (TS) GetInt16(); break;
	case ST_UINT32:		tu = (TU) GetUInt32(); u = true; break;
	case ST_INT32:		ts = (TS) GetInt32(); break;
	default:
	{
		stringstream msg;
		msg << "Invalid storage type " << EventPropertyValue::DescribeStorageType(stype)
			<< " for use with length-based content algorithms";
		throw invalid_argument(msg.str());
	}
	}

	if (!append)
		result.resize(0);

	if (u)
		ScalarToBinary<TU>(tu, fmt, result);
	else
		ScalarToBinary<TS>(ts, fmt, result);
}

void EventPropertyValue::ToBinary(ByteArray& result, const EPVFormatConfig& fmt, bool append) const
{
	const EPVFormatConfig::ContentAlgorithm ca = fmt.GetContentAlgorithm();
	size_t lenContent;
	const StorageType stype = LiquidRobotics::EventLib::GetStorageType(theValue.in(), &lenContent);

	switch(ca)
	{
	case EPVFormatConfig::CA_LENGTH1:		ToBinaryWithLength<UInt8,Int8>(result, fmt, append, stype);		break;
	case EPVFormatConfig::CA_LENGTH2:		ToBinaryWithLength<UInt16,Int16>(result, fmt, append, stype);	break;
	case EPVFormatConfig::CA_LENGTH4:		ToBinaryWithLength<UInt32,Int32>(result, fmt, append, stype);	break;

	case EPVFormatConfig::CA_LITERAL:				// calls recursively with literal data
	{
		EPVFormatConfig fmt2(fmt);

		fmt2.SetContentAlgorithm(EPVFormatConfig::CA_RAW);
		fmt.GetLiteral().ToBinary(result, fmt2, append);
		break;
	}

	case EPVFormatConfig::CA_RAW:					// handling the raw format cases here
	{
		if (!append)
			result.resize(0);

		switch(stype)
		{
		case ST_UINT8:						ScalarToBinary<UInt8>(GetUInt8(), result);						break;
		case ST_INT8:						ScalarToBinary<Int8>(GetInt8(), result);						break;
		case ST_UINT16:						ScalarToBinary<UInt16>(GetUInt16(), fmt, result);				break;
		case ST_INT16:						ScalarToBinary<Int16>(GetInt16(), fmt, result);					break;
		case ST_UINT32:						ScalarToBinary<UInt32>(GetUInt32(), fmt, result);				break;
		case ST_INT32:						ScalarToBinary<Int32>(GetInt32(), fmt, result);					break;
		case ST_SINGLE_FLOAT:				ScalarToBinary<SingleFloat>(GetSingleFloat(), result);			break;
		case ST_DOUBLE_FLOAT:				ScalarToBinary<DoubleFloat>(GetDoubleFloat(), result);			break;
		case ST_STRING:						{ String val = GetString(); ScalarToBinary(val, fmt, result);	break; }
		case ST_BOOLEAN:					ScalarToBinary<Boolean>(GetBoolean(), result);					break;
		case ST_NULL:																						break;
		case ST_UINT8_VECTOR:				VectorToBinary(GetUInt8Vector(), fmt, result);					break;
		case ST_INT8_VECTOR:				VectorToBinary(GetInt8Vector(), fmt, result);					break;
		case ST_UINT16_VECTOR:				VectorToBinary(GetUInt16Vector(), fmt, result);					break;
		case ST_INT16_VECTOR:				VectorToBinary(GetInt16Vector(), fmt, result);					break;
		case ST_UINT32_VECTOR:				VectorToBinary(GetUInt32Vector(), fmt,result);					break;
		case ST_INT32_VECTOR:				VectorToBinary(GetInt32Vector(), fmt, result);					break;
		case ST_SINGLE_FLOAT_VECTOR:		VectorToBinary(GetSingleFloatVector(), fmt, result);			break;
		case ST_DOUBLE_FLOAT_VECTOR:		VectorToBinary(GetDoubleFloatVector(), fmt, result);			break;
		case ST_STRING_VECTOR:				VectorToBinary(GetStringVector(), fmt, result);					break;
		case ST_BOOLEAN_VECTOR:				VectorToBinary(GetBooleanVector(), fmt, result);				break;

		case ST_UNSUPPORTED:
		default:
		{
			stringstream msg;
			msg << "Cannot convert type " << DescribeStorageType(stype) << " to binary";
			throw runtime_error(msg.str());
		}

		}

		break;
	}

	default:
	{
		stringstream msg;
		msg << "(ToBinary) Unexpected content algorithm " << ((int) ca);
		throw runtime_error(msg.str());
	}

	}
}

string EventPropertyValue::GetAsString() const
{
	stringstream stm;

	switch(GetStorageType())
	{
	case ST_UINT8:					stm << GetUInt8();							break;
	case ST_INT8:					stm << GetInt8();							break;
	case ST_UINT16:					stm << GetUInt16();							break;
	case ST_INT16:					stm << GetInt16();							break;
	case ST_UINT32:					stm << GetUInt32();							break;
	case ST_INT32:					stm << GetInt32();							break;
	case ST_SINGLE_FLOAT:			stm << GetSingleFloat();					break;
	case ST_DOUBLE_FLOAT:			stm << GetDoubleFloat();					break;
	case ST_STRING:					stm << GetString();							break;
	case ST_BOOLEAN:				stm << (GetBoolean() ? "true" : "false");	break;
	default:																	break;
	}

	return stm.str();
}

static bool StrToBool(const string& str)
{
	bool result;

	if (iequals(str, "false") || iequals(str, "F") || iequals(str, "no") || iequals(str, "N"))
		result = false;
	else if (iequals(str, "true") || iequals(str, "T") || iequals(str, "yes") || iequals(str, "Y"))
		result = true;
	else
		result = !!lexical_cast<int>(str);

	return result;
}

void EventPropertyValue::SetAsString(StorageType stype, const string& newValue)
{
	switch(stype)
	{
	case ST_UINT8:				SetUInt8(lexical_cast<UInt8>(newValue));				break;
	case ST_INT8:				SetInt8(lexical_cast<Int8>(newValue));					break;
	case ST_UINT16:				SetUInt16(lexical_cast<UInt16>(newValue));				break;
	case ST_INT16:				SetUInt16(lexical_cast<Int16>(newValue));				break;
	case ST_UINT32:				SetUInt32(lexical_cast<UInt32>(newValue));				break;
	case ST_INT32:				SetInt32(lexical_cast<Int32>(newValue));				break;
	case ST_SINGLE_FLOAT:		SetSingleFloat(lexical_cast<SingleFloat>(newValue));	break;
	case ST_DOUBLE_FLOAT:		SetDoubleFloat(lexical_cast<DoubleFloat>(newValue));	break;
	case ST_STRING:				SetString(newValue);									break;
	case ST_BOOLEAN:			SetBoolean(StrToBool(newValue));						break;
#if 0
	case ST_UINT8_VECTOR:
	case ST_INT8_VECTOR:
	case ST_UINT16_VECTOR:
	case ST_INT16_VECTOR:
	case ST_UINT32_VECTOR:
	case ST_INT32_VECTOR:
	case ST_SINGLE_FLOAT_VECTOR:
	case ST_DOUBLE_FLOAT_VECTOR:
	case ST_STRING_VECTOR:
	case ST_BOOLEAN_VECTOR:
#endif

	default:

		throw invalid_argument("Unsupported storage type for SetAsString");
	}
}

template<typename T>
void load2(boost::archive::xml_iarchive& ar, T& tval)
{
	ar >> make_nvp("value", tval);
}

void EventPropertyValue::load(boost::archive::xml_iarchive& ar, const unsigned int version)
{
	string ststr;
	ar >> make_nvp("storageType", ststr);

	StorageType resultingType;
	FromString(ststr, resultingType);

	switch(resultingType)
	{
	case ST_UINT8:					{ UInt8 val; 				load2(ar, val); SetUInt8(val);				break; }
	case ST_INT8:					{ Int8 val; 				load2(ar, val); SetInt8(val);				break; }
	case ST_UINT16:					{ UInt16 val; 				load2(ar, val); SetUInt16(val); 			break; }
	case ST_INT16:					{ Int16 val; 				load2(ar, val); SetInt16(val); 				break; }
	case ST_UINT32:					{ UInt32 val; 				load2(ar, val); SetUInt32(val); 			break; }
	case ST_INT32:					{ Int32 val; 				load2(ar, val); SetInt32(val); 				break; }
	case ST_SINGLE_FLOAT:			{ SingleFloat val; 			load2(ar, val); SetSingleFloat(val); 		break; }
	case ST_DOUBLE_FLOAT:			{ DoubleFloat val; 			load2(ar, val); SetDoubleFloat(val); 		break; }
	case ST_STRING:					{ String val; 				load2(ar, val); SetString(val); 			break; }
	case ST_BOOLEAN:				{ Boolean val; 				load2(ar, val); SetBoolean(val); 			break; }
	case ST_NULL:																							break;
	case ST_UNSUPPORTED:																					break;
	case ST_UINT8_VECTOR:			{ ByteArray val; 			load2(ar, val); SetByteArray(val); 			break; }
	case ST_INT8_VECTOR:			{ Int8Vector val; 			load2(ar, val); SetInt8Vector(val); 		break; }
	case ST_UINT16_VECTOR:			{ UInt16Vector val;			load2(ar, val); SetUInt16Vector(val); 		break; }
	case ST_INT16_VECTOR:			{ Int16Vector val;			load2(ar, val); SetInt16Vector(val); 		break; }
	case ST_UINT32_VECTOR:			{ UInt32Vector val; 		load2(ar, val); SetUInt32Vector(val); 		break; }
	case ST_INT32_VECTOR:			{ Int32Vector val; 			load2(ar, val); SetInt32Vector(val);		break; }
	case ST_SINGLE_FLOAT_VECTOR:	{ SingleFloatVector val; 	load2(ar, val); SetSingleFloatVector(val);	break; }
	case ST_DOUBLE_FLOAT_VECTOR:	{ DoubleFloatVector val; 	load2(ar, val); SetDoubleFloatVector(val);	break; }
	case ST_STRING_VECTOR:			{ StringVector val; 		load2(ar, val); SetStringVector(val);		break; }
	case ST_BOOLEAN_VECTOR:			{ BooleanVector val; 		load2(ar, val); SetBooleanVector(val);		break; }

	case ST_TYPE_MASK:
	case ST_VECTOR:
	{
		stringstream msg;
		msg << "Resulting type " << ((int) resultingType) << " unexpected";
		throw runtime_error(msg.str());
	}

	}
}

template<typename T> void save2(boost::archive::xml_oarchive& ar, const T& tval)
{
	ar << make_nvp("value", tval);
}

void EventPropertyValue::save(boost::archive::xml_oarchive& ar, const unsigned int version) const
{
	const StorageType stype = GetStorageType();
	string ststr = ToString(stype);
	ar << make_nvp("storageType", ststr);

	switch(stype)
	{
	case ST_UINT8:					{ UInt8 val = GetUInt8();								save2(ar, val);		break; }
	case ST_INT8:					{ Int8 val = GetInt8();									save2(ar, val);		break; }
	case ST_UINT16:					{ UInt16 val = GetUInt16();								save2(ar, val);		break; }
	case ST_INT16:					{ Int16 val = GetInt16();								save2(ar, val);		break; }
	case ST_UINT32:					{ UInt32 val = GetUInt32();								save2(ar, val);		break; }
	case ST_INT32:					{ Int32 val = GetInt32();								save2(ar, val);		break; }
	case ST_SINGLE_FLOAT:			{ SingleFloat val = GetSingleFloat();					save2(ar, val);		break; }
	case ST_DOUBLE_FLOAT:			{ DoubleFloat val = GetDoubleFloat();					save2(ar, val);		break; }
	case ST_STRING:					{ String val = GetString();								save2(ar, val);		break; }
	case ST_BOOLEAN:				{ Boolean val = GetBoolean();							save2(ar, val);		break; }
	case ST_NULL:																								break;
	case ST_UNSUPPORTED:																						break;
	case ST_UINT8_VECTOR:			{ ByteArrayPtr val = GetByteArray();					save2(ar, *val);	break; }
	case ST_INT8_VECTOR:			{ Int8VectorPtr val = GetInt8Vector();					save2(ar, *val);	break; }
	case ST_UINT16_VECTOR:			{ UInt16VectorPtr val = GetUInt16Vector();				save2(ar, *val);	break; }
	case ST_INT16_VECTOR:			{ Int16VectorPtr val = GetInt16Vector();				save2(ar, *val);	break; }
	case ST_UINT32_VECTOR:			{ UInt32VectorPtr val = GetUInt32Vector();				save2(ar, *val);	break; }
	case ST_INT32_VECTOR:			{ Int32VectorPtr val = GetInt32Vector();				save2(ar, *val);	break; }
	case ST_SINGLE_FLOAT_VECTOR:	{ SingleFloatVectorPtr val = GetSingleFloatVector();	save2(ar, *val);	break; }
	case ST_DOUBLE_FLOAT_VECTOR:	{ DoubleFloatVectorPtr val = GetDoubleFloatVector();	save2(ar, *val);	break; }
	case ST_STRING_VECTOR:			{ StringVectorPtr val = GetStringVector();				save2(ar, *val);	break; }
	case ST_BOOLEAN_VECTOR:			{ BooleanVectorPtr val = GetBooleanVector();			save2(ar, *val);	break; }

	case ST_TYPE_MASK:
	case ST_VECTOR:
	{
		stringstream msg;
		msg << "Storage type " << ((int) stype) << " unexpected";
		throw runtime_error(msg.str());
	}

	}
}

void EventPropertyValue::Load(XmlNode& node, const XmlNVPBase& nvp)
{
	string storageStr;
	LoadFromNode(node, XmlNVPBase("type", "type"), storageStr);

	StorageType resultingType;

	FromString(storageStr, resultingType);

	XmlNVPBase valueInfo("value", "value", nvp.GetFlags());

	switch(resultingType)
	{
	case ST_UINT8:					{ UInt8 val; 				LoadFromNode(node, valueInfo, val);						SetUInt8(val);				break; }
	case ST_INT8:					{ Int8 val; 				LoadFromNode(node, valueInfo, val); 					SetInt8(val);				break; }
	case ST_UINT16:					{ UInt16 val; 				LoadFromNode(node, valueInfo, val); 					SetUInt16(val); 			break; }
	case ST_INT16:					{ Int16 val; 				LoadFromNode(node, valueInfo, val);						SetInt16(val); 				break; }
	case ST_UINT32:					{ UInt32 val; 				LoadFromNode(node, valueInfo, val); 					SetUInt32(val); 			break; }
	case ST_INT32:					{ Int32 val; 				LoadFromNode(node, valueInfo, val); 					SetInt32(val); 				break; }
	case ST_SINGLE_FLOAT:			{ SingleFloat val; 			LoadFromNode(node, valueInfo, val); 					SetSingleFloat(val); 		break; }
	case ST_DOUBLE_FLOAT:			{ DoubleFloat val; 			LoadFromNode(node, valueInfo, val); 					SetDoubleFloat(val); 		break; }
	case ST_STRING:					{ String val; 				LoadFromNode(node, valueInfo, val);						SetString(val); 			break; }

	case ST_BOOLEAN:
	{
		Boolean val;
		XmlBoolean xb(val);

		LoadFromNode(node, valueInfo, xb);
		SetBoolean(val);
		break;
	}

	case ST_NULL:																																	break;
	case ST_UNSUPPORTED:																															break;
	case ST_UINT8_VECTOR:			{ ByteArray val;			LoadFromNode(node, valueInfo, val); 					SetByteArray(val);			break; }
	case ST_INT8_VECTOR:			{ Int8Vector val;			LoadFromNode(node, valueInfo, val); 					SetInt8Vector(val); 		break; }
	case ST_UINT16_VECTOR:			{ UInt16Vector val;			LoadFromNode(node, valueInfo, val);						SetUInt16Vector(val); 		break; }
	case ST_INT16_VECTOR:			{ Int16Vector val;			LoadFromNode(node, valueInfo, val); 					SetInt16Vector(val); 		break; }
	case ST_UINT32_VECTOR:			{ UInt32Vector val;			LoadFromNode(node, valueInfo, val); 					SetUInt32Vector(val); 		break; }
	case ST_INT32_VECTOR:			{ Int32Vector val;			LoadFromNode(node, valueInfo, val); 					SetInt32Vector(val); 		break; }
	case ST_SINGLE_FLOAT_VECTOR:	{ SingleFloatVector val;	LoadFromNode(node, valueInfo, val); 					SetSingleFloatVector(val); 	break; }
	case ST_DOUBLE_FLOAT_VECTOR:	{ DoubleFloatVector val;	LoadFromNode(node, valueInfo, val); 					SetDoubleFloatVector(val); 	break; }
	case ST_STRING_VECTOR:			{ StringVector val;			LoadFromNode(node, valueInfo, val); 					SetStringVector(val); 		break; }

	case ST_BOOLEAN_VECTOR:
	{
		BooleanVector val;
		XmlBooleanVector xbv(val);

		LoadFromNode(node, valueInfo, xbv);
		SetBooleanVector(val);
		break;
	}

	case ST_TYPE_MASK:
	case ST_VECTOR:
	{
		stringstream msg;
		msg << "Resulting type " << ((int) resultingType) << " unexpected";
		throw runtime_error(msg.str());
	}

	}
}

void EventPropertyValue::Save(XmlNode& node, const XmlNVPBase& nvp) const
{
	const StorageType stype = GetStorageType();
	string storageStr = ToString(stype);

	SaveToNode(node, XmlNVPBase("type", "type"), storageStr);
	XmlNVPBase valueInfo("value", "value", nvp.GetFlags());

	switch(stype)
	{
	case ST_UINT8:					{ UInt8 val = GetUInt8();								SaveToNode(node, valueInfo, val);						break; }
	case ST_INT8:					{ Int8 val = GetInt8();									SaveToNode(node, valueInfo, val);						break; }
	case ST_UINT16:					{ UInt16 val = GetUInt16();								SaveToNode(node, valueInfo, val);						break; }
	case ST_INT16:					{ Int16 val = GetInt16();								SaveToNode(node, valueInfo, val);						break; }
	case ST_UINT32:					{ UInt32 val = GetUInt32();								SaveToNode(node, valueInfo, val);						break; }
	case ST_INT32:					{ Int32 val = GetInt32();								SaveToNode(node, valueInfo, val);						break; }
	case ST_SINGLE_FLOAT:			{ SingleFloat val = GetSingleFloat();					SaveToNode(node, valueInfo, val);						break; }
	case ST_DOUBLE_FLOAT:			{ DoubleFloat val = GetDoubleFloat();					SaveToNode(node, valueInfo, val);						break; }
	case ST_STRING:					{ String val = GetString();								SaveToNode(node, valueInfo, val);						break; }
	case ST_BOOLEAN:				{ Boolean val = GetBoolean();							SaveToNode(node, valueInfo, XmlBoolean(val));			break; }
	case ST_NULL:																																	break;
	case ST_UNSUPPORTED:																															break;
	case ST_UINT8_VECTOR:			{ ByteArrayPtr val = GetByteArray();					SaveToNode(node, valueInfo, *val);						break; }
	case ST_INT8_VECTOR:			{ Int8VectorPtr val = GetInt8Vector();					SaveToNode(node, valueInfo, *val);						break; }
	case ST_UINT16_VECTOR:			{ UInt16VectorPtr val = GetUInt16Vector();				SaveToNode(node, valueInfo, *val);						break; }
	case ST_INT16_VECTOR:			{ Int16VectorPtr val = GetInt16Vector();				SaveToNode(node, valueInfo, *val);						break; }
	case ST_UINT32_VECTOR:			{ UInt32VectorPtr val = GetUInt32Vector();				SaveToNode(node, valueInfo, *val);						break; }
	case ST_INT32_VECTOR:			{ Int32VectorPtr val = GetInt32Vector();				SaveToNode(node, valueInfo, *val);						break; }
	case ST_SINGLE_FLOAT_VECTOR:	{ SingleFloatVectorPtr val = GetSingleFloatVector();	SaveToNode(node, valueInfo, *val);						break; }
	case ST_DOUBLE_FLOAT_VECTOR:	{ DoubleFloatVectorPtr val = GetDoubleFloatVector();	SaveToNode(node, valueInfo, *val);						break; }
	case ST_STRING_VECTOR:			{ StringVectorPtr val = GetStringVector();				SaveToNode(node, valueInfo, *val);						break; }
	case ST_BOOLEAN_VECTOR:			{ BooleanVectorPtr val = GetBooleanVector();			SaveToNode(node, valueInfo, XmlBooleanVector(*val));	break; }

	case ST_TYPE_MASK:
	case ST_VECTOR:
	{
		stringstream msg;
		msg << "Storage type " << ((int) stype) << " unexpected";
		throw runtime_error(msg.str());
	}

	}
}

ostream& operator<<(ostream& stm, const EventPropertyValue& epv)
{
	epv.Describe(stm);
	return stm;
}

}
}
