#ifndef HEADER_PSYCHLOPS_GRAPHIC_API_WIN32
#define HEADER_PSYCHLOPS_GRAPHIC_API_WIN32

#include <vector>
#include <string>

#include <windows.h>
#include <gl/gl.h>


#include "../../core/graphic/psychlops_g_image.h"
#include "../../core/graphic/psychlops_g_font.h"
#include "../gl/psychlops_g_cache.h"


namespace Psychlops {

	class Canvas;
	class DebugTweakTool;
	class APICanvasProperties {
		friend class Canvas;
		friend class DebugTweakTool;
		public:
		enum WINDOW_TYPE { FULLSCREEN, WINDOW };

	protected:
		static WNDCLASSEX wcx;
		static bool wcx_setted;
		static void setWindowClass();

	public:

		HDC the_display_;				//	Handle for Device Context
		HWND the_window_;			//	Handle for Window
		HGLRC the_GL_context_;			//	Handle for OpenGL Context
		DEVMODE mode_, original_mode_;
		int vleft, vright, vtop, vbottom;

		bool has_instance_;
		bool vsync_available_;
		WINDOW_TYPE window_type;
		BOOL err;

	public:
		Canvas *outer;
		int width_, height_, colordepth_;
		double refreshrate_;

	public:
		APICanvasProperties();
		virtual ~APICanvasProperties();
		void getDisplayMertix(const Display& d);
		void generateCanvasInstance(const Display& d);
		void generateCanvasInstance(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display& d);
		void generateCanvasInstance(DEVMODE &d_mode, const Display& d);
		void destroyCanvasInstance();
	protected:
		void attachOpenGLContext(HWND *hWnd, HDC *hDC, HGLRC *hRC, int d_colordepth);
		void detachOpenGLContext(HWND hWnd, HDC hDC, HGLRC hRC);

	////	Gamma Table Section
	public:
		void flip();
	/*
		// OLD
		void cacheLetters(Letters &letter);
		void uncacheLetters(Letters &letter);
		void drawLetters(
			Letters &letters, const double x, const double y,
			const double r, const double g, const double b, const double a,
			const int horiz_align, const double max_width);

		// NEW
	protected:
		class TextCacheAllocation
		{
			public:
			bool dirty_;
			Image img;
			TextCacheAllocation();
			~TextCacheAllocation();
			void dirty();
			void uncache();
		};
		std::map<Letters*, TextCacheAllocation *> text_cache;
		bool isCached(Letters &letters);
		*/
	protected:
		Utilities::TextCacheManager text_cache;
	public:
		void draw(
			Letters &letters, const double x, const double y,
			const double r, const double g, const double b, const double a,
			const int horiz_align, const int vertical_align, const double max_width);
		//void draw(Letters &letters);
		void cache(Letters &letters);
		void uncache(Letters &letters);
		void uncacheAllLetters();
		void cacheText(Letters &drawee, Utilities::CacheOnImage &alloc);


	////	Gamma Table Section
	public:
		enum { RAMP_STEPS_ = 256 };
		struct GAMMA_RAMP_TABLE {
			WORD r[RAMP_STEPS_];
			WORD g[RAMP_STEPS_];
			WORD b[RAMP_STEPS_];
		};
		GAMMA_RAMP_TABLE savedGammaRamp_;
		LPVOID savedGammaRamp_ptr_;
		int calibration_mode_;

		double limit(double v);
		void setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b);
		void setGammaTable(const std::vector<double> &table_r, const std::vector<double> &table_g, const std::vector<double> &table_b);
		void setGammaTable(LPVOID table);
		void saveGammaValue();
		int getGammaMode();
		void destroyGammaSettings();
		/*	Psychlops is not event-message based application,
			thus we omit "main loop" recieving mesasges from Windows OS or other applications.
			PsychlopsAPP recieves messages through Canvas::flip(),
			or recieve on main loop and "virtual main" function runs on another thread.	*/
		Point left_top();

		void shift(int x, int y);
	};

	class APICanvasPropertiesFullscreen : public APICanvasProperties {
	public:
		APICanvasPropertiesFullscreen(const Display &target);
		APICanvasPropertiesFullscreen(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display &target);
	};

	class APICanvasPropertiesWindow : public APICanvasProperties {
	public:
		APICanvasPropertiesWindow(int d_width, int d_height, const Display& d);
		APICanvasPropertiesWindow(int d_left, int d_top, int d_width, int d_height);
		virtual ~APICanvasPropertiesWindow();
		void generate(int d_left, int d_top, int d_width, int d_height);
	};


	class Image;
	namespace Devices { class CanvasBits; }
	class APIImageCache {
		friend class Canvas;
		friend class Image;
		friend class Devices::CanvasBits;
		public:
		GLuint VRAMoffset, tex_width, tex_height;
		APIImageCache();
		unsigned int getTexIndex();
	};
	class APIImageProperties {
		friend class Canvas;
		friend class Image;
		friend class Devices::CanvasBits;
		private:
//		static int max_reg, rights_[10+1], bottoms_[10+1];

		const Image *outer_;
		static const int PixCompGL_[3];
		static const int PixPrecGL_[2];

		public:
//		static bool regist(int maxwidth, int maxheight, int width, int height, int &left, int &top);
		APIImageProperties();
		APIImageProperties(Image *outer);
		virtual ~APIImageProperties();
		void attach();
		void detach();
		void drawText(int x, int y, const char* str, int strlength);
	};

	class APIFontProperties {
		protected:
		bool cached;
		GLuint cache_id, length;
		double base_width, base_height;
		GLushort *lists;
		static const GLushort lists100[100];

		public:
		APIFontProperties();
		virtual ~APIFontProperties();
		void uncache();
		void uncache(const HDC &ctx);
		void cache(const HDC &ctx, Letters &letters);
		void culcVirtualMetrix(Letters &letters);
		void draw(const HDC &ctx,
			const Letters &letters, const double x, const double y,
			const double r, const double g, const double b, const double a,
			const int horiz_align, const double max_width) const;

	};



}	/*	<- namespace Psycholops 	*/

#endif

