#ifndef VIDEO_INT_H
#define VIDEO_INT_H
#include <string>
#include <map>
#include <vector>
#include "event.h"
#include <stdint.h>
#ifdef Revision
#undef Revision
#endif
#define Revision "video_int.h $Revision: 1.9 $"

typedef int8_t Sint8;
typedef uint8_t Uint8;
typedef uint16_t Uint16;
typedef int16_t Sint16;
typedef uint32_t Uint32;
typedef int32_t Sint32;

/**
 * Хранение конфигурации. Допустимо использование нескольких файлов конфигурациию.
 * Для загрузки конфигурации используется интерфейс драйверов. Допустимо создание и использование одновременно нескольких хранилищ конфигурации с разными (или одинаковыми) драйверами.
 * Обеспечивается многопоточная безопасность.
 *@author Denis A. Birukov aka Messenger of death
 *@date 18.08.2005
 */
struct VideoRect
{
	double x_s;
	double y_s;
	double x_e;
	double y_e;
};
struct VideoColor
{
	VideoColor(int rii, int gii, int bii, int aii):r((float)rii/255.), g((float)gii/255.), b((float)bii/255.), a((float)aii/255.), ri(rii), gi(gii), bi(bii), ai(aii)	
	{};
	VideoColor():r(0), g(0), b(0), a(0), ri(0), gi(0), bi(0), ai(0)	{};
	void set_color(int rii, int gii, int bii, int aii)
	{
		r=((float)ri/255.);
		g=((float)gi/255.);
		b=((float)bi/255.);
		a=((float)ai/255.);
		ri=rii;
		gi=gii;
		bi=bii;
		ai=aii;
	}
	void set_color(float rf, float gf, float bf, float af)
	{
		r=rf;
		g=gf;
		b=bf;
		a=af;
		ri=(int)(r*255.);
		gi=(int)(g*255.);
		bi=(int)(b*255.);
		ai=(int)(a*255.);
	}
	void set_r(int rii){r=((float)rii/255.);ri=rii;}
	void set_g(int gii){g=((float)gii/255.);gi=gii;}
	void set_b(int bii){b=((float)bii/255.);bi=bii;}
	void set_a(int aii){a=((float)aii/255.);ai=aii;}
	float r;
	float g;
	float b;
	float a;
	unsigned char ri;
	unsigned char gi;
	unsigned char bi;
	unsigned char ai;
};

class Video_Features
{
	public:
		virtual bool _support_blit_abs() {return false;}
		virtual bool _support_blit() {return false;}
		virtual bool _support_create_surface_abs() {return false;}
		virtual bool _support_create_surface() {return false;}
		virtual bool _support_create_surface_from_surface() {return false;}
		virtual bool _support_get_main_surfaace() {return false;}
		virtual ~Video_Features() {}};

class Video_Surface;
class Video_Sprite;
class Video_Particles;

