/*******************************************************************************
 * povmscpp.cpp
 *
 * This module contains the C++ interface version of povms.cpp
 *
 * ---------------------------------------------------------------------------
 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
 *
 * POV-Ray is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * POV-Ray is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------------
 * POV-Ray is based on the popular DKB raytracer version 2.12.
 * DKBTrace was originally written by David K. Buck.
 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
 * ---------------------------------------------------------------------------
 * $File: //depot/public/povray/3.x/source/base/povmscpp.cpp $
 * $Revision: #1 $
 * $Change: 6069 $
 * $DateTime: 2013/11/06 11:59:40 $
 * $Author: chrisc $
 *******************************************************************************/

// configbase.h must always be the first POV file included within base *.cpp files
#include "configbase.h"

#include "povmscpp.h"

#include "zlib.h"

// this must be the last file included
#include "base/povdebug.h"

#include <stdlib.h>
#include <string.h>

const POVMSType kPOVMSRawStreamEncoding = 'RAWS';
const POVMSType kPOVMSGZipStreamEncoding = 'GZIP';

POVMSUCS2String POVMS_ASCIItoUCS2String(const char *s)
{
	POVMSUCS2String r;
	unsigned char ch;

	if(s != NULL)
	{
		while(*s != 0)
		{
			ch = *s++;
			r += (POVMSUCS2)(ch);
		}
	}

	return r;
}

std::string POVMS_UCS2toASCIIString(const POVMSUCS2String& s)
{
	std::string r;

	for(std::size_t i = 0; i < s.length(); i++)
	{
		if(s[i] >= 256)
			r += ' ';
		else
			r += (char)(s[i]);
	}

	return r;
}

