/*
 *  psychlops_g_canvas_API_OSX.h
 *  Psychlops Standard Library (MacOSX)
 *
 *  Last Modified 2005/12/24 by Kenchi HOSOKAWA
 *  (C) 2005 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_GRAPHIC_API_OSX
#define HEADER_PSYCHLOPS_GRAPHIC_API_OSX

#include <vector>

#include <ApplicationServices/ApplicationServices.h>
#include <CoreServices/CoreServices.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <AGL/agl.h>

#include <mach/mach.h>
#include <mach/mach_time.h>

#include "../../core/graphic/psychlops_g_font.h"
#include "../../core/graphic/psychlops_g_Image.h"


namespace Psychlops {
	
	class Canvas;
	class Display;
	class APICanvasProperties;
	class APIImageProperties;
	class APIFontProperties;
	class DebugTweakTool;
	
	
	struct WindowMetrix {
	public:
		int width, height, colordepth;
		double refreshrate;
	};
	
	class APICanvasProperties {
	public:
		bool vsync_available_;
		Canvas *outer;
	protected:
		bool has_instance_;
		OSStatus err;
		CGDirectDisplayID target_display_;
		//		CGDisplayErr disperr;
		CFDictionaryRef current_mode_, original_mode_;
		CGGammaValue
		savedRedMin_, savedRedMax_, savedRedGamma_,
		savedGreenMin_, savedGreenMax_, savedGreenGamma_,
		savedBlueMin_, savedBlueMax_, savedBlueGamma_;
		int gamma_mode_;
		CGContextRef quartz_context_;
		
	public:
		int width_, height_, colordepth_;
		double refreshrate_;
		
	public:
		APICanvasProperties();
		virtual ~APICanvasProperties();
		virtual void flip() = 0;
		
		WindowMetrix getDisplayMetrix(CGDirectDisplayID target);
		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(const CGGammaValue * const table_r, const CGGammaValue * const table_g, const CGGammaValue * const table_b, const int num_steps);
		void saveGammaValue();
		void destroyGammaSettings();
		
		//void cacheLetters(Letters &letter);
		//void uncacheLetters(Letters &letter);
		void cache(Letters &letter);
		void uncache(Letters &letter);
		void drawLetters(
						 Letters &letters, const double x, const double y,
						 const Color & col,
						 //			const double r, const double g, const double b, const double a,
						 const int horiz_align, const int vertical_align, const double max_width);
		virtual Point left_top() = 0;
	};
	
	class APICanvasPropertiesFullscreen : public APICanvasProperties {
	private:
		CGLContextObj cgl_context_;
		CGOpenGLDisplayMask dispOpenGLDisplayMask;
		Point lefttop;
	public:
		APICanvasPropertiesFullscreen(const Display &target);
		APICanvasPropertiesFullscreen(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display &target);
		virtual ~APICanvasPropertiesFullscreen();
		void generateCanvasInstance(const Display &target);
		void generateCanvasInstance(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display &target);
		void generateCanvasInstance(CFDictionaryRef d_mode, CGDirectDisplayID target);
		void destroyCanvasInstance();
		virtual void flip();
		virtual void waitRefresh();
		virtual Point left_top();
	};
	
	class APICanvasPropertiesWindow : public APICanvasProperties {
		friend class DebugTweakTool;
	private:
		void *api_objc_;
		WindowRef window_;
		AGLContext agl_context_;
		Point lefttop;
	public:
		APICanvasPropertiesWindow();
		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 generateCanvasInstance(int d_left, int d_top, int d_width, int d_height);
		void destroyCanvasInstance();
		virtual void flip();
		virtual Point left_top();
	};
	
	
	class Image;
	class APIImageCache {
		friend class Canvas;
		friend class Image;
		friend class APIFontProperties;
	public:
		GLuint VRAMoffset, tex_width, tex_height;
		unsigned int getTexIndex();
	};
	class Devices::CanvasBits;
	class APIImageProperties {
		friend class Canvas;
		friend class Image;
		friend class APIFontProperties;
		friend class Devices::CanvasBits;
	private:
		//		static int max_reg, rights_[10+1], bottoms_[10+1];
		
		const Image *outer_;
		CGContextRef pic_;
		CGColorSpaceRef colorSpace;
		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_);
		~APIImageProperties();
		void attach();
		void detach();
		/*		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);*/
	};
	
	
	class APIFontProperties {
	protected:
		bool cached, layout_defined;
		UniChar* theUnicodeText;
		ATSUStyle theStyle;
		ATSUTextLayout theLayout;
		Image cache_img;
		int cache_w, cache_h, cache_baseX, cache_baseY;
		
	public:
		APIFontProperties();
		virtual ~APIFontProperties();
		void cache(const CGContextRef &ctx, Letters &letters, DrawableWithCache &target);
		void uncache(const CGContextRef &ctx, Letters &letters);
		void draw(const CGContextRef &ctx, const Letters &letters, const double x, const double y, const Color &col, const int horiz_align, const double max_width, DrawableWithCache &target);
		void setLayout(Letters &letters);
		void cache_on_context(const CGContextRef &ctx);
		void draw_on_context(const CGContextRef &ctx, const float posX, const float posY, const double r,  const double g,  const double b, const double a);
		void cache_on_image(Letters &letters, DrawableWithCache &target);
		void draw_cached_image(const double posX, const double posY, const Color &col, DrawableWithCache &target);
	};
	
}	/*	<- namespace Psycholops 	*/


#endif