class Video_Interface
{
	public:
		/**
		 *                      Запрос возможностей видео устройства
		 * @return константная ссылка на объект возможностей.
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual const Video_Features& _get_features() = 0;


		/**
		 *                      Запрос имени драйвера
		 * @return имя драйвера
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual std::string _get_driver_name() = 0;

		/**
		 *                      Удаляет поверхность по имени
		 * @param name имя поверхности
		 * @param group имя группы
		 * @return true в случае удачного удаления.  Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _free_surface ( std::string name, std::string group="" ) = 0;

		/**
		 *                      Производит отображение поверхности from на поверхность to. При этом поверхность from отобржается с координаты from_x, from_y поверхности from в координаты to_x, to_y поверхности to. Т.е. при from_x=10,from_y=10,to_x=10,to_y=10 и размерами from:15x15, to 20x20 кусок поверхности from начиная с координат [10;10] будет помещен в поверхность to с координатами 10_10. При этом, кусок поверхности будет обрезан, если она целиком  не влазиет в указанные координаты.
		 * @param from Отображаемая поверхность
		 * @param from_x Начало участка отображения по x в абсолютных координатах
		 * @param from_y Начало участка отображения по y в абсолютных координатах
		 * @param to Поверхность, в которую осуществляется отображение
		 * @param to_x Начало участка по x в абсолютных координатах
		 * @param to_y Начало участка по y в абсолютных координатах
		 * @return true в случае успеха.  Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _blit ( std::string from, int from_x, int from_y, std::string to, int to_x, int to_y ) {return false;}

		/**
		 *                      Производит отображение поверхности from на поверхность to. При этом поверхность from отобржается с координаты from_x, from_y поверхности from в координаты to_x, to_y поверхности to. Т.е. при from_x=10,from_y=10,to_x=10,to_y=10 и размерами from:15x15, to 20x20 кусок поверхности from начиная с координат [10;10] будет помещен в поверхность to с координатами 10_10. При этом, кусок поверхности будет обрезан, если она целиком  не влазиет в указанные координаты.
		 * @param from Отображаемая поверхность
		 * @param from_x Начало участка отображения по x в относительных  координатах
		 * @param from_y Начало участка отображения по y в относительных координатах
		 * @param to Поверхность, в которую осуществляется отображение
		 * @param to_x Начало участка по x в относительных координатах
		 * @param to_y Начало участка по y в относительных координатах
		 * @return true в случае успеха.  Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _blit ( std::string from, double from_x, double from_y, std::string to, double to_x, double to_y ) {return false;}

		/**
		 * Добавляет спрайт в очередь на отрисовку
		 * @param name Имя спрайта.
		 * @param group имя группы
		 * @return true в случае успеха. Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 25.11.2007
		 */
		virtual bool _add_sprite ( std::string name, std::string group="" ) = 0;
		/**
		 * Добавляет спрайт в очередь на отрисовку
		 * @param spr Указатель на спрайт
		 * @return true в случае успеха. Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 01.12.2007
		 */
		virtual bool _add_sprite ( Video_Sprite *spr ) = 0;
		/**
		 * Добавляет набор частиц очередь на отрисовку
		 * @param name Имя набора.
		 * @param group имя группы
		 * @param is_background требуется ли отображать данные частицы до отображения всего остального
		 * @return true в случае успеха. Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 25.11.2007
		 */
		virtual bool _add_particles ( std::string name, std::string group="", bool is_background = false  ) = 0;

		/**
		*                      Создание поверхности с заданным именем в заданной группе. В случае, если группа несуществует, то она создается автоматически. Если указанное имя уже существует в указанной группе, то поведение зависит от флага rewrite(по умолчанию - поверхность заменяется)
		* @param xs Ширина поверхности в абсолютных единицах
		* @param ys Высота поверхности в абсолютных единицах
		* @param name Имя содаваемой поверхности
		* @param group_name Имя группы, в которой создается поверхность. По умолчанию - current, что соответствует текущей группе.
		* @param rewrite Флаг замены поверхности. Если установлен в true(по умолчанию), то поверхность будет замещать существующую.
		* @return true в случае успешного завершения. В случае неудачи, получить причину можно функцией _get_error()
		* @author Denis A. Birukov aka Messenger of death
		* @date 30.08.2005
		*/
		virtual bool _create_surface ( int xs, int ys, std::string name, std::string group_name = "current", bool rewrite = true ) {return false;}

		/**
		 *                      Создание поверхности с заданным именем в заданной группе. В случае, если группа несуществует, то она создается автоматически. Если указанное имя уже существует в указанной группе, то поведение зависит от флага rewrite(по умолчанию - поверхность заменяется)
		 * @param xs Ширина поверхности в относительных единицах
		 * @param ys Высота поверхности в относительных единицах
		 * @param name Имя содаваемой поверхности
		 * @param group_name Имя группы, в которой создается поверхность. По умолчанию - current, что соответствует текущей группе.
		 * @param rewrite Флаг замены поверхности. Если установлен в true(по умолчанию), то поверхность будет замещать существующую.
		 * @return true в случае успешного завершения. В случае неудачи, получить причину можно функцией _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _create_surface ( double xs, double ys, std::string name, std::string group_name = "current", bool rewrite = true ) {return false;}

		/**
		 *                      Изменяет текущую группу. В случае, если указанной группы несуществует, то текущая группа останется без изменений.
		 * @param name Имя новой текущей группы
		 * @return true в случае успеха. Ошибка может быть получена через _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _set_current_group ( std::string name ) = 0;

		/**
		 *                      Возвращает текущю группу.
		 * @return Строка, содержащая имя текущей группы.
		 */
		virtual std::string _get_current_group() = 0;