/*****************************************************************************
*
* CLASS
*   POVMS_Container
*   
* DESCRIPTION
*   Base class for all other POVMS classes.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_Container::POVMS_Container()
{
	data.type = kPOVMSType_Null;
	data.size = 0;
	data.ptr = NULL;
}

POVMS_Container::~POVMS_Container()
{
	// do nothing for now
}

POVMSType POVMS_Container::Type() const
{
	return data.type;
}

size_t POVMS_Container::Size() const
{
	return data.size;
}

bool POVMS_Container::IsNull() const
{
	return (data.type == kPOVMSType_Null);
}

void POVMS_Container::DetachData()
{
	data.type = kPOVMSType_Null;
	data.size = 0;
	data.ptr = NULL;
}


/*****************************************************************************
*
* CLASS
*   POVMS_Attribute
*   
* DESCRIPTION
*   Class handling POVMSAttribute.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_Attribute::POVMS_Attribute()
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Attribute::POVMS_Attribute(const char *str)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_CString, reinterpret_cast<const void *>(str), strlen(str) + 1);
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(const POVMSUCS2 *str)
{
	int len;
	int err;

	for(len = 0; str[len] != 0; len++) { }

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_UCS2String, reinterpret_cast<const void *>(str), (len + 1) * 2);
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(POVMSInt value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_Int, (void *)(&value), sizeof(POVMSLong));
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(POVMSLong value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_Long, (void *)(&value), sizeof(POVMSLong));
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(POVMSFloat value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_Float, (void *)(&value), sizeof(POVMSFloat));
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(bool b)
{
	POVMSBool value = (POVMSBool)b;
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_Bool, (void *)(&value), sizeof(POVMSBool));
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(POVMSType value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_Type, (void *)(&value), sizeof(POVMSType));
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(std::vector<POVMSInt>& value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_VectorInt, (void *)(&value[0]), sizeof(POVMSInt) * value.size());
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(std::vector<POVMSLong>& value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_VectorLong, (void *)(&value[0]), sizeof(POVMSLong) * value.size());
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(std::vector<POVMSFloat>& value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_VectorFloat, (void *)(&value[0]), sizeof(POVMSFloat) * value.size());
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(std::vector<POVMSType>& value)
{
	int err;

	err = POVMSAttr_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttr_Set(&data, kPOVMSType_VectorType, (void *)(&value[0]), sizeof(POVMSType) * value.size());
	if(err != pov_base::kNoErr)
	{
		(void)POVMSAttr_Delete(&data);
		throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Attribute::POVMS_Attribute(POVMSAttribute& convert)
{
	data = convert;
}

POVMS_Attribute::POVMS_Attribute(const POVMS_Attribute& source)
{
	int err;

	err = POVMSAttr_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Attribute::~POVMS_Attribute()
{
	int err;

	err = POVMSAttr_Delete(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Attribute& POVMS_Attribute::operator=(const POVMS_Attribute& source)
{
	int err;

	err = POVMSAttr_Delete(&data);
	if(err == pov_base::kNoErr)
		err = POVMSAttr_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return *this;
}

void POVMS_Attribute::Get(POVMSType type, void *data, int *maxdatasize)
{
	int err;

	err = POVMSAttr_Get(&this->data, type, data, maxdatasize);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Attribute::Set(POVMSType type, const void *data, int datasize)
{
	int err;

	err = POVMSAttr_Set(&this->data, type, data, datasize);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

int POVMS_Attribute::GetStringLength() const // Note: Includes trailing \0 character code!
{
	return Size();
}

int POVMS_Attribute::GetString(char *str, int maxlen)
{
	Get(kPOVMSType_CString, (void *)str, &maxlen);

	return maxlen;
}

std::string POVMS_Attribute::GetString()
{
	int len = Size();

	char *strptr = new char[len];

	try
	{
		Get(kPOVMSType_CString, (void *)strptr, &len);

		std::string str(strptr);

		delete[] strptr;

		return str;
	}
	catch(pov_base::Exception&)
	{
		delete[] strptr;
		throw;
	}

	return std::string();
}

int POVMS_Attribute::GetUCS2StringLength() const // Note: Includes trailing \0 character code!
{
	return Size() / 2;
}

int POVMS_Attribute::GetUCS2String(POVMSUCS2 *str, int maxlen)
{
	maxlen /= 2;

	Get(kPOVMSType_UCS2String, (void *)str, &maxlen);

	return maxlen / 2;
}

POVMSUCS2String POVMS_Attribute::GetUCS2String()
{
	int len = Size();

	POVMSUCS2 *strptr = new POVMSUCS2[len / 2];

	try
	{
		Get(kPOVMSType_UCS2String, (void *)strptr, &len);

		POVMSUCS2String str(strptr);

		delete[] strptr;

		return str;
	}
	catch(pov_base::Exception&)
	{
		delete[] strptr;
		throw;
	}

	return POVMSUCS2String();
}

POVMSInt POVMS_Attribute::GetInt()
{
	POVMSInt result;
	int len = sizeof(result);

	Get(kPOVMSType_Int, (void *)&result, &len);

	return result;
}

POVMSLong POVMS_Attribute::GetLong()
{
	POVMSLong result;
	int len = sizeof(result);

	Get(kPOVMSType_Long, (void *)&result, &len);

	return result;
}

POVMSFloat POVMS_Attribute::GetFloat()
{
	POVMSFloat result;
	int len = sizeof(result);

	Get(kPOVMSType_Float, (void *)&result, &len);

	return result;
}

POVMSBool POVMS_Attribute::GetBool()
{
	POVMSBool result;
	int len = sizeof(result);

	Get(kPOVMSType_Bool, (void *)&result, &len);

	return result;
}

POVMSType POVMS_Attribute::GetType()
{
	POVMSType result;
	int len = sizeof(result);

	Get(kPOVMSType_Type, (void *)&result, &len);

	return result;
}

std::vector<POVMSInt> POVMS_Attribute::GetIntVector()
{
	std::vector<POVMSInt> result;
	result.resize(GetVectorSize());
	int len = result.size() * sizeof(POVMSInt);

	Get(kPOVMSType_VectorInt, (void *)&result[0], &len);

	return result;
}

std::vector<POVMSLong> POVMS_Attribute::GetLongVector()
{
	std::vector<POVMSLong> result;
	result.resize(GetVectorSize());
	int len = result.size() * sizeof(POVMSLong);

	Get(kPOVMSType_VectorLong, (void *)&result[0], &len);

	return result;
}

std::vector<POVMSFloat> POVMS_Attribute::GetFloatVector()
{
	std::vector<POVMSFloat> result;
	result.resize(GetVectorSize());
	int len = result.size() * sizeof(POVMSFloat);

	Get(kPOVMSType_VectorFloat, (void *)&result[0], &len);

	return result;
}

std::vector<POVMSType> POVMS_Attribute::GetTypeVector()
{
	std::vector<POVMSType> result;
	result.resize(GetVectorSize());
	int len = result.size() * sizeof(POVMSType);

	Get(kPOVMSType_VectorType, (void *)&result[0], &len);

	return result;
}

int POVMS_Attribute::GetVectorSize() const
{
	switch(Type())
	{
		case kPOVMSType_VectorInt:
			return Size() / sizeof(POVMSInt);
		case kPOVMSType_VectorLong:
			return Size() / sizeof(POVMSLong);
		case kPOVMSType_VectorFloat:
			return Size() / sizeof(POVMSFloat);
		case kPOVMSType_VectorType:
			return Size() / sizeof(POVMSType);
		default:
			throw POV_EXCEPTION_CODE(pov_base::kCannotHandleDataErr);
	}

	return 0;
}


/*****************************************************************************
*
* CLASS
*   POVMS_List
*   
* DESCRIPTION
*   Class handling POVMSAttributeList.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_List::POVMS_List()
{
	int err;

	err = POVMSAttrList_New(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_List::POVMS_List(POVMSAttributeList& convert)
{
	data = convert;
}

POVMS_List::POVMS_List(const POVMS_List& source)
{
	int err;

	err = POVMSAttrList_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_List::~POVMS_List()
{
	int err;

	err = POVMSAttrList_Delete(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_List& POVMS_List::operator=(const POVMS_List& source)
{
	int err;

	err = POVMSAttrList_Delete(&data);
	if(err == pov_base::kNoErr)
		err = POVMSAttrList_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return *this;
}

void POVMS_List::Append(POVMS_Attribute& item)
{
	int err;

	err = POVMSAttrList_Append(&data, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::Append(POVMS_List& item)
{
	int err;

	err = POVMSAttrList_Append(&data, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::Append(POVMS_Object& item)
{
	int err;

	err = POVMSAttrList_Append(&data, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::AppendN(int cnt, POVMS_Attribute& item)
{
	for(; cnt > 0; cnt--) // TODO - make more efficient
		Append(item);
}

void POVMS_List::AppendN(int cnt, POVMS_List& item)
{
	for(; cnt > 0; cnt--) // TODO - make more efficient
		Append(item);
}

void POVMS_List::AppendN(int cnt, POVMS_Object& item)
{
	for(; cnt > 0; cnt--) // TODO - make more efficient
		Append(item);
}

void POVMS_List::GetNth(int index, POVMS_Attribute& item)
{
	int err;

	err = POVMSAttr_Delete(&item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttrList_GetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_List::GetNth(int index, POVMS_List& item)
{
	int err;

	err = POVMSAttrList_Delete(&item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttrList_GetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_List::GetNth(int index, POVMS_Object& item)
{
	int err;

	err = POVMSObject_Delete(&item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSAttrList_GetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_List::SetNth(int index, POVMS_Attribute& item)
{
	int err;

	err = POVMSAttrList_SetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::SetNth(int index, POVMS_List& item)
{
	int err;

	err = POVMSAttrList_SetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::SetNth(int index, POVMS_Object& item)
{
	int err;

	err = POVMSAttrList_SetNth(&data, index, &item.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	item.DetachData();
}

void POVMS_List::RemoveNth(int index)
{
	int err;

	err = POVMSAttrList_RemoveNth(&data, index);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_List::Clear()
{
	int err;

	err = POVMSAttrList_Clear(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

int POVMS_List::GetListSize()
{
	int len = 0;
	int err;

	err = POVMSAttrList_Count(&data, &len);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return len;
}


/*****************************************************************************
*
* CLASS
*   POVMS_Object
*   
* DESCRIPTION
*   Class handling POVMSObject.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_Object::POVMS_Object()
{
	// Null object!
}

POVMS_Object::POVMS_Object(POVMSType objclass)
{
	int err;

	err = POVMSObject_New(&data, objclass);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Object::POVMS_Object(POVMSObject& convert)
{
	data = convert;
}

POVMS_Object::POVMS_Object(POVMSObjectPtr convert)
{
	if(convert != NULL)
		data = *convert;
}

POVMS_Object::POVMS_Object(const POVMS_Object& source)
{
	if(source.IsNull() == false)
	{
		int err;

		err = POVMSObject_Copy(&source.data, &data);
		if(err != pov_base::kNoErr)
			throw POV_EXCEPTION_CODE(err);
	}
}

POVMS_Object::~POVMS_Object()
{
	int err;

	err = POVMSObject_Delete(&data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Object& POVMS_Object::operator=(const POVMS_Object& source)
{
	int err;

	err = POVMSObject_Delete(&data);
	if((err == pov_base::kNoErr) && (IsNull() == false))
		err = POVMSObject_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return *this;
}

void POVMS_Object::Get(POVMSType key, POVMS_Attribute& attr)
{
	int err;

	err = POVMSAttr_Delete(&attr.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSObject_Get(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::Get(POVMSType key, POVMS_List& attr)
{
	int err;

	err = POVMSAttrList_Delete(&attr.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSObject_Get(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::Get(POVMSType key, POVMS_Object& attr)
{
	int err;

	err = POVMSObject_Delete(&attr.data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
	err = POVMSObject_Get(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::Set(POVMSType key, POVMS_Attribute& attr)
{
	int err;

	err = POVMSObject_Set(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	attr.DetachData();
}

void POVMS_Object::Set(POVMSType key, POVMS_List& attr)
{
	int err;

	err = POVMSObject_Set(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	attr.DetachData();
}

void POVMS_Object::Set(POVMSType key, POVMS_Object& attr)
{
	int err;

	err = POVMSObject_Set(&data, &attr.data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	attr.DetachData();
}

void POVMS_Object::Remove(POVMSType key)
{
	int err;

	err = POVMSObject_Remove(&data, key);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

bool POVMS_Object::Exist(POVMSType key)
{
	return (POVMSObject_Exist(&data, key) == pov_base::kNoErr);
}

void POVMS_Object::Merge(POVMS_Object& source)
{
	int err;

	err = POVMSObject_Merge(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

const POVMSObject& POVMS_Object::operator*() const
{
	return *((const POVMSObject*)(&data));
}

const POVMSObject* POVMS_Object::operator->() const
{
	return (const POVMSObject*)(&data);
}

POVMSObject POVMS_Object::operator()()
{
	POVMS_Object tc(*this);
	POVMSObject t = *((POVMSObjectPtr)(&tc.data));
	tc.DetachData();
	return t;
}

void POVMS_Object::SetString(POVMSType key, const char *str)
{
	int err;

	err = POVMSUtil_SetString(&data, key, str);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetUCS2String(POVMSType key, const POVMSUCS2 *str)
{
	int err;

	err = POVMSUtil_SetUCS2String(&data, key, str);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetInt(POVMSType key, POVMSInt value)
{
	int err;

	err = POVMSUtil_SetInt(&data, key, value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetLong(POVMSType key, POVMSLong value)
{
	int err;

	err = POVMSUtil_SetLong(&data, key, value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetFloat(POVMSType key, POVMSFloat value)
{
	int err;

	err = POVMSUtil_SetFloat(&data, key, value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetBool(POVMSType key, POVMSBool value)
{
	int err;

	err = POVMSUtil_SetBool(&data, key, value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetType(POVMSType key, POVMSType value)
{
	int err;

	err = POVMSUtil_SetType(&data, key, value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Object::SetIntVector(POVMSType key, std::vector<POVMSInt>& value)
{
	POVMS_Attribute attr(value);

	Set(key, attr);
}

void POVMS_Object::SetLongVector(POVMSType key, std::vector<POVMSLong>& value)
{
	POVMS_Attribute attr(value);

	Set(key, attr);
}

void POVMS_Object::SetFloatVector(POVMSType key, std::vector<POVMSFloat>& value)
{
	POVMS_Attribute attr(value);

	Set(key, attr);
}

void POVMS_Object::SetTypeVector(POVMSType key, std::vector<POVMSType>& value)
{
	POVMS_Attribute attr(value);

	Set(key, attr);
}

int POVMS_Object::GetStringLength(POVMSType key)
{
	int len = 0;
	int err;

	err = POVMSUtil_GetStringLength(&data, key, &len);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return len;
}

int POVMS_Object::GetString(POVMSType key, char *str, int maxlen)
{
	int err;

	err = POVMSUtil_GetString(&data, key, str, &maxlen);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return maxlen;
}

std::string POVMS_Object::GetString(POVMSType key)
{
	int len = 0;
	int err;

	err = POVMSUtil_GetStringLength(&data, key, &len);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	char *strptr = new char[len];

	err = POVMSUtil_GetString(&data, key, strptr, &len);
	if(err != pov_base::kNoErr)
	{
		delete[] strptr;
		throw POV_EXCEPTION_CODE(err);
	}

	std::string str(strptr);

	delete[] strptr;

	return str;
}

int POVMS_Object::GetUCS2StringLength(POVMSType key)
{
	int len = 0;
	int err;

	err = POVMSUtil_GetUCS2StringLength(&data, key, &len);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return len;
}

int POVMS_Object::GetUCS2String(POVMSType key, POVMSUCS2 *str, int maxlen)
{
	int err;

	err = POVMSUtil_GetUCS2String(&data, key, str, &maxlen);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return maxlen;
}

POVMSUCS2String POVMS_Object::GetUCS2String(POVMSType key)
{
	int len = 0;
	int err;

	err = POVMSUtil_GetUCS2StringLength(&data, key, &len);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	POVMSUCS2 *strptr = new POVMSUCS2[len];

	err = POVMSUtil_GetUCS2String(&data, key, strptr, &len);
	if(err != pov_base::kNoErr)
	{
		delete[] strptr;
		throw POV_EXCEPTION_CODE(err);
	}

	POVMSUCS2String str(strptr);

	delete[] strptr;

	return str;
}

POVMSInt POVMS_Object::GetInt(POVMSType key)
{
	POVMSInt value;
	int err;

	err = POVMSUtil_GetInt(&data, key, &value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return value;
}

POVMSLong POVMS_Object::GetLong(POVMSType key)
{
	POVMSLong value;
	int err;

	err = POVMSUtil_GetLong(&data, key, &value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return value;
}

POVMSFloat POVMS_Object::GetFloat(POVMSType key)
{
	POVMSFloat value;
	int err;

	err = POVMSUtil_GetFloat(&data, key, &value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return value;
}

POVMSBool POVMS_Object::GetBool(POVMSType key)
{
	POVMSBool value;
	int err;

	err = POVMSUtil_GetBool(&data, key, &value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return value;
}

POVMSType POVMS_Object::GetType(POVMSType key)
{
	POVMSType value;
	int err;

	err = POVMSUtil_GetType(&data, key, &value);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return value;
}

std::vector<POVMSInt> POVMS_Object::GetIntVector(POVMSType key)
{
	POVMS_Attribute attr;

	Get(key, attr);

	return attr.GetIntVector();
}

std::vector<POVMSLong> POVMS_Object::GetLongVector(POVMSType key)
{
	POVMS_Attribute attr;

	Get(key, attr);

	return attr.GetLongVector();
}

std::vector<POVMSFloat> POVMS_Object::GetFloatVector(POVMSType key)
{
	POVMS_Attribute attr;

	Get(key, attr);

	return attr.GetFloatVector();
}

std::vector<POVMSType> POVMS_Object::GetTypeVector(POVMSType key)
{
	POVMS_Attribute attr;

	Get(key, attr);

	return attr.GetTypeVector();
}

std::string POVMS_Object::TryGetString(POVMSType key, const char *alt)
{
	if(Exist(key) == true)
		return GetString(key);

	return std::string(alt);
}

std::string POVMS_Object::TryGetString(POVMSType key, const std::string& alt)
{
	if(Exist(key) == true)
		return GetString(key);

	return alt;
}

POVMSUCS2String POVMS_Object::TryGetUCS2String(POVMSType key, const char *alt)
{
	if(Exist(key) == true)
		return GetUCS2String(key);

	return POVMS_ASCIItoUCS2String(alt);
}

POVMSUCS2String POVMS_Object::TryGetUCS2String(POVMSType key, const POVMSUCS2String& alt)
{
	if(Exist(key) == true)
		return GetUCS2String(key);

	return alt;
}

POVMSInt POVMS_Object::TryGetInt(POVMSType key, POVMSInt alt)
{
	if(Exist(key) == true)
		return GetInt(key);

	return alt;
}

POVMSLong POVMS_Object::TryGetLong(POVMSType key, POVMSLong alt)
{
	if(Exist(key) == true)
		return GetLong(key);

	return alt;
}

POVMSFloat POVMS_Object::TryGetFloat(POVMSType key, POVMSFloat alt)
{
	if(Exist(key) == true)
		return GetFloat(key);

	return alt;
}

POVMSBool POVMS_Object::TryGetBool(POVMSType key, POVMSBool alt)
{
	if(Exist(key) == true)
		return GetBool(key);

	return alt;
}

POVMSType POVMS_Object::TryGetType(POVMSType key, POVMSType alt)
{
	if(Exist(key) == true)
		return GetType(key);

	return alt;
}

void POVMS_Object::Read(InputStream& stream, bool continued, bool headeronly)
{
	POVMSStream headerstream[16];
	POVMSStream *objectstream = NULL;
	POVMSStream *compressedstream = NULL;
	int err = pov_base::kNoErr;
	int maxheadersize = 0;
	int datasize = 0;

	try
	{
		err = POVMSObject_Delete(&data);
		if(err != pov_base::kNoErr)
			throw POV_EXCEPTION_CODE(err);

		if(continued == false)
		{
			char header[8];
			POVMSInt version = 0;

			if(!stream.read((void *)headerstream, 12))
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

			datasize = 0;
			maxheadersize = 12; // header

			datasize += POVMSStream_ReadString(header, headerstream + datasize, 8, &maxheadersize);                // header       8 byte
			if(!((header[0] == 'P') && (header[1] == 'O') && (header[2] == 'V') && (header[3] == 'R') &&
			     (header[4] == 'A') && (header[5] == 'Y') && (header[6] == 'M') && (header[7] == 'S')))
				throw POV_EXCEPTION_CODE(pov_base::kVersionErr);

			datasize += POVMSStream_ReadInt(&version, headerstream + datasize, &maxheadersize);                    // version      4 byte
			if(version != 0x0370)
				throw POV_EXCEPTION_CODE(pov_base::kVersionErr);
		}

		if(headeronly == false)
		{
			POVMSInt objectsize = 0;
			POVMSType encoding = kPOVMSRawStreamEncoding;

			if(!stream.read((void *)headerstream, 8))
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

			datasize = 0;
			maxheadersize = 8; // header

			datasize += POVMSStream_ReadInt(&objectsize, headerstream + datasize, &maxheadersize);                 // data size    4 byte
			if(objectsize == 0)
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

			datasize += POVMSStream_ReadType(&encoding, headerstream + datasize, &maxheadersize);                  // encoding     4 byte
			if(encoding == kPOVMSRawStreamEncoding)
			{
				objectstream = new POVMSStream[objectsize];

				if(!stream.read((void *)objectstream, objectsize))                                                 // object       x byte
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

				if(POVMSStream_Read(&data, objectstream, &objectsize) == 0)
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);
			}
			else if(encoding == kPOVMSGZipStreamEncoding)
			{
				int compressedsize = objectsize;

				datasize = 0;
				maxheadersize = 4; // header

				if(!stream.read((void *)headerstream, 4))
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

				datasize += POVMSStream_ReadInt(&objectsize, headerstream + datasize, &maxheadersize);             // object size  4 byte
				if(objectsize == 0)
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

				compressedstream = new POVMSStream[compressedsize];
				objectstream = new POVMSStream[objectsize];

				if(!stream.read((void *)compressedstream, compressedsize))                                         // data         x byte
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

				// uncompress stream data
				uLongf destlen = (uLongf)objectsize;
				if(uncompress((Bytef *)(objectstream), &destlen, (Bytef *)(compressedstream), (uLongf)(compressedsize)) != Z_OK)
					throw POV_EXCEPTION_CODE(pov_base::kCannotHandleDataErr);

				if(POVMSStream_Read(&data, objectstream, &objectsize) == 0)
					throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);
			}
			else
				throw POV_EXCEPTION_CODE(pov_base::kCannotHandleDataErr);
		}

		if(objectstream != NULL)
			delete[] objectstream;
		objectstream = NULL;

		if(compressedstream != NULL)
			delete[] compressedstream;
		compressedstream = NULL;
	}
	catch(...)
	{
		if(objectstream != NULL)
			delete[] objectstream;

		if(compressedstream != NULL)
			delete[] compressedstream;

		throw;
	}
}

void POVMS_Object::Write(OutputStream& stream, bool append, bool compress)
{
	POVMSType encoding = kPOVMSRawStreamEncoding;
	POVMSStream headerstream[16];
	POVMSStream *objectstream = NULL;
	POVMSStream *compressedstream = NULL;
	int maxheadersize = 0;
	int maxobjectsize = 0;
	int objectsize = 0;
	int datasize = 0;

	try
	{
		objectsize = POVMSStream_Size(&data);
		if(objectsize == 0)
			throw POV_EXCEPTION_CODE(pov_base::kNullPointerErr);

		if(append == false)
		{
			datasize = 0;
			maxheadersize = 12; // header

			datasize += POVMSStream_WriteString("POVRAYMS", headerstream + datasize, &maxheadersize);              // header       8 byte
			datasize += POVMSStream_WriteInt(0x0370, headerstream + datasize, &maxheadersize);                     // version      4 byte

			if(!stream.write((void *)headerstream, datasize))
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);
		}

		objectstream = new POVMSStream[objectsize];
		maxobjectsize = objectsize;
		(void)POVMSStream_Write(&data, objectstream, &maxobjectsize);

#ifdef POVMS_COMPRESSION_ENABLED
		if(compress == true)
		{
			compressedstream = new POVMSStream[objectsize * 2];

			// compress stream data
			uLongf destlen = (uLongf)(objectsize * 2);
			if(compress2((Bytef *)(compressedstream), &destlen, (Bytef *)(objectstream), (uLongf)(objectsize), Z_BEST_COMPRESSION) != Z_OK)
				throw POV_EXCEPTION_CODE(pov_base::kCannotHandleDataErr);

			datasize = 0;
			maxheadersize = 12; // header

			datasize += POVMSStream_WriteInt((POVMSInt)(destlen), headerstream + datasize, &maxheadersize);        // data size    4 byte
			datasize += POVMSStream_WriteType(kPOVMSGZipStreamEncoding, headerstream + datasize, &maxheadersize);  // encoding     4 byte
			datasize += POVMSStream_WriteInt(objectsize, headerstream + datasize, &maxheadersize);                 // object size  4 byte

			if(!stream.write((void *)headerstream, datasize))
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

			if(!stream.write((void *)compressedstream, (int)(destlen)))                                            // data         x byte
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);
		}
		else
#endif
		{
			datasize = 0;
			maxheadersize = 8; // header

			datasize += POVMSStream_WriteInt(objectsize, headerstream + datasize, &maxheadersize);                 // object size  4 byte
			datasize += POVMSStream_WriteType(kPOVMSRawStreamEncoding, headerstream + datasize, &maxheadersize);   // encoding     4 byte

			if(!stream.write((void *)headerstream, datasize))
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);

			if(!stream.write((void *)objectstream, objectsize))                                                    // object       x byte
				throw POV_EXCEPTION_CODE(pov_base::kFileDataErr);
		}

		if(objectstream != NULL)
			delete[] objectstream;
		objectstream = NULL;

		if(compressedstream != NULL)
			delete[] compressedstream;
		compressedstream = NULL;
	}
	catch(...)
	{
		if(objectstream != NULL)
			delete[] objectstream;

		if(compressedstream != NULL)
			delete[] compressedstream;

		throw;
	}
}


/*****************************************************************************
*
* CLASS
*   POVMS_Message
*   
* DESCRIPTION
*   Class handling messages contained in POVMSObjects.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_Message::POVMS_Message()
{
	// Null object!
}

POVMS_Message::POVMS_Message(POVMSType objclass, POVMSType msgclass, POVMSType msgid) : POVMS_Object(objclass)
{
	int err;

	err = POVMSMsg_SetupMessage(&data, msgclass, msgid);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Message::POVMS_Message(POVMS_Object& convert, POVMSType msgclass, POVMSType msgid) : POVMS_Object(convert)
{
	int err;

	err = POVMSMsg_SetupMessage(&data, msgclass, msgid);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

POVMS_Message::POVMS_Message(POVMSObject& convert) : POVMS_Object(convert)
{
}

POVMS_Message::POVMS_Message(POVMSObjectPtr convert) : POVMS_Object(convert)
{
}

POVMS_Message::POVMS_Message(const POVMS_Message& source) : POVMS_Object(source)
{
}

POVMS_Message& POVMS_Message::operator=(const POVMS_Message& source)
{
	int err;

	err = POVMSObject_Delete(&data);
	if((err == pov_base::kNoErr) && (source.IsNull() == false))
		err = POVMSObject_Copy(&source.data, &data);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return *this;
}

POVMSType POVMS_Message::GetClass()
{
	POVMSType type;
	int err;

	err = POVMSMsg_GetMessageClass(&data, &type);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return type;
}

POVMSType POVMS_Message::GetIdentifier()
{
	POVMSType type;
	int err;

	err = POVMSMsg_GetMessageIdentifier(&data, &type);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return type;
}

POVMSAddress POVMS_Message::GetSourceAddress()
{
	POVMSAddress addr;
	int err;

	err = POVMSMsg_GetSourceAddress(&data, &addr);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return addr;
}

POVMSAddress POVMS_Message::GetDestinationAddress()
{
	POVMSAddress addr;
	int err;

	err = POVMSMsg_GetDestinationAddress(&data, &addr);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	return addr;
}

void POVMS_Message::SetSourceAddress(POVMSAddress addr)
{
	int err;

	err = POVMSMsg_SetSourceAddress(&data, addr);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}

void POVMS_Message::SetDestinationAddress(POVMSAddress addr)
{
	int err;

	err = POVMSMsg_SetDestinationAddress(&data, addr);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);
}


/*****************************************************************************
*
* CLASS
*   POVMS_MessageReceiver
*   
* DESCRIPTION
*   Class receiving messages.
*
* CHANGES
*   -
*
******************************************************************************/

