/*******************************************************************************
 * renderbackend.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/backend/control/renderbackend.cpp $
 * $Revision: #1 $
 * $Change: 6069 $
 * $DateTime: 2013/11/06 11:59:40 $
 * $Author: chrisc $
 *******************************************************************************/

// frame.h must always be the first POV file included (pulls in platform config)
#include "backend/frame.h"
#include "base/povms.h"
#include "base/povmscpp.h"
#include "base/povmsgid.h"
#include "base/pov_err.h"
#include "backend/povray.h"
#include "backend/control/renderbackend.h"
#include "backend/scene/scene.h"
#include "backend/scene/view.h"

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

namespace pov
{

using namespace pov_base;

POVMSContext RenderBackend::context = NULL;

RenderBackend::RenderBackend(POVMSContext ctx,  bool (*val)(POVMSAddress)) :
	POVMS_MessageReceiver(ctx),
	validateFrontendAddress(val),
	scenecounter(0),
	viewcounter(0)
{
	context = ctx;

	InstallFront(kPOVMsgClass_BackendControl, kPOVMsgIdent_CreateScene, this, &RenderBackend::CreateScene);
	InstallFront(kPOVMsgClass_BackendControl, kPOVMsgIdent_CloseScene, this, &RenderBackend::CloseScene);

	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_CreateView, this, &RenderBackend::CreateView);
	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_CloseView, this, &RenderBackend::CloseView);

	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_StartParser, this, &RenderBackend::StartParser);
	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_StopParser, this, &RenderBackend::StopParser);
	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_PauseParser, this, &RenderBackend::PauseParser);
	InstallFront(kPOVMsgClass_SceneControl, kPOVMsgIdent_ResumeParser, this, &RenderBackend::ResumeParser);

	InstallFront(kPOVMsgClass_ViewControl, kPOVMsgIdent_StartRender, this, &RenderBackend::StartRender);
	InstallFront(kPOVMsgClass_ViewControl, kPOVMsgIdent_StopRender, this, &RenderBackend::StopRender);
	InstallFront(kPOVMsgClass_ViewControl, kPOVMsgIdent_PauseRender, this, &RenderBackend::PauseRender);
	InstallFront(kPOVMsgClass_ViewControl, kPOVMsgIdent_ResumeRender, this, &RenderBackend::ResumeRender);

	InstallFront(kPOVMsgClass_FileAccess, kPOVMsgIdent_ReadFile, this, &RenderBackend::ReadFile);
}

RenderBackend::~RenderBackend()
{
}

void RenderBackend::SendSceneOutput(SceneId sid, POVMSAddress addr, POVMSType ident, POVMS_Object& obj)
{
	POVMS_Message msg(obj, kPOVMsgClass_SceneOutput, ident);

	msg.SetInt(kPOVAttrib_SceneId, sid);
	msg.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, msg, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendViewOutput(ViewId vid, POVMSAddress addr, POVMSType ident, POVMS_Object& obj)
{
	POVMS_Message msg(obj, kPOVMsgClass_ViewOutput, ident);

	msg.SetInt(kPOVAttrib_ViewId, vid);
	msg.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, msg, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendFindFile(POVMSContext ctx, SceneId sid, POVMSAddress addr, const vector<POVMSUCS2String>& filenames, POVMSUCS2String& filename)
{
	POVMS_Message msg(kPOVObjectClass_FileData, kPOVMsgClass_FileAccess, kPOVMsgIdent_FindFile);
	POVMS_Message result(kPOVObjectClass_FileData, kPOVMsgClass_FileAccess, kPOVMsgIdent_FindFile);
	POVMS_List files;

	for(vector<POVMSUCS2String>::const_iterator i(filenames.begin()); i != filenames.end(); i++)
	{
		POVMS_Attribute attr(i->c_str());
		files.Append(attr);
	}

	msg.Set(kPOVAttrib_ReadFile, files);

	msg.SetInt(kPOVAttrib_SceneId, sid);
	msg.SetDestinationAddress(addr);

	POVMS_SendMessage(ctx, msg, &result, kPOVMSSendMode_WaitReply);

	filename = result.TryGetUCS2String(kPOVAttrib_ReadFile, "");
}

void RenderBackend::SendReadFile(POVMSContext ctx, SceneId sid, POVMSAddress addr, const POVMSUCS2String& filename, POVMSUCS2String& localfile, POVMSUCS2String& fileurl)
{
	POVMS_Message msg(kPOVObjectClass_FileData, kPOVMsgClass_FileAccess, kPOVMsgIdent_ReadFile);
	POVMS_Message result(kPOVObjectClass_FileData, kPOVMsgClass_FileAccess, kPOVMsgIdent_ReadFile);

	msg.SetUCS2String(kPOVAttrib_ReadFile, filename.c_str());

	msg.SetInt(kPOVAttrib_SceneId, sid);
	msg.SetDestinationAddress(addr);

	POVMS_SendMessage(ctx, msg, &result, kPOVMSSendMode_WaitReply);

	localfile = result.TryGetUCS2String(kPOVAttrib_LocalFile, "");
	fileurl = result.TryGetUCS2String(kPOVAttrib_FileURL, "");
}

void RenderBackend::SendCreatedFile(POVMSContext ctx, SceneId sid, POVMSAddress addr, const POVMSUCS2String& filename)
{
	POVMS_Message msg(kPOVObjectClass_FileData, kPOVMsgClass_FileAccess, kPOVMsgIdent_CreatedFile);

	msg.SetUCS2String(kPOVAttrib_CreatedFile, filename.c_str());

	msg.SetInt(kPOVAttrib_SceneId, sid);
	msg.SetDestinationAddress(addr);

	POVMS_SendMessage(ctx, msg, NULL, kPOVMSSendMode_NoReply);
}

void RenderBackend::SendSuccessResult(POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_BackendControl, kPOVMsgIdent_Done);

	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendFailedResult(int error, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_BackendControl, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_ErrorNumber, error);
	result.SetString(kPOVAttrib_EnglishText, pov_base::Exception::lookup_code(error).c_str());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendFailedResult(const pov_base::Exception& e, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_BackendControl, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_ErrorNumber, e.code(kCannotHandleRequestErr));
	// pov_base::Exception(...) does a code->string lookup if a string isn't supplied
	result.SetString(kPOVAttrib_EnglishText, e.what());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendFailedResult(const char *str, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_BackendControl, kPOVMsgIdent_Failed);

	result.SetString(kPOVAttrib_EnglishText, str);
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendSceneSuccessResult(SceneId sid, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_SceneOutput, kPOVMsgIdent_Done);

	result.SetInt(kPOVAttrib_SceneId, sid);
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendSceneFailedResult(SceneId sid, int error, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_SceneOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_SceneId, sid);
	result.SetInt(kPOVAttrib_ErrorNumber, error);
	result.SetString(kPOVAttrib_EnglishText, pov_base::Exception::lookup_code(error).c_str());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendSceneFailedResult(SceneId sid, const pov_base::Exception& e, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_SceneOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_SceneId, sid);
	result.SetInt(kPOVAttrib_ErrorNumber, e.code(kCannotHandleRequestErr));
	// pov_base::Exception(...) does a code->string lookup if a string isn't supplied
	result.SetString(kPOVAttrib_EnglishText, e.what());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendSceneFailedResult(SceneId sid, const char *str, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_SceneOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_SceneId, sid);
	result.SetString(kPOVAttrib_EnglishText, str);
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendViewSuccessResult(ViewId vid, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_ViewOutput, kPOVMsgIdent_Done);

	result.SetInt(kPOVAttrib_ViewId, vid);
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendViewFailedResult(ViewId vid, int error, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_ViewOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_ViewId, vid);
	result.SetInt(kPOVAttrib_ErrorNumber, error);
	result.SetString(kPOVAttrib_EnglishText, pov_base::Exception::lookup_code(error).c_str());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendViewFailedResult(ViewId vid, const pov_base::Exception& e, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_ViewOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_ViewId, vid);
	result.SetInt(kPOVAttrib_ErrorNumber, e.code(kCannotHandleRequestErr));
	// pov_base::Exception(...) does a code->string lookup if a string isn't supplied
	result.SetString(kPOVAttrib_EnglishText, e.what());
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::SendViewFailedResult(ViewId vid, const char *str, POVMSAddress addr)
{
	POVMS_Message result(kPOVObjectClass_ResultData, kPOVMsgClass_ViewOutput, kPOVMsgIdent_Failed);

	result.SetInt(kPOVAttrib_ViewId, vid);
	result.SetString(kPOVAttrib_EnglishText, str);
	result.SetDestinationAddress(addr);

	POVMS_SendMessage(RenderBackend::context, result, NULL, kPOVMSSendMode_NoReply); // POVMS context provide for source address access only!
}

void RenderBackend::CreateScene(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		POVMSAddress backendAddress = POVMSInvalidAddress;
		int err = POVMS_GetContextAddress(context, &backendAddress);

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

		shared_ptr<Scene> scene(new Scene(backendAddress, msg.GetSourceAddress(), scenecounter + 1));

		scenecounter++;

		POVMS_Message newresult(result, result.GetClass(), kPOVMsgIdent_Done);
		result = newresult;
		result.SetInt(kPOVAttrib_SceneId, scenecounter);

		scenes[scenecounter] = scene;
		try
		{
			scene2views[scenecounter] = set<ViewId>();
		}
		catch(std::exception&)
		{
			scenes.erase(scenecounter);
			throw;
		}
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::CloseScene(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

		if(i == scenes.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if(scene2views[sid].size() > 0)
			throw POV_EXCEPTION_CODE(kNotNowErr);

		try { scenes.erase(sid); } catch(pov_base::Exception&) { }
		try { scene2views.erase(sid); } catch(pov_base::Exception&) { }

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::CreateView(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

		if(i == scenes.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		shared_ptr<View> view(i->second->NewView(msg.TryGetInt(kPOVAttrib_Width, 160), msg.TryGetInt(kPOVAttrib_Height, 120), viewcounter + 1));

		viewcounter++;

		POVMS_Message newresult(result, result.GetClass(), kPOVMsgIdent_Done);
		result = newresult;
		result.SetInt(kPOVAttrib_ViewId, viewcounter);

		views[viewcounter] = view;
		try { view2scene[viewcounter] = sid; } catch(std::exception&) { views.erase(viewcounter); throw; }
		try { scene2views[sid].insert(viewcounter); } catch(std::exception&) { views.erase(viewcounter); view2scene.erase(viewcounter); throw; }
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::CloseView(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		ViewId vid = msg.GetInt(kPOVAttrib_ViewId);

		map<ViewId, shared_ptr<View> >::iterator i(views.find(vid));

		if(i == views.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		try { views.erase(vid); } catch(pov_base::Exception&) { }
		try { scene2views[view2scene[vid]].erase(vid); } catch(pov_base::Exception&) { }
		try { view2scene.erase(vid); } catch(pov_base::Exception&) { }

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::StartParser(POVMS_Message& msg, POVMS_Message&, int)
{
	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		try
		{
			if(validateFrontendAddress(msg.GetSourceAddress()) == false)
				throw POV_EXCEPTION_CODE(kAuthorisationErr);

			map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

			if(i == scenes.end())
				throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

			i->second->StartParser(msg);
		}
		catch(pov_base::Exception& e)
		{
			SendSceneFailedResult(sid, e, msg.GetSourceAddress());
		}
	}
	catch(pov_base::Exception& e)
	{
		SendFailedResult(e, msg.GetSourceAddress());
	}
	catch(std::runtime_error& e)
	{
		SendFailedResult(e.what(), msg.GetSourceAddress());
	}
	catch(std::bad_alloc&)
	{
		SendFailedResult(kOutOfMemoryErr, msg.GetSourceAddress());
	}
}

void RenderBackend::StopParser(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

		if(i == scenes.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsParsing() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->StopParser();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::PauseParser(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

		if(i == scenes.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsParsing() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->PauseParser();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::ResumeParser(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		SceneId sid = msg.GetInt(kPOVAttrib_SceneId);

		map<SceneId, shared_ptr<Scene> >::iterator i(scenes.find(sid));

		if(i == scenes.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsParsing() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->ResumeParser();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::StartRender(POVMS_Message& msg, POVMS_Message&, int)
{
	try
	{
		ViewId vid = msg.GetInt(kPOVAttrib_ViewId);

		try
		{
			if(validateFrontendAddress(msg.GetSourceAddress()) == false)
				throw POV_EXCEPTION_CODE(kAuthorisationErr);

			map<ViewId, shared_ptr<View> >::iterator i(views.find(vid));

			if(i == views.end())
				throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

			if(i->second->IsRendering() == true)
				throw POV_EXCEPTION_CODE(kNotNowErr);

			i->second->StartRender(msg);
		}
		catch(pov_base::Exception& e)
		{
			SendViewFailedResult(vid, e, msg.GetSourceAddress());
		}
	}
	catch(pov_base::Exception& e)
	{
		SendFailedResult(e, msg.GetSourceAddress());
	}
	catch(std::runtime_error& e)
	{
		SendFailedResult(e.what(), msg.GetSourceAddress());
	}
	catch(std::bad_alloc&)
	{
		SendFailedResult(kOutOfMemoryErr, msg.GetSourceAddress());
	}
}

void RenderBackend::StopRender(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		ViewId vid = msg.GetInt(kPOVAttrib_ViewId);

		map<ViewId, shared_ptr<View> >::iterator i(views.find(vid));

		if(i == views.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsRendering() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->StopRender();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::PauseRender(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		ViewId vid = msg.GetInt(kPOVAttrib_ViewId);

		map<ViewId, shared_ptr<View> >::iterator i(views.find(vid));

		if(i == views.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsRendering() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->PauseRender();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::ResumeRender(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	try
	{
		ViewId vid = msg.GetInt(kPOVAttrib_ViewId);

		map<ViewId, shared_ptr<View> >::iterator i(views.find(vid));

		if(i == views.end())
			throw POV_EXCEPTION_CODE(kInvalidIdentifierErr);

		if((i->second->IsRendering() == false) && (i->second->IsPaused() == false))
			throw POV_EXCEPTION_CODE(kNotNowErr);

		i->second->ResumeRender();

		MakeDoneResult(result);
	}
	catch(pov_base::Exception& e)
	{
		MakeFailedResult(e, result);
	}
	catch(std::runtime_error& e)
	{
		MakeFailedResult(e.what(), result);
	}
	catch(std::bad_alloc&)
	{
		MakeFailedResult(kOutOfMemoryErr, result);
	}
}

void RenderBackend::ReadFile(POVMS_Message& msg, POVMS_Message& result, int)
{
	if(ValidateFrontendAddress(msg.GetSourceAddress(), result) == false)
		return;

	MakeFailedResult(kCannotHandleRequestErr, result);
}

bool RenderBackend::ValidateFrontendAddress(POVMSAddress addr, POVMS_Message& result)
{
	if(validateFrontendAddress(addr) == false)
	{
		MakeFailedResult(kAuthorisationErr, result);

		return false;
	}
	else
		return true;
}

void RenderBackend::MakeFailedResult(int error, POVMS_Message& result)
{
	POVMS_Message newmsg(result, result.GetClass(), kPOVMsgIdent_Failed);
	result = newmsg;
	result.SetInt(kPOVAttrib_ErrorNumber, error);
	result.SetString(kPOVAttrib_EnglishText, pov_base::Exception::lookup_code(error).c_str());
}

void RenderBackend::MakeFailedResult(const pov_base::Exception& e, POVMS_Message& result)
{
	POVMS_Message newmsg(result, result.GetClass(), kPOVMsgIdent_Failed);
	result = newmsg;
	result.SetInt(kPOVAttrib_ErrorNumber, e.code(kCannotHandleRequestErr));
	// pov_base::Exception(...) does a code->string lookup if a string isn't supplied
	result.SetString(kPOVAttrib_EnglishText, e.what());
}

void RenderBackend::MakeFailedResult(const char *str, POVMS_Message& result)
{
	POVMS_Message newmsg(result, result.GetClass(), kPOVMsgIdent_Failed);
	result = newmsg;
	result.SetString(kPOVAttrib_EnglishText, str);
}

void RenderBackend::MakeDoneResult(POVMS_Message& result)
{
	POVMS_Message newmsg(result, result.GetClass(), kPOVMsgIdent_Done);
	result = newmsg;
}

}
