/*
 * $Id: scenemanager.cpp 4867 2018-03-12 07:06:04Z antonin.misek-skoda-auto.cz $
 *
 * Description  : One line description of file.
 * Author       : Vaclav Kyba <mail/Jabber: vaseo1@gmail.com>  <ICQ: 98576293>
 *
 * Purpose      :
 *     Long description of what the file is for.
 */

#include "kernel.h"
#include "scenemanager.h"
//#include "flexilog.h"
#include "eventhandler.h"

using namespace VRUT;


SCENE_ID SceneManager::AddScene(const wxString &name, SCENE_ID sceneID)
{
	wxCriticalSectionLocker locker(scenesMutex);
	if (sceneID!=SCENE_ID_NONE)
		RemoveScene(sceneID);
	else
		sceneID = GetNewSceneID();
	if (sceneID>=sceneList.size())
		sceneList.insert(sceneList.end(), sceneID-sceneList.size()+1, NULL);
	Scene * scene = new Scene(sceneID, KERNEL->GetMessageSink());
	scene->SetName(name);
	sceneList.at(sceneID) = scene;
	KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_ADDED(sceneID));
	return sceneID;
}


void SceneManager::RemoveScene(SCENE_ID sceneID)
{
	wxCriticalSectionLocker locker(scenesMutex);
	if ((sceneID<sceneList.size()) && (sceneList[sceneID]))
	{
		sceneList[sceneID] = (Scene *)NULL;
		KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_REMOVED(sceneID));
	}
}


const_smart_pointer<Image> SceneManager::GetImage(const wxString & imgPath, bool loadIfNotFound, int cubeSide, wxString refName, bool reload, int flip)
{
	if (refName.IsEmpty())
	{
		refName=imgPath;
		cubeSide=-1;
	}
	imageListMutex.Enter();
	ImageList::iterator img = imageList.find(refName);
	if ((img != imageList.end()) && !reload)
	{
		smart_pointer_v2<Image> image=img->second;
		imageListMutex.Leave();
		if (cubeSide!=-1)
		{
			//add cube side
			bool loaded = image->Load(imgPath, cubeSide, flip);
			KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(refName, loaded, cubeSide));
		}
		return image;
	}
	imageListMutex.Leave();
	if (loadIfNotFound || reload)
	{
		wxFileName fname(imgPath);
//		fname.MakeAbsolute();
		Image * image = (Image *)NULL;
		if (fname.GetExt().IsSameAs(wxT("dds"), false))
			image = new ImageDDS;
		else if (fname.GetExt().IsSameAs(wxT("hdr"), false))
			image = new ImageHDR;
		else
			image = new ImageCommon;
		if (image && image->Load(imgPath/*fname.GetFullPath()*/, cubeSide, flip))
		{
			image->SetTransparencyAndSetAlphaUsage(true);
			wxCriticalSectionLocker imageListMutexLock(imageListMutex);
			img = imageList.find(refName);
			if (img != imageList.end())
				img->second = smart_pointer_v2<Image>(image);
			else
			{
				imageList.insert(ImageList::value_type(refName, smart_pointer_v2<Image>(image)));
				img = imageList.find(refName);
			}
			if (img->second)
			{
				KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(refName, true, cubeSide));
				return img->second;
			}
		}
		else
			SAFE_DELETE(image);
		LOGERROR(wxT("Image not loaded: '")+imgPath+wxT("'"));
		KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(refName, false, cubeSide));
	}
	return (Image *)NULL;
}

void SceneManager::AddImage(const wxString & imgPath, Image *image, int cubeSide, wxString refName)
{
	if (refName.IsEmpty())
	{
		refName=imgPath;
		cubeSide=-1;
	}
	imageListMutex.Enter();
	ImageList::iterator img = imageList.find(refName);
	if (img != imageList.end())
	{
		if (cubeSide!=-1)
		{
			//add cube side
			if ((img->second->GetType()==Image::WXIMAGE) && (image->GetType()==Image::WXIMAGE))
			{
				static_cast<ImageCommon*>(img->second.getPtr())->SetImage(static_cast<ImageCommon*>(image)->GetWxImage(cubeSide), cubeSide);
				delete image;
			}
			else
			{
				LOGERROR(wxT("<SceneManager::AddImage>not implemented SetImage for given type"));
				delete image;
			}
		}
		else
		{
			img->second = smart_pointer_v2<Image>(image);
		}
		imageListMutex.Leave();
		KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(refName, true, cubeSide));
	}
	else
	{
		auto res = imageList.insert(ImageList::value_type(refName, smart_pointer_v2<Image>(image)));
		imageListMutex.Leave();
		if (res.second)
			KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(refName, true, cubeSide));
	}
}

void SceneManager::GetImageNames(std::vector<wxString> &imageNames)
{
	wxCriticalSectionLocker lock(imageListMutex);
	for (auto &image : imageList)
		imageNames.push_back(image.first);
}

void SceneManager::RenameImage(const wxString &old_name, const wxString &new_name)
{
	imageListMutex.Enter();

	ImageList::iterator old_name_iter = imageList.find(old_name);
	if (old_name_iter == imageList.end())
	{
		imageListMutex.Leave();
		LOGWARNING("<SceneManager::RenameImage> Cannot rename " + old_name + " to " + new_name + ", source image does not exist");
		return;		// Do nothing
	}

	smart_pointer_v2<Image> old_name_image = old_name_iter->second;
	imageList.erase(old_name_iter);
	imageList[new_name] = old_name_image;
	imageListMutex.Leave();

	KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(old_name, true, -1));
	KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(new_name, true, -1));
}

void SceneManager::CopyImage(const wxString &source_name, const wxString &dest_name)
{
	imageListMutex.Enter();

	ImageList::iterator src_image_iter = imageList.find(source_name);
	if (src_image_iter == imageList.end())
	{
		imageListMutex.Leave();
		LOGWARNING("<SceneManager::CopyImage> Cannot copy " + source_name + " to " + dest_name + ", source image does not exist");
		return;		// Do nothing
	}

	imageList[dest_name] = src_image_iter->second;
	imageListMutex.Leave();

	KERNEL->GetMessageSink()->DistributeToListeners(GET_EVT_SCENE_IMAGE_ADDED(dest_name, true, -1));
}
