/*
/ BSTMDIRECTOR.H
/ **************
/ The Scene Director acts as the core abstraction
/ layer between the graphics device and the game.
/ It also handles all game resources and scenes.
/
/ Will Beddow 2010 - http://343gs.com/brainstem
/
/ This software is currently under development
/ and is subject to change and improvement. Some
/ aspects of the system are incomplete and/or 
/ unstable due to ongoing implementation.
/
*/

#ifndef __BSTMDIRECTOR_H__
#define __BSTMDIRECTOR_H__

#include "Compile.h"
#include "Types.h"
#include "Director.h"
#include "Scene.h"
#include "Texture.h"
#include "Mesh.h"
#include "Node.h"
#include "Model.h"
#include "Primitive.h"

#include "BstmDevice.h"
#include "BstmScene.h"
#include "BstmDisplay.h"
#include "BstmTerrain.h"
#include "BstmSprite.h"
#include "BstmSky.h"
#include "BstmCamera.h"

#include <vector>
#include <map>
#include <sstream>

namespace Brainstem
{  
	class BstmDirector : public IDirector
	{
	public:
		BstmDirector(IKernel* kernel);
		~BstmDirector();

		bool Init();
		void Update();
		void Release();
		void Render(IScene* scene);

		IScene* CreateScene();
		IDisplay* CreateDisplay();
		IDisplay* CreateDisplay(Color color);

		ITexture* CreateTexture(const char* filename);

		IScene* GetActiveScene();
		void SetActiveScene(IScene* scene);

		ISceneNode* AddTeapot(IScene* scene);
		ISceneNode* AddSphere(IScene* scene, float radius, unsigned int slices, unsigned int stacks);
		ISceneNode* AddBox(IScene* scene, float width, float height, float depth);
		ISceneNode* AddPlane(IScene* scene, float width, float height);
		ISceneNode* AddXModel(IScene* scene, const char* filename);

		ISprite* AddSprite(IScene* scene);

		ITerrain* AddTerrainFromFile(IScene* scene, unsigned int patches, const char* filename, float scaleFactor);
		ITerrain* AddTerrainRandom(IScene* scene, unsigned int patches, int seed, float noiseSize, float persistence, int octaves, float scaleFactor);

		ISky* AddSkyDome(IScene* scene);

		ICamera* AddFirstPersonCamera(IScene* scene, float rotationSpeed, float movementSpeed, bool isNoClip);
		ICamera* AddStaticCamera(IScene* scene, Vector3<float> target);

		void AddLight(IScene* scene, ILight* light);

		AUTO_OBJECT_SIZE;
		virtual const char* GetName() { return "Scene Director"; }

	private:

		std::vector<IPtr<IScene>> Scenes;
		std::vector<IPtr<IDisplay>> Displays;
		std::vector<IPtr<IMesh>> Meshes;
		std::vector<IPtr<ITexture>> Textures;

		ISceneNode* AddPrimitive(IScene* scene, Primitive* primitive);
		ISceneNode* AddPrimitive(IScene* scene, const char* id, Primitive* primitive);

		IMesh* FindMeshInstance(const char* id);
		ITexture* FindTextureInstance(const char* id);

		IKernel* Kernel;
		BstmDevice* Renderer;
		IDirect3DDevice9* Device;
		ID3DXEffect* Effect;

		IDirect3DTexture9* BstmDiffuseTexture;
		IDirect3DTexture9* BstmNormalTexture;
		IDirect3DTexture9* BstmHeightTexture;
		IDirect3DTexture9* BstmBlankTexture;

		#ifndef ERR_SCENE_NULL
		#define ERR_SCENE_NULL(scene, id) { if (scene == NULL) { AllowUpdate = false; AllowRender = false;  WRITE_ERROR(this, "Cannot Create " << id << " | Provided Scene is NULL"); return NULL; } }
		#endif 

		#ifndef ERR_NODE_INIT_NULL
		#define ERR_NODE_INIT_NULL(result, id) { if (!result) { AllowUpdate = false; AllowRender = false; WRITE_ERROR(this, "Initialisation Failed | " << id); return NULL; } }
		#endif 
	};
}


#endif