#pragma once
#include "engine_structs.h"
#include "Interfaces/modelinterface.h"
#include "Interfaces/textureinterface.h"
#include "Interfaces/meshinterface.h"
#include "Interfaces/camerainterface.h"
#include "Interfaces/shaderprograminterface.h"
#include "Interfaces/materialinterface.h"
#include "Interfaces/lightinterface.h"
#include <string>
namespace M3D
{
//Forward declarations
class Model;
class Camera;
class ShaderProgram;
class Texture;
class Mesh;
class Material;
class EngineInterface;
class TextureLayer;
class Light;
/**
 * Интерфейсный класс для любого графического движка. Реализует только общую для всех движков фунциональность.
 * @author Denis A. Biryukov
 */
class EngineInterface
{
	public:
		enum OBJECT_TYPE
		{
			OBJECT_DYNAMIC = 0,
			OBJECT_STATIC
		};
		EngineInterface():_mem_info_(),	_limits_(){};
		virtual ~EngineInterface() {};

		//Initialization functions
		/**
		 * Устанавливает максимальное кол-во объектов. При этом происходит перезагрузка всех уже загруженных моделей, выделение памяти под все объекты. Идиентификаторы объектов при этом остаются валидными. Операция очень длительная.
		 * Если texture_size или mesh_size больше чем максимально допустимый для видеокарты, он будет признан равным максимально допустимому
		 * @param limits список ограничений для движка
		 * @author Denis A. Biryukov
		 */
		virtual void set_limits ( const EngineLimits &limits ) = 0;
		/**
		 * Производит инициализацию внутренних структур движка и OpenGL контекста
		 * @param w ширина OpenGL окна
		 * @param h высота OpenGL окна
		 * @param fov угол обзора (в градусах)
		 * @author Denis A. Biryukov
		 */
		virtual void _init_ ( int w, int h, float fov ) = 0;

		//Camera functions
		/**
		 * Создает камеру
		 * @return идиентификатор камеры
		 * @author Denis A. Biryukov
		 */
		virtual CameraInterface create_camera() = 0;
		/**
		 * Устанавливает указаную камеру текущей
		 * @author Denis A. Biryukov
		 */
		virtual void switch_camera ( const CameraInterface &camera ) = 0;
		/**
		 * Удаляет указанную камеру. После данной операции ее идиентификатор более не будет валидным
		 * @author Denis A. Biryukov
		 */
		virtual void remove_camera ( const CameraInterface &camera ) = 0;

		//Model functions
		/**
		 * Создает пустой объект.
		 * @return Идиентификатор объекта
		 * @author Denis A. Biryukov
		 */
		virtual ModelInterface create_model( ) = 0;
		/**
		 * Создает копию указанной модели
		 * @param model идиентификатор клонируемой модели
		 * @return Идиентификатор новой модели
		 * @author Denis A. Biryukov
		 */
		virtual ModelInterface clone_model( const ModelInterface &model) = 0;
		/**
		 * Добавляет объект в список отображения.
		 * @param obj идиентификатор объекта
		 * @author Denis A. Biryukov
		 */
		virtual void add_model ( const ModelInterface &obj ) = 0;

		/**
		 * Удаляет объект из списка отображения. Для статических объектов не делает ничего
		 * @param obj идиентификатор объекта
		 * @author Denis A. Biryukov
		 */
		virtual void remove_model ( const ModelInterface &obj ) = 0;

		//Shader functions
		/**
		 * Создает новую шейдерную программу
		 * @return Идиентификатор шейдерной программы
		 * @author Denis A. Biryukov
		 */
		virtual ShaderProgramInterface create_shader_program() = 0;
		/**
		 * Устанавливает шейдерную программу текущей (переопределяет то, что указанно в свойствах объекта.
		 * @param shader_id идиентификатор шейдерной программы
		 * @author Denis A. Biryukov
		 */
		virtual void override_shader_program ( const ShaderProgramInterface &shader_id ) = 0;
		/**
		 * Снимаешь переопределение шейдерной программы
		 * @author Denis A. Biryukov
		 */
		virtual void remove_shader_override() = 0;
		/**
		 * Удаляет указанную шейдерную программу.
		 * @param shader_id идиентификатор шейдерной программы
		 * @author Denis A. Biryukov
		 */
		virtual void remove_shader_program ( const ShaderProgramInterface &shader_id ) = 0;

		//Material functions
		/**
		 * Создает материал
		 * @return идиентификатор материала
		 * @author Denis A. Biryukov
		 */
		virtual MaterialInterface create_material() = 0;

		//Texture functions
		/**
		 * Создает текстуру
		 * @return идиентификатор текстуры
		 * @author Denis A. Biryukov
		 */
		virtual TextureInterface create_texture() = 0;

		//Light functions
		/**
		 * Создает источник света
		 * @return идиентификатор источника света
		 * @author Denis A. Biryukov
		 */
		virtual LightInterface create_light() = 0;
		/**
		 * Производит установку источника света.
		 * ///@TODO временная функция, необходимо будет в будущем както модифицировать процесс установки источников света, чтобы можно было задавать несколько источников одновременно
		 * @author Denis A. Biryukov
		 */
		virtual void set_light ( const LightInterface &light_id ) = 0;

		//Draw functions
		/**
		 * Производит установку режима отрисовки.
		 * @param draw_mode режим отрисовки
		 * @author Denis A. Biryukov
		 */
		virtual void set_draw_mode ( DRAW_MODE draw_mode ) = 0;
		/**
		 * Производит отрисовку всех объектов которые находятся в списке отображения. Для статических объектов не производится никакого запроса данных по ним, для динамических объектов применяются соответствуюющие преобразования.
		 */
		virtual void draw() = 0;

//		virutal void

		friend class ModelInterface;
		friend class CameraInterface;
		friend class ShaderProgramInterface;
		friend class LightInterface;
		friend class Model;
		friend class TextureLayer;
		friend class Material;
		friend void LoadModel ( const std::string &fname, Model *model, Mesh *mesh, Material *material, EngineInterface *engine );
	protected:
		virtual Model* _get_model ( int model_id ) const = 0;
		virtual Camera* _get_camera ( int camera_id ) const = 0;
		virtual ShaderProgram* _get_shader ( int shader_id ) const = 0;
		virtual Texture* _get_texture ( int texture_id ) const = 0;
		virtual Mesh* _get_mesh ( int mesh_id ) const = 0;
		virtual Material* _get_material ( int material_id ) const = 0;
		virtual Light* _get_light ( int light_id ) const = 0;

		EngineMemInfo _mem_info_;
		EngineLimits _limits_;
		int _w_;
		int _h_;
		float _fov_;
};

}