		/**
		 *                      Возвращает имя, ассоциированное с основной поверхностью.
		 * @return Имя, ассоциированное с основной поверхностью
		 */
		virtual std::string _get_main_surface() {return "";}

		/**
		 *                      Возвращает указатель на запрашиваемую видео поверхность.
		 * @param name Имя запрашиваемой поверхности
		 * @param group имя группы
		 * @return Указатель на поверхность
		 */
		virtual Video_Surface* _get_surface ( std::string name, std::string group="" ) = 0;

		/**
		 *                      Возвращает указатель на запрашиваемую группу частиц.
		 * @param name Имя запрашиваемой группы частиц
		 * @param group имя группы
		 * @return Указатель на поверхность
		 */
		virtual Video_Particles* _get_particles ( std::string name, std::string group_name="" )=0;
		/**
		 *                      Возвращает указатель на запрашиваемый спрайт.
		 * @param name Имя запрашиваемой поверхности
		 * @param group имя группы
		 * @return Указатель на поверхность
		 */
		virtual Video_Sprite* _get_sprite ( std::string sprite_name, std::string group_name="" ) =0;


		/**
		 *                      Добавление поверхности с заданным именем в заданной группе. В случае, если группа несуществует, то она создается автоматически. Если указанное имя уже существует в указанной группе, то поведение зависит от флага rewrite(по умолчанию - поверхность заменяется)
		 * @param surf Указатель на добавляемую поверхность
		 * @param name Имя содаваемой поверхности
		 * @param group_name Имя группы, в которой создается поверхность. По умолчанию - current, что соответствует текущей группе.
		 * @param rewrite Флаг замены поверхности. Если установлен в true(по умолчанию), то поверхность будет замещать существующую.
		 * @return true в случае успешного завершения. В случае неудачи, получить причину можно функцией _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual bool _create_surface ( Video_Surface *surf, std::string name, std::string group_name = "current", bool rewrite = true ) {return false;}

		/**
		*                      Добавление спрайта с заданным именем в заданной группе. В случае, если группа несуществует, то она создается автоматически. Если указанное имя уже существует в указанной группе, то поведение зависит от флага rewrite(по умолчанию - поверхность заменяется). Созданный спрайт привязывается к указанной поверхности
		* @param name Имя содаваемой поверхности
		* @param group_name Имя группы, в которой создается поверхность. 
		* @param surf_name Имя поверхности для соединения со спрайтом
		* @param surf_group Имя группы поверхности
		* @param rewrite Флаг замены поверхности. Если установлен в true(по умолчанию), то поверхность будет замещать существующую.
		* @return true в случае успешного завершения. В случае неудачи, получить причину можно функцией _get_error()
		* @author Denis A. Birukov aka Messenger of death
		* @date 30.08.2005
		 */
		virtual bool _create_sprite ( std::string name, std::string group_name, std::string surf_name, std::string surf_group, bool rewrite = true ) {return false;}

		/**
		 * Добавление набора частиц с заданным именем в заданной группе. В случае, если группа несуществует, то она создается автоматически. Если указанное имя уже существует в указанной группе, то поведение зависит от флага rewrite(по умолчанию - заменяется). Созданный набор частиц спрайт привязывается к указанной поверхности
		 * @param name Имя содаваемого набора частиц
		 * @param group_name Имя группы, в которой создается набор частиц. 
		 * @param surf_name Имя поверхности для соединения с набором частиц
		 * @param surf_group Имя группы поверхности
		 * @param count количество частиц
		 * @param rewrite Флаг замены поверхности. Если установлен в true(по умолчанию), то поверхность будет замещать существующую.
		 * @return true в случае успешного завершения. В случае неудачи, получить причину можно функцией _get_error()
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 04.12.2007
		 */
		virtual bool _create_particles ( std::string name, std::string group_name, std::string surf_name, std::string surf_group, int count, bool rewrite=false ) =0;
		
