/*
 *  psychlops_io_display.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2009/06/19 by Kenchi HOSOKAWA
 *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_DEVICES_DISPLAY
#define HEADER_PSYCHLOPS_DEVICES_DISPLAY


#include <sstream>
#include <vector>
#include <string>
#include <memory>
#include "../graphic/psychlops_g_shape.h"
#include "../graphic/psychlops_g_font.h"

namespace Psychlops {


	class APIDisplayProperties;
	class APICanvasPropertiesFullscreen;
	class APICanvasPropertiesWindow;
	class Canvas;
	class Display {
		friend class Canvas;
		friend class APICanvasProperties;
		friend class APICanvasPropertiesFullscreen;
		friend class APICanvasPropertiesWindow;
		friend class APIDisplayProperties;

	////////////////	Body of expression of Display devices	////////////////
	private:
		mutable std::auto_ptr<APIDisplayProperties> api_;
		Display(APIDisplayProperties *);

	public:
		int width, height;
		int color_depth;
		double refresh_rate;
		std::string name;
		Rectangle area;

		Display(const Display&);
		~Display();
		Display& operator =(const Display&);
		void refreshInfo();

		static const std::vector<Display> list();
		//static const Display main();
		struct PROPERTY_DISPLAY
		{
			private:
			int N;
			public:
			PROPERTY_DISPLAY(int n);
			operator Display() const;
			int getWidth() const;
			int getHeight() const;
			int getColorDepth() const;
			double getRefreshRate() const;
			Rectangle getArea() const;
		};
		static const PROPERTY_DISPLAY primary;
		static const PROPERTY_DISPLAY secondary;


	////////////////	Maybe replaced by Drawable::prime	////////////////
	public:
		static Canvas *the_canvas;


	////////////////	Wrapper of Canvas	////////////////
	public:
		static void flip(int and_wait_N_vsyncs = 1);
		static void flipAndWait(int and_wait_N_vsyncs);
		static void flipAfter(int frame);
			//	obsolete
			static void displayFrame(void);
			static void displayFrameWithWait(int num_frames_to_wait);
//		static void clear(Canvas::TargetSurface target=Canvas::BACK);
//		static void clear(Color col, Canvas::TargetSurface target=Canvas::BACK);
		enum TargetSurface { ALL=1, BACK=2, FRONT=4 };
		static void clear(TargetSurface target=BACK);
		static void clear(Color col, TargetSurface target=BACK);
		static void setClearColor(Color col);

		////////	Drawing Graphical Elements   ////////
		static void copy(Rectangle &source, const Rectangle &target, bool doesdeletesource=false, const Color &delcol=Color::black);
		static void pix(const double x, const double y, const Color &col);
		static void pix(const Point &po, const Color &col);
		static void pix(int dotsCnt, double x[], double y[], const Color col[]);
		static void pix(int dotsCnt, double x[], double y[], const Color &col);
		static void pix(int dotsCnt, const Point po[], const Color col[]);
		static void line(double x1, double y1, double x2, double y2, const Color &col);
		static void line(const Point &po1, const Point &po2, const Color &col);
		static void line(double x1, double y1, double x2, double y2, const Stroke &strk);
		static void line(const Point &po1, const Point &po2, const Stroke &strk);
		static void rect(const Rectangle &rect, const Color &col);
		static void rect(const int nRects, const Rectangle *rec, const Color &col);
		static void rect(const int nRects, const Rectangle *rec, const Color *col);
		static void rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col);
		static void rect(const Rectangle &rect, const Stroke &strk);
		static void rect(const int nRects, const Rectangle *rec, const Stroke &strk);
		static void rect(const int nRects, const Rectangle *rec, const Stroke *strk);
		static void rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Stroke *strk);
		static void oval(Rectangle &rect, const Color &col);
		static void oval(Rectangle &rect, const Stroke &strk);
		static void ellipse(Rectangle &rect, const Color &col);
		static void ellipse(Rectangle &rect, const Stroke &strk);
		static void ellipse(Ellipse &ell, const Color &col);
		static void ellipse(Ellipse &ell, const Stroke &strk);
		static void polygon(Point *vertices, unsigned int nVertices, const Color &col);
		static void polygon(Point *vertices, unsigned int nVertices, const Stroke &strk);
		static void drawPixel(double x, double y, const Color &col);
		static void drawPixel(const Point &po, const Color &col);
		static void drawPixel(int dotsCnt, double x[], double y[], const Color col[]);
		static void drawPixel(int dotsCnt, double x[], double y[], const Color &col);
		static void drawPixel(int dotsCnt, const Point po[], const Color col[]);
		static void drawLine(double x1, double y1, double x2, double y2, const Color &col);
		static void drawLine(const Point &po1, const Point &po2, const Color &col);
		static void fillRect(const Rectangle &rect, const Color &col);
		static void fillRect(const int nRects, const Rectangle *rec, const Color &col);
		static void fillRect(const int nRects, const Rectangle *rec, const Color *col);
		static void fillRect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col);
		static void fillOval(Rectangle &rect, const Color &col);
		static void drawPolygon(Point *vertices, unsigned int nVertices, const Color &col);

		static void copy(const Rectangle &source, const Rectangle &target, bool doesdeletesource=false, const Color &delcol=Color::black);
		static void to(Image &img, const Rectangle &srcrect);
//		static void to(Image &img, const Rectangle &srcrect, const Rectangle &tgtrect);
		static void drawImage(const Image &img);
		static void drawImage(const Image &img, const double left, const double top);

		////////	Utilities   ////////

		//	FPS Checker
		static void displayFPS();
		static void initFPS();
		static void watchFPS();
		static void ignoreFPS();
		static void showFPS();
		static void hideFPS();
		static int lastFailedFrames();
			//	obsolete
			static void enableFPSChecker();	//	obsolete
			static void disableFPSChecker();	//	obsolete
			static void enableDisplayingFPS();	//	obsolete
			static void disableDisplayingFPS();	//	obsolete

		static void progressbar(Rectangle &inrect, Color fillcol=Color::blue, Color empcol=Color(0.25,0.25,0.25));
		static void progressbar(double l, double t, double r, double b, Color fillcol=Color::blue, Color empcol=Color(0.25,0.25,0.25));
		static void progressbar(double percentage);
//#ifdef __GNUC__
		template <typename X> static void progressbar(X now, X max) { progressbar((double)now/(double)max); }
		private:
		static void var_(const std::string number, const double x, const double y, const Color &col=Color::white, const bool fillForward = false);
		public:
		template <typename X> static void var(X val, double x, double y, const Color &col=Color::white, bool fillForward = false) {
			std::stringstream var_buffer_("");
 			var_buffer_ << val;
			std::string str = var_buffer_.str();
			var_(str, x, y, col, fillForward);
		}
		//template <typename X> static void var(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { var(val, x, y, col, fillForward); };
		template <typename X> static void checkVar(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { var(val, x, y, col, fillForward); }
		template <typename X> static void varcheck(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { var(val, x, y, col, fillForward); }
/*
		template <typename X> static void progressbar(X now, X max) { the_canvas->progressbar((double)now/(double)max); }
		template <typename X> static void var(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { the_canvas->var(val, x, y, col, fillForward); };
		template <typename X> static void checkVar(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { the_canvas->var(val, x, y, col, fillForward); }
			//	obsolete
			template <typename X> static void varcheck(const X val, const double x, const double y, const Color col=Color::white, const bool fillForward=false) { the_canvas->var(val, x, y, col, fillForward); }
*/


		enum { TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT };
		static int msg(const char* string, const double x, const double y, const Color col=Color::white, const int align=TEXT_ALIGN_LEFT, const double max_width=-1.0);
		static int msg(const std::string &string, const double x, const double y, const Color col=Color::white, const int align=TEXT_ALIGN_LEFT, const double max_width=-1.0);
		static int msg(Letters &letters, const double x, const double y, const Color &col=Color::white, const int horiz_align=TEXT_ALIGN_LEFT, const double max_width=-1.0);
		static int msg(const std::wstring &string, const double x, const double y, const Color &col=Color::white, const int horiz_align=Letters::TEXT_ALIGN_LEFT, const double max_width=-1.0);
			//	obsolete alias
			static int showMessage(const char* string, const double x, const double y, const Color col=Color::white, const int align=TEXT_ALIGN_LEFT, const double max_width=-1.0);
			static int showMessage(const std::string &string, const double x, const double y, const Color col=Color::white, const int align=TEXT_ALIGN_LEFT, const double max_width=-1.0);
			static void message(const char* string, const double x, const double y, const Color col=Color::white);	//	obsolete


		static void setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b);
		static void setGammaTable(const std::vector<double> &table_r, const std::vector<double> &table_g, const std::vector<double> &table_b);


		////////	Properties	////////
		static int getWidth();
		static int getHeight();
		static int getColorDepth();
		static double getRefreshRate();
		static double getHcenter();
		static double getVcenter();
		static Point getCenter();
/*		class READ_ONLY_X_ : public Canvas::READ_ONLY_<double> { public: operator double(); };
		class READ_ONLY_Y_ : public Canvas::READ_ONLY_<double> { public: operator double(); };
		class READ_ONLY_CENTER_ : public Canvas::READ_ONLY_POINT_ { public: READ_ONLY_X_ x; READ_ONLY_Y_ y; operator Point(); };
		static READ_ONLY_CENTER_ center;
		class READ_ONLY_REFRESH_ : public Canvas::READ_ONLY_<double> { public: operator double(); };
		static READ_ONLY_REFRESH_ RefreshRate;
*/
	};


}	/*	<- namespace Psycholops 	*/


#endif
