/*
 * $Id: scenemanager.h 4661 2017-08-23 20:40:02Z 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.
 */


#ifndef __SCENEMANAGER__H__
#define __SCENEMANAGER__H__
//#include <wx/app.h>
//#include <wx/hashmap.h>
//#include "common.h"
#include "image.h"
#include "scene.h"
#include "imagecommon.h"
#include "imagedds.h"
#include "imageHDR.h"

#include "VrutApi.h"

namespace VRUT
{
	///Class for access and modifications of scene graphs
	class VRUT_CORE_API SceneManager
	{
	private:
		WX_DECLARE_STRING_HASH_MAP(smart_pointer_v2<Image>, ImageList);
		///List of managed scenes
		std::vector<smart_pointer_v2<Scene> > sceneList;
		///Loaded images list
		ImageList imageList;
		///Mutex for new ID generation
		mutable wxCriticalSection scenesMutex;
		///Mutex for access to imageList
		wxCriticalSection imageListMutex;

	public:
		///Class constructor
		SceneManager() {}
		///Class destructor
		~SceneManager() {}
		///Cleanup manager data to allow safe application exit
		void ReleaseManagerData()
		{
			sceneList.clear();
			imageList.clear();
		}

		SCENE_ID GetNewSceneID()
		{
			wxCriticalSectionLocker locker(scenesMutex);
			sceneList.push_back(NULL);
			return NODE_ID(sceneList.size()-1);
		}

		///Get scene container
		void GetScene(smart_pointer_v2<Scene> &scene, SCENE_ID sceneID) const
		{
			scenesMutex.Enter();
			scene.assign(( sceneID >= sceneList.size() ? (Scene *)NULL : sceneList[sceneID].getPtr() ));
			scenesMutex.Leave();
		}

		///Get list of SCENE_IDs
		///\param[out] IDlist List of SCENE_IDs
		void GetSceneIDs(std::vector<SCENE_ID> &IDlist) const
		{
			wxCriticalSectionLocker locker(scenesMutex);
			for (size_t i=0; i<sceneList.size(); i++)
			{
				if (sceneList[i])
					IDlist.push_back(SCENE_ID(i));
			}
		}

		///Get all scenes
		void GetScenes(std::vector<smart_pointer_v2<Scene> > &scenes) const
		{
			scenesMutex.Enter();
			for (auto &scene : sceneList)
			{
				if (scene)
				{
					smart_pointer_v2<Scene> sceneNew;
					scenes.push_back(sceneNew);
					scenes.back().assign(scene.getPtr());
				}
			}
			scenesMutex.Leave();
		}

		///Add scene graph
		///\return newly created scene
		SCENE_ID AddScene(const wxString &name, SCENE_ID sceneID);

		///Remove scene graph (does not delete)
		void RemoveScene(SCENE_ID id);

		///Get texture image, load from given filename if not loaded
		///NOTE: If called from module, module must call wxInitAllImageHandlers() first
		///\param[in] imgPath Path to image file (also a key to hash map with images)
		///\param[in] loadIfNotFound Load texture from file if not found in image list
		///\param[in] reload force texture reload
		///\param[in] flip Flips texture on load, see Image::Load for more info
		///\return Image instance or \c NULL
		const_smart_pointer<Image> GetImage(const wxString & imgPath, bool loadIfNotFound = true, int cubeSide=-1, wxString refName=wxT(""), bool reload=false, int flip=0);

		/// Add or change image given by data
		/// AddImage takes an ownership of passed Image, do not deallocate it after calling this function
		///\param[in] imgPath unique identifier of the image (also a key to hash map with images)
		///\param[in] image image
		void AddImage(const wxString & imgPath, Image *image, int cubeSide=-1, wxString refName=wxT(""));

		/// Writes a list of names of all images into \c imageNames
		void GetImageNames(std::vector<wxString> &imageNames);

		/// Renames \c old_name image to \c new_name image.
		/// If \c old_name does not correspont to any image, nothing happens.
		/// If \c new_name already exists, it is overwriten with old image
		void RenameImage(const wxString &old_name, const wxString &new_name);

		/// Copies \c source_name image to \c dest_name image. Performs a shallow copy, i.e. source and dest
		/// images are still the same object.
		/// If \c old_name does not correspont to any image, nothing happens.
		/// If \c new_name already exists, it is overwriten with old image
		/// \todo It is unresolved whether to perform a shallow copy or a deep copy.
		void CopyImage(const wxString &source_name, const wxString &dest_name);
	};
}

#endif