		/**
		 * Управление обработкой событий нажития клавиш мыши. По умолчанию - отключено
		 * @param state true - события будут возвращаться через _get_event, false - нет
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 11.01.2008
		 */
		virtual void _enable_mouse_button_event(bool state)=0;

		/**
		 * Управление обработкой событий нажития клавиш клавиатуры. По умолчанию - отключено
		 * @param state true - события будут возвращаться через _get_event, false - нет
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 11.01.2008
		 */
		virtual void _enable_keyboard_event(bool state)=0;
		
		/**
		 * Управление обработкой событий ввода печатаемых символов. По умолчанию - отключено
		 * @param state true - события будут возвращаться через _get_event, false - нет
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 11.01.2008
				 */
		virtual void _enable_char_event(bool state)=0;
                
                virtual void _enable_mouse_move_event ( bool state )=0;

		/**
		 *                      Производит отображение всех отрисованных элементов.
		 */
		virtual void _draw() = 0;

		virtual Sint16 _get_width()=0;
		virtual Sint16 _get_height()=0;
		//Write documentation
		virtual bool _init() =0;
		virtual bool _deinit() =0;
		virtual std::string _get_error() =0;

		virtual void _get_mouse_position ( int *x, int *y ) =0;
		virtual void _get_mouse_position ( double *x, double *y ) =0;
		virtual void _get_mouse_state (const MOUSE_BUTTON &button, EVENT_TYPE *state) = 0; 
		virtual Event _get_event() =0;

		virtual bool check_surface_point ( double x_pos, double y_pos, double x_point, double y_point, std::string surface_name, std::string group_name ) =0;
		
		virtual bool _set_mouse_pointer(std::string sprite_name, std::string sprite_group){return false;};
		virtual void _enable_mouse_cursor (bool state){};


		
		Video_Interface() {}
		/**
		 *                      Деструктор видео драйвера. Должен выполнять все требуемые шаги по корректному завершению его работы.
		 * @author Denis A. Birukov aka Messenger of death
		 * @date 30.08.2005
		 */
		virtual ~Video_Interface() {}};
class Video_Surface
{
	public:
		enum ALPHASTATE
		{
		    ALPHA_NO=0,
		    ALPHA_CHANNEL=1
	};

		/** Возвращает указатель на данные о поверхности.*/
		virtual void* _get_surface_data();
		/** Возвращает ширину поверхности в пикселях*/
		virtual int _get_width() const;
		/** Возвращает высоту поверхности в пикселях*/
		virtual int _get_height() const;
		/** Возвращает количество байт на пиксель*/
		virtual int _get_bpp() const;
		/** Возвращает длину строки поверхности*/
		virtual int _get_line_size() const;
		/** Возвращает маску данных красного канала*/
		virtual Uint32 _get_Rmask() const;
		/** Возвращает маску данных синего канала*/
		virtual Uint32 _get_Bmask() const;
		/** Возвращает маску данных зеленого канала*/
		virtual Uint32 _get_Gmask() const;
		/** Возвращает маску данных альфа канала*/
		virtual Uint32 _get_Amask() const;
		/** Присоединяет поверхность к спрайту*/
		virtual void _link_sprite ( std::string sprite_name, std::string sprite_group );
		virtual void _link_sprite ( Video_Sprite *spr );
		/** Создает поверхность требуемого с указанным кол-вом байт на пиксель*/
		virtual bool _create_ ( Uint16 w, Uint16 h );
		/** Производит создание требуемого количества текстур*/
		virtual void _split_texture_ ( Uint16 x, Uint16 y, Uint16 w, Uint16 h, Sint16 *mas, Uint8 len );
		/** Обновляет данные о поверхности */
		virtual void _update_ ( ) =0;
		/** Устанавливает или снимает обработку альфа канала для данной поверхности*/
		virtual void _set_alpha_status ( ALPHASTATE act );
		/** Возвращает признак обработки альфа канала поверхности*/
		virtual ALPHASTATE _get_alpha_status();
		virtual ~Video_Surface();
		Video_Surface();