POVMS_MessageReceiver::POVMS_MessageReceiver(POVMSContext contextref)
{
	context = contextref;
	receivers = NULL;
}

POVMS_MessageReceiver::~POVMS_MessageReceiver()
{
	while(receivers != NULL)
		RemoveNode(receivers);

	receivers = NULL;
	context = NULL;
}

void POVMS_MessageReceiver::Remove(POVMSType hclass, POVMSType hid)
{
	HandlerNode *nodeptr = NULL;

	for(nodeptr = receivers; nodeptr != NULL; nodeptr = nodeptr->next)
	{
		if((nodeptr->hclass == hclass) && ((nodeptr->hid == hid) || (hid == kPOVMSType_WildCard)))
		{
			RemoveNode(nodeptr);
			nodeptr = receivers;
		}
	}
}

int POVMS_MessageReceiver::ReceiveHandler(POVMSObjectPtr msg, POVMSObjectPtr result, int mode, void *privatedataptr)
{
	POVMS_MessageReceiver *self = (POVMS_MessageReceiver *)privatedataptr;
	HandlerNode *nodeptr = NULL;
	POVMSType hclass = kPOVMSType_Null;
	POVMSType hid = kPOVMSType_Null;
	int err = pov_base::kNoErr;

	if(self == NULL)
		err = pov_base::kParamErr;
	if(err == pov_base::kNoErr)
		err = POVMSMsg_GetMessageClass(msg, &hclass);
	if(err == pov_base::kNoErr)
		err = POVMSUtil_GetType(msg, kPOVMSMessageIdentID, &hid);
	for(nodeptr = self->receivers; nodeptr != NULL && err == pov_base::kNoErr; nodeptr = nodeptr->next)
	{
		if((nodeptr->hclass == hclass) && ((nodeptr->hid == hid) || (nodeptr->hid == kPOVMSType_WildCard)))
		{
			if(nodeptr->handleroo != NULL)
			{
				POVMS_Message result_obj(result);
				POVMS_Message msg_obj(msg);

				// Note: This try-catch block is only required because msg_obj.DetachData always has to be executed! [trf]
				try
				{
					nodeptr->handleroo->Call(msg_obj, result_obj, mode);
				}
				catch(...)
				{
					// result and msg no longer own their resources; if we don't clear them here,
					// we can get a double-free in a parent method when this method throws an exception.
					// an example of this is when create scene fails with an out-of-memory exception.
					memset(result, 0, sizeof(*result));
					memset(msg, 0, sizeof(*msg));

					msg_obj.DetachData();
					throw;
				}

				msg_obj.DetachData();

				if((result != NULL) && (result_obj.IsNull() == false))
					*result = result_obj();
			}
			else if(nodeptr->handler != NULL)
				nodeptr->handler->Call(msg, result, mode);
			else
				err = pov_base::kNullPointerErr;
		}
	}

	return err;
}

