#pragma once
#include "engineinterface.h"
#include "fixed_stack.h"
#include "openglstate.h"
#include <GL/glew.h>
#include <set>

namespace M3D
{
//Forward declarations
class Texture;
class Object;
class Mesh;
class Light;
/**
	@author Denis A. Biryukov <denis.birukov@gmail.com>
*/
class OpenGL31Engine : public EngineInterface
{
	public:
		OpenGL31Engine();

		~OpenGL31Engine();
                
                //Initialization functions
                virtual void set_limits( const EngineLimits &limits );
                virtual void _init_(int w, int h, float fov);

                //Camera functions
		virtual CameraInterface create_camera();
                virtual void remove_camera( const CameraInterface& camera );
                virtual void switch_camera( const CameraInterface& camera );
                
                //Model functions
		virtual ModelInterface create_model( );
		virtual ModelInterface clone_model( const ModelInterface &model );
		virtual void add_model( const ModelInterface& obj );
                virtual void remove_model( const ModelInterface& obj );
                
                //Shader functions
                virtual ShaderProgramInterface create_shader_program();
                virtual void override_shader_program(const ShaderProgramInterface &shader_id);
                virtual void remove_shader_override();
                virtual void remove_shader_program(const ShaderProgramInterface &shader_id);
                
                //Material functions
                virtual MaterialInterface create_material();
                
                //Texture functions
                virtual TextureInterface create_texture();
		
		//Light functions
		virtual LightInterface create_light();
		virtual void set_light ( const LightInterface &light_id );
                
                //Draw functions
                virtual void draw();
		virtual void set_draw_mode(DRAW_MODE draw_mode);
                
                
	protected:
		virtual Camera* _get_camera( int camera_id ) const;
		virtual Model* _get_model( int model_id ) const;
		virtual ShaderProgram* _get_shader( int shader_id ) const;
		virtual Texture* _get_texture( int texture_id ) const;
		virtual Mesh* _get_mesh( int mesh_id) const;
                virtual Material* _get_material( int material_id) const;
		virtual Light* _get_light ( int light_id ) const;
	private:
		struct OpenGLCapabilities
		{
			public:
				std::string gl_version;
				std::string gl_vendor;
				std::string gl_shading_language_version;
                                std::string gl_renderer;
                                std::string gl_extensions;
				GLint max_vertices;
				GLint max_indeces;
				GLint max_point_size;
				GLint max_texture_size;
		} _capabilities_;
		
		Model *_models_;
		Texture *_textures_;
		Mesh *_meshes_;
		Camera *_cameras_;
		ShaderProgram *_shaders_;
                Material *_materials_;
		Light *_lighs_;
		
		fixed_stack<int32_t> *_model_ids_;
		fixed_stack<int32_t> *_texture_ids_;
		fixed_stack<int32_t> *_mesh_ids_;
		fixed_stack<int32_t> *_camera_ids_;
		fixed_stack<int32_t> *_shader_ids_;
                fixed_stack<int32_t> *_material_ids_;
                fixed_stack<int32_t> *_light_ids_;
		
                std::set<Material*> _materials_to_draw_;

		CameraInterface _active_camera_;
		ShaderProgramInterface _override_shader_program_;
		bool _is_override_shader_program_;
		LightInterface _current_light_;
                
                struct RendererInfo
                {
                    uint32_t _frame_no_;
                    RendererInfo() : _frame_no_ (0){};
                } _renderer_info_;
                OpenGLState _gl_state_;
};

}