		struct Video_Surface_Data
		{
			Video_Surface_Data ( Uint16 x, Uint16 y, Uint16 w, Uint16 h ) {_x = x;_y = y;_w = w;_h = h;}
			Uint16 _x;
			Uint16 _y;
			Uint16 _w;
			Uint16 _h;
		};

		void *_surface_;
		Uint32 _Rmask_;
		Uint32 _Gmask_;
		Uint32 _Bmask_;
		Uint32 _Amask_;
		ALPHASTATE _alpha_;
		Uint8 _bpp_;
		Sint16 _w_;
		Sint16 _h_;
//		std::vector<Video_Surface_Data> _tex_;
		bool _need_update_;
		std::vector<std::pair<std::string, std::string> > _sprites_;
		std::vector<Video_Sprite*> _sprites_p_;

};

class Video_Sprite
{
	public:
		/** Изменяет коэффициент масштабирования*/
		virtual void _set_scale ( float x,float y );
		/** Изменяет угол поворота по осям x,y,z*/
		virtual void _set_rotation ( float x,float y,float z );
		/** устанавливает базовую точку(центр) спрайта*/
		virtual void _set_base_point ( double x, double y );
		/** устанавливает базовую точку(центр) спрайта*/
		virtual void _set_base_point ( int x, int y );
		/** Устанавливает прозрачность спрайта*/
		virtual void _set_alpha ( float a );
		/** Устанавливает координаты для вывода спрайта */
		virtual void _set_coord ( double x, double y );
		/** Присоединяет спрайт к поверхности */
		virtual void _set_surface ( Video_Interface *vid, std::string name, std::string group );
		virtual ~Video_Sprite() {};
		Video_Sprite ( std::string spr_name, std::string spr_group, Video_Interface *vid );
		virtual void _set_blend_color(float r, float g, float b);
		
		virtual int _get_height() const {return _h_;}
		virtual int _get_width() const {return _w_;}
		virtual double _get_x() const {return _x_;}
		virtual double _get_y() const {return _y_;}
		virtual double _get_base_x() const {return _base_x_;}
		virtual double _get_base_y() const {return _base_y_;}
		virtual double _get_v_offset(double v_offset);
		virtual double _get_h_offset(double h_offset);
		/** Получение сектора в которую будет отображен спрайт*/
		virtual void _get_rectangle(VideoRect *rect);
		
		std::string _surface_name_;
		std::string _surface_group_;
		std::string _sprite_name_;
		std::string _sprite_group_;
		float _Ablend_;
		float _Rblend_;
		float _Gblend_;
		float _Bblend_;
		float _scale_x_;
		float _scale_y_;
		double _base_x_;
		double _base_y_;
		float _rotation_[3];
		int _w_;
		int _h_;
		double _x_;
		double _y_;
		bool _drawed_;
		bool _need_draw_;
		Video_Interface *_drv_;

};
/** Используется для вывода большого кол-ва однотипных объектов с одинаковыми поверхностями*/
class Video_Particles
{
	public:
		Video_Particles():_surface_name_(""), _surface_group_(""), _base_x_(0.0), _base_y_(0.0), _changed_(true), _count_(0){};
		virtual ~Video_Particles(){};
		/** Установка базовой точки для рисования частиц*/
		virtual void _set_particles_base_coord ( float x, float y ){_base_x_=x; _base_y_=y; _changed_=true;}
		/** Установка параметров отдельной частицы*/
		virtual bool _set_particle ( int particle_num, float x, float y, int r=255, int g=255, int b=255, float a=1.0 )=0;
		/** Получение базовых координат частиц*/
		virtual void _get_particles_base_coord ( float *x, float *y ){*x=_base_x_;*y=_base_y_; _changed_=true;}
		/** получает параметры отдельной частицы*/
		virtual bool _get_particle ( int particle_num, float *x, float *y, int *r=0, int *g=0, int *b=0, float *a=0 )=0;
		virtual void _set_particle_size(int size){_size_=size;}
		
		//Описывают поверхность, могут отсутствовать.
		std::string _surface_name_;
		std::string _surface_group_;
		float _base_x_;
		float _base_y_;
		bool _changed_;
		int _count_;
		int _size_;
};


#endif