void POVMS_MessageReceiver::AddNodeFront(POVMSType hclass, POVMSType hid, HandlerOO *hooptr, Handler *hptr)
{
	HandlerNode *nodeptr = new HandlerNode;
	int err = pov_base::kNoErr;

	nodeptr->last = NULL;
	nodeptr->next = NULL;
	nodeptr->hclass = hclass;
	nodeptr->hid = hid;
	nodeptr->handleroo = hooptr;
	nodeptr->handler = hptr;

	err = POVMS_InstallReceiver(context, ReceiveHandler, hclass, hid, (void *)this);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	nodeptr->last = NULL;
	nodeptr->next = receivers;
	if(nodeptr->next != NULL)
		nodeptr->next->last = nodeptr;
	receivers = nodeptr;
}

void POVMS_MessageReceiver::AddNodeBack(POVMSType hclass, POVMSType hid, HandlerOO *hooptr, Handler *hptr)
{
	HandlerNode *nodeptr = new HandlerNode;
	HandlerNode *iptr = NULL;
	int err = pov_base::kNoErr;

	nodeptr->last = NULL;
	nodeptr->next = NULL;
	nodeptr->hclass = hclass;
	nodeptr->hid = hid;
	nodeptr->handleroo = hooptr;
	nodeptr->handler = hptr;

	err = POVMS_InstallReceiver(context, ReceiveHandler, hclass, hid, (void *)this);
	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	if(receivers == NULL)
	{
		nodeptr->last = NULL;
		nodeptr->next = NULL;
		if(nodeptr->next != NULL)
			nodeptr->next->last = nodeptr;
		receivers = nodeptr;
	}
	else
	{
		iptr = receivers;
		while(iptr->next != NULL)
			iptr = iptr->next;
		nodeptr->last = iptr;
		nodeptr->next = NULL;
		iptr->next = nodeptr;
	}
}

void POVMS_MessageReceiver::RemoveNode(HandlerNode *nodeptr)
{
	if(nodeptr != NULL)
	{
		(void)POVMS_RemoveReceiver(context, nodeptr->hclass, nodeptr->hid);

		if(nodeptr->last != NULL)
			nodeptr->last->next = nodeptr->next;
		if(nodeptr->next != NULL)
			nodeptr->next->last = nodeptr->last;
		if(receivers == nodeptr)
			receivers = nodeptr->next;

		if(nodeptr->handleroo != NULL)
			delete nodeptr->handleroo;
		if(nodeptr->handler != NULL)
			delete nodeptr->handler;

		delete nodeptr;
	}
}


/*****************************************************************************
*
* FUNCTION
*   POVMS_Send
*   
* DESCRIPTION
*   POVMS_SendMessage same as POVMS_Send in povms.cpp, but takes
*   only a POVMS_Message object as arguments and sends it using
*   kPOVMSSendMode_NoReply mode. Note that sending using this mode
*   does not require a POVMS context, which makes sending messages
*   from any thread really easy as long as no reply is needed.
*
* CHANGES
*   -
*
******************************************************************************/

void POVMS_SendMessage(POVMS_Message& msg)
{
	int err;

	err = POVMS_Send(NULL, &msg.data, NULL, kPOVMSSendMode_NoReply);

	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	msg.DetachData();
}


/*****************************************************************************
*
* FUNCTION
*   POVMS_Send
*   
* DESCRIPTION
*   POVMS_SendMessage same as POVMS_Send in povms.cpp, but takes
*   POVMS_Messages objects as arguments.
*
* CHANGES
*   -
*
******************************************************************************/

void POVMS_SendMessage(POVMSContext contextref, POVMS_Message& msg, POVMS_Message *result, int mode)
{
	int err;

	if(result != NULL)
		err = POVMS_Send(contextref, &msg.data, &result->data, mode);
	else
		err = POVMS_Send(contextref, &msg.data, NULL, mode);

	if(err != pov_base::kNoErr)
		throw POV_EXCEPTION_CODE(err);

	msg.DetachData();
}
