/*
 *  psychlops_g_canvas.cpp
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2006/02/11 by Kenchi HOSOKAWA
 *  (C) 2006 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
 */


#include <math.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <sstream>

#include "../math/psychlops_math.h"
#include "psychlops_g_canvas.h"
#include "psychlops_g_image.h"
#include "../devices/psychlops_io_hid.h"

#define PSYCHLOPS_WINDOW_API_PLATFORM
#include "../../platform/psychlops_platform_selector.h"
#include "../../extension/standard/widgets/psychlops_widget.h"
#include "../../extension/standard/widgets/psychlops_widgets.h"


namespace Psychlops {


	////////	Construct and Destruct  ////////

	Canvas::Canvas(const Canvas&)
		: has_instance_(false), not_time_critical_(false), APIsetColor(0)
	{
	}
	Canvas::Canvas()
		: has_instance_(false), not_time_critical_(false), APIsetColor(0)
	{
	}
	Canvas::Canvas(CanvasMode mode, const Display disp)
		: has_instance_(false), not_time_critical_(false), APIsetColor(0)
	{
		set(mode, disp);
	}
	Canvas::Canvas(int d_width, int d_height, CanvasMode mode, const Display disp)
		: has_instance_(false),  not_time_critical_(false),APIsetColor(0)
	{
		set(d_width, d_height, mode, disp);
	}
	Canvas::Canvas(Rectangle d_rect, CanvasMode mode)
		: has_instance_(false), not_time_critical_(false), APIsetColor(0)
	{
		set(d_rect, mode);
	}
	Canvas::Canvas(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display disp)
		: has_instance_(false), not_time_critical_(false), APIsetColor(0)
	{
		set(d_width, d_height, d_colordepth, d_refreshrate, disp);
	}
	Canvas::~Canvas(void)
	{
		release();
	}


	void Canvas::set(CanvasMode mode, const Display disp) {
		if(has_instance_) throw RESET;
		switch(mode) {
			case fullscreen:
				api = new APICanvasPropertiesFullscreen(disp);
				break;
			case window:
			default:
				api = new APICanvasPropertiesWindow(800,600,disp);
				Mouse::show();
				break;
		}
		has_instance_ = true;
		initProperties();
	}
	void Canvas::set(int d_width, int d_height, CanvasMode mode, const Display disp) {
		api = new APICanvasPropertiesWindow(d_width,d_height, disp);
		has_instance_ = true;
		initProperties();
		Mouse::show();
	}
	void Canvas::set(Rectangle d_rect, CanvasMode mode) {
		api = new APICanvasPropertiesWindow((int)d_rect.getLeft(), (int)d_rect.getTop(), (int)d_rect.getWidth(), (int)d_rect.getHeight());
		has_instance_ = true;
		initProperties();
		Mouse::show();
	}
	void Canvas::set(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display disp) {
		if(has_instance_) throw RESET;
		api = new APICanvasPropertiesFullscreen(d_width, d_height, d_colordepth, d_refreshrate, disp);
		has_instance_ = true;
		initProperties();
	}
	void Canvas::initProperties() {
		not_time_critical_ = false;
		api->outer = this;
		setDefaultCanvas(this);
		initCounters();
		Width =       api->width_;
		Height =      api->height_;
		colordepth =  api->colordepth_;
		refreshrate = api->refreshrate_;
		frameIntervalAccurate = 1000.0/refreshrate;
		center.x.set(Width/2.0);
		center.y.set(Height/2.0);
		RefreshRate.set(getRefreshRate());

		////	Initialize peripheral properties
		initPrimitives();
		setClearColor( Color::black );
		clear_area_.set(Width, Height);
		loadFontMinimum();

		initAPIprop();
		
		if(!api->vsync_available_) {
			Rectangle *rect = new Rectangle(600, 20);
			rect->centering(getCenter().x, getHeight()-20);
			rect->fill = Color::red;
			Letters *let = new Letters(L"Executing without synchronization with Monitor Vsync", Font(12));
			let->datum = rect->getCenter();
			let->shift(0,5);
			let->align = Letters::TEXT_ALIGN_CENTER;
			let->fill = Color::white;
			internal_billboard.push_back(rect);
			internal_billboard.push_back(let);
			billboard.push_back(rect);
			billboard.push_back(let);
		}
		APICanvasPropertiesWindow* iswindow = dynamic_cast<APICanvasPropertiesWindow*>(api);
		if(iswindow) {
			Widgets::TitleBar::default_titlebar = new Widgets::TitleBar(*this);
			billboard.push_back(Widgets::TitleBar::default_titlebar);
		}
		eventroot.root = this;
	}
	void Canvas::initCounters() {
		DISPLAYED_FRAMES=0, FAILED_FRAMES=0, LAST_FAILED_FRAMES = 0, TOTAL_REFRESH=0, FAILED_FLIPS=0, displayedFrames=0, failedFrames=0, lastFailedFrames_=0;
		frameInterval=0.0, frameIntervalAccurate=0.0, frameAccuracy = 0.0;
		rest_wating_vsyncs_=0; time_lastFrame.update(); time_lastFrame_before_flip_.update(); time_init_.update(); checkingFPS=false; checkingFPS_last=false; displayingFPS=false;
		progressbarrect.set(102,12);
		progressbarbordercolor=Color::gray;
		progressbarfillcolor=Color::blue;
		progressbarerrorcolor=Color::magenta;
		progressbaremptycolor.set(0.25,0.25,0.25);
	}

	void Canvas::initPrimitives() {
		setfontLCD();
//		setfontMinimum();
		setFillOvalPrimitives();
	}

	void Canvas::setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b) {
		if(has_instance_) api->setGammaValue(gamma_r, gamma_g, gamma_b);
	}
	void Canvas::setGammaTable(const std::vector<double> &table_r,const std::vector<double> &table_g, const std::vector<double> &table_b) {
		if(has_instance_) api->setGammaTable(table_r, table_g, table_b);
	}
	/*void Canvas::setGammaTable(const Matrix &table_all) {
		if(has_instance_) {
			double *(table[3]);
			int k=0, num_steps=table_all.getCols();
			for(int i=0; i<3; i++) {
				table[i] = new double[num_steps];
				k = i+1;
				for(int j=0; j<num_steps; j++) table[0][j] = (double)table_all(j,i);
			}
			api->setGammaTable(table[0], table[1], table[2], num_steps);
			for(int i=0; i<3; i++) delete [] table[i];
		}
	}*/
	void Canvas::loadFontMinimum() {
		if(!Font::initialized) Font::initializeFontMinimum();
		for(int i=0; i<Font::ASCII_NUM; i++) {
			Font::font_minimum[i].cache(*this);
		}
	}



	//  release
	void Canvas::release() {
		if(has_instance_) {
			if(!internal_billboard.empty()) {
				for(std::vector<Figure*>::iterator i = internal_billboard.begin(); i!=internal_billboard.end(); i++) {
					delete (*i);
				}
			}
			if(!letter_cache.empty()) for(std::list<Letters *>::iterator it=letter_cache.begin(); it!=letter_cache.end(); it++) delete *it;
			if(!img_caches.empty()) {
				for(ImageCache::iterator it=img_caches.begin(); it!=img_caches.end(); it++) {
					uncacheImageBody(*(it->first));
				}
			}
			img_caches.clear();
			if(!let_caches.empty()) {
				for(LettersCache::iterator it=let_caches.begin(); it!=let_caches.end(); it++) {
					//api->uncacheLetters(*(it->first));
					api->uncache(*(it->first));
				}
			}
			let_caches.clear();


			delete api;
		}
		resetDefaultCanvas(this);
		has_instance_ = false;
	}



	void Canvas::setPhysicalSettings(double width, double height, double distance, int horizontalpixs, int varticalpixs) {
		DisplayWidthCentimeter_ = width;
		DisplayHeightCentimeter_ = height;
		DisplayDistanceCentimeter_ = distance;
		DisplayHorizontalPixelNumber_ = horizontalpixs;
		DisplayVerticalPixelNumber_ = varticalpixs;
	}
	int Canvas::horizontalArcdegToPixel(double angle) {
		return (int)(	((double)DisplayHorizontalPixelNumber_/DisplayWidthCentimeter_)   //h_pixels_a_millimeter
						*DisplayDistanceCentimeter_
						*tan(angle*PI/360.0)	//	== tan( (width/2) * (2*PI/360.0) )
						*2.0);
	}
	int Canvas::varticalArcdegToPixel(double angle) {
		return (int)(	((double)DisplayVerticalPixelNumber_/DisplayHeightCentimeter_)   //v_pixels_a_millimeter
						*DisplayDistanceCentimeter_
						*tan(angle*PI/360.0)	//	== tan( (width/2) * (2*PI/360.0) )
						*2.0);
	}
	int Canvas::getDisplayHorizontalPixelNumber() {
		return DisplayHorizontalPixelNumber_;
	}
	int Canvas::getDisplayVerticalPixelNumber() {
		return DisplayVerticalPixelNumber_;
	}




	////////	Drawing Graphical Elements   ////////

	Canvas& Canvas::drawPixel(double x, double y, const Color &col) { pix(x,y,col); return *this; }
	Canvas& Canvas::drawPixel(const Point &po, const Color &col) { return pix(po,col); }
	void Canvas::drawPixel(int dotsCnt, double x[], double y[], const Color col[]) { pix(dotsCnt,x,y,col); }
	void Canvas::drawPixel(int dotsCnt, double x[], double y[], const Color &col=Color::white) { pix(dotsCnt,x,y,col); }
	void Canvas::drawPixel(int dotsCnt, const Point po[], const Color col[]) { pix(dotsCnt,po,col); }
	void Canvas::drawLine(double x1, double y1, double x2, double y2, const Color &col) { line(x1, y1, x2, y2, col); }
	void Canvas::drawLine(const Point &po1, const Point &po2, const Color &col) { line(po1,po2,col); }
	Canvas& Canvas::fillRect(const Rectangle &rec, const Color &col) { return rect(rec,col); }
	Canvas& Canvas::fillRect(const int nRects, const Rectangle *rec, const Color &col) { return rect(nRects,rec,col); }
	Canvas& Canvas::fillRect(const int nRects, const Rectangle *rec, const Color *col) { return rect(nRects,rec,col); }
	Canvas& Canvas::fillRect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col) { return rect(nRectsBegin,nRectsEnd,rec,col); }
	Canvas& Canvas::fillOval(const Rectangle &rect, const Color &col) { return ellipse(rect,col); }
	Canvas& Canvas::oval(const Ellipse &drawee, const Color &col) { return ellipse(drawee, col); }
	Canvas& Canvas::oval(const Ellipse &drawee, const Stroke &strk) { return ellipse(drawee, strk); }
	Canvas& Canvas::oval(const Rectangle &rect, const Color &col) { return ellipse(rect, col); }
	Canvas& Canvas::oval(const Rectangle &rect, const Stroke &strk) { return ellipse(rect, strk); }
	void Canvas::drawPolygon(Point *vertices, unsigned int nVertices, const Color &col) { polygon(vertices, nVertices, col); }


	template void Canvas::var<int>(int val, double x, double y, const Color &col, bool fillForward);
	template void Canvas::var<double>(double val, double x, double y, const Color &col, bool fillForward);
	int Canvas::msg(const std::string &string, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max__width) { return msg(string.c_str(),x,y,col,horiz_align,vertical_align,max__width); }
	int Canvas::showMessage(const char* string, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max__width) { return msg(string,x,y,col,horiz_align,vertical_align,max__width); }
	int Canvas::showMessage(const std::string &string, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max__width) { return msg(string.c_str(),x,y,col,horiz_align,vertical_align,max__width); }
		//	obsolete
		void Canvas::message(const char* string, const double x, const double y, const Color &col) { msg(string,x,y,col); }	//	obsolete
	int Canvas::msg(const std::wstring &string, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max_width) {
		Letters *out = 0;
		std::list<Letters *>::iterator it;
		for(it=letter_cache.begin(); it!=letter_cache.end(); it++) {
			if((**it).str==string) {
				out = *it;
				//letter_cache.erase(it);
				//letter_cache.push_front(out);
			}
		}
		if(out==0) {
			out = new Letters(string);
			letter_cache.push_front(out);
			if(letter_cache.size()>10) {
				delete letter_cache.back();
				letter_cache.pop_back();
			}
		}
		return msg(*out,x,y,col,horiz_align,max_width);
	}
	Canvas& Canvas::letters(Letters &letters, const Color &col) {
		if(let_caches.count(&letters)==0) cacheLetters(letters);
		msg(letters, letters.getDatum().x, letters.getDatum().y, col, letters.align);
		return *this;
	}
	void Canvas::cacheLetters(Letters &letters) {
		//api->cacheLetters(letters);
		api->cache(letters);
		if(let_caches.count(&letters)==0) let_caches.insert(std::pair<Letters*, Letters::Cache*>(&letters, &(letters.caches[this]) ));
	}
	void Canvas::uncacheLetters(Letters &letters) {
		//api->uncacheLetters(letters);
		api->uncache(letters);
		if(let_caches.count(&letters)!=0) let_caches.erase(&letters);
	}
	void Canvas::cacheImage(Image &img) {
		cacheImageBody(img);
		if(img_caches.count(&img)==0) img_caches.insert(std::pair<Image*, ImageCache_*>(&img, &(img.caches[this]) ));
	}
	void Canvas::uncacheImage(Image &img) {
		uncacheImageBody(img);
		if(img_caches.count(&img)!=0) img_caches.erase(&img);
	}


/*
	int Canvas::msg(const std::string &string, const double x, const double y, const double max_width, const int align, const Color col) {
		return msg(string.c_str(), x, y, max_width, align, col);
	}
	void Canvas::showMessage(const char* string, const double x, const double y, const Color col) { msg(string,x,y,col); }
	void Canvas::showMessage(const std::string &string, const double x, const double y, const Color col) { msg(string,x,y,col); }
	int Canvas::showMessage(const char* string, const double x, const double y, const double max_width, const int align, const Color col) { return msg(string,x,y,max_width,align,col); }
	int Canvas::showMessage(const std::string &string, const double x, const double y, const double max_width, const int align, const Color col) { return msg(string,x,y,max_width,align,col); }
		//	obsolete
		//void Canvas::varcheck(const int number, const double x, const double y, const Color col, const bool fillForward) { var(number,x,y,col,fillForward); }	//	obsolete
		void Canvas::message(const char* string, const double x, const double y, const Color col) { msg(string,x,y,col); }	//	obsolete
*/


	////	Drawing Images

	Canvas& Canvas::image(const Image &img) {
		drawImage(img, img.targetarea_.getLeft(), img.targetarea_.getTop());
		return *this;
	}
	void Canvas::drawImage(const Image &img) {
		drawImage(img, img.targetarea_.getLeft(), img.targetarea_.getTop());
	}
	Canvas& Canvas::image(const Image &img, const double left, const double top) {
		drawImage(img, left, top);
		return *this;
	}


	////////	Critical Operations ////////
	void Canvas::flipAndWait(const int frame_duration_by_vsyncs) {
		flip(frame_duration_by_vsyncs);
	}
	void Canvas::flipAfter(const int frame_duration_by_vsyncs) {
		rest_wating_vsyncs_ += frame_duration_by_vsyncs-1;
		flip(1);
	}
	void Canvas::flip(float N) { throw Exception(typeid(*this), "Specification Error", "Canvas::flip can not accept float point number."); }
	void Canvas::flip(double N) { throw Exception(typeid(*this), "Specification Error", "Canvas::flip can not accept float point number."); }
		//	obsolete
		void Canvas::displayFrame(void) { flip(1); }
		void Canvas::displayFrameWithWait(int nextframe) { flip(nextframe); }
		void Canvas::displayFrameWithWait(double N) { flip(N); }

	Canvas& Canvas::clear(const Color &col) {
		return clear(col, BACK);
	}
	Canvas& Canvas::clear(TargetSurface target) {
		return clear(bgcolor_, target);
	}
	void Canvas::setClearColor(Color col) {
		bgcolor_ = col;
	}



	////////	Utilities   ////////
	void Canvas::progressbar(Rectangle &inrect, Color fillcol, Color empcol) {
		progressbarrect = inrect;
		progressbarfillcolor = fillcol;
		progressbaremptycolor = empcol;
	}
	void Canvas::progressbar(double l, double t, double r, double b, Color fillcol, Color empcol) {
		Rectangle tmprect(l,t,r,b);
		progressbar(tmprect, fillcol, empcol);
	}





	////////	DISPLAY UTILITIES   ////////
	void Canvas::displayFPS() {
		int line_height = font_LCD_height+3, line_offset = 20;
		Rectangle baserect(Width-100, 1, Width-2, (int)(line_height*3.5));
		APICanvasPropertiesWindow* iswindow = dynamic_cast<APICanvasPropertiesWindow*>(api);
		if(iswindow) {
			baserect.shift(0, 20);
		}
		//glPushAttrib(GL_ALL_ATTRIB_BITS);
		//glEnable(GL_BLEND);
		Color fgcol(1.0,1.0,1.0), bgcol(0.0,0.0,0.0,0.5);
		fillRect(baserect, bgcol);
		//glDisable(GL_BLEND);
		//glPopAttrib();


		char digit[64];
		sprintf(digit, "%li", FAILED_FRAMES);
		var_(digit, (double)(baserect.right-10.0), (double)(baserect.top+line_offset), Color::red, false);
		sprintf(digit, "%li", (TOTAL_REFRESH));
		var_(digit, baserect.right-10, baserect.top+line_height+line_offset, Color::white, false);
		if(LAST_FAILED_FRAMES>0) fgcol=Color::red;
		else if(frameInterval>frameIntervalAccurate) fgcol=Color::cyan;
		else fgcol=Color::white;
		sprintf(digit, "%i", (int)(frameInterval));
		var_(digit, baserect.right-10, baserect.top+line_height*2+line_offset, fgcol, false);
	}
	void Canvas::initFPS() {
		failedFrames = 0;
		displayedFrames = 0;
		FAILED_FRAMES = 0;
		DISPLAYED_FRAMES = 0;
		TOTAL_REFRESH = 0;
	}
	void Canvas::watchFPS() {
		checkingFPS = true;
		time_lastFrame.update();
	}
	void Canvas::ignoreFPS() {
		checkingFPS = false;
		checkingFPS_last = false;
	}
	void Canvas::showFPS() {
		displayingFPS = true;
	}
	void Canvas::hideFPS() {
		displayingFPS = false;
	}
	int Canvas::lastFailedFrames() {
		return lastFailedFrames_;
	}
		//	obsolete
		void Canvas::enableFPSChecker() { watchFPS(); }
		void Canvas::disableFPSChecker() { ignoreFPS(); }
		void Canvas::enableDisplayingFPS() { showFPS(); }
		void Canvas::disableDisplayingFPS() { hideFPS(); }



	////////	AUX	////////
	void Canvas::makeTimeCritical(bool b) { not_time_critical_ = !b; }
	bool Canvas::isTimeCritical() const { return !(not_time_critical_); }


	////////	GET ELEMENT   ////////
	int Canvas::getWidth() const { return Width; }
	int Canvas::getHeight() const { return Height; }
	int Canvas::getColorDepth() const { return colordepth; }
	double Canvas::getRefreshRate() const { return refreshrate; }
	double Canvas::getHcenter() const { return Width/2 - 0.5; }
	double Canvas::getVcenter() const { return Height/2 - 0.5;	}
	const Point Canvas::getCenter() const {
		Point po(getHcenter(), getVcenter());
		return po;
	}
	Canvas::READ_ONLY_POINT_::READ_ONLY_POINT_() {}
	Canvas::READ_ONLY_POINT_::operator Point() const { return Point(x,y); }


	void Canvas::setDefaultCanvas(Canvas *cnvs) {
		if(Display::the_canvas==0) Display::the_canvas = cnvs;
		if(Drawable::prime==Drawable::dummy) Drawable::prime = cnvs;
		if(DrawableWithCache::prime==0) DrawableWithCache::prime = cnvs;
		if(!Drawable::billboard.contents.empty()) {
			cnvs->billboard.push_back(&Drawable::billboard);
		}
	}
	void Canvas::resetDefaultCanvas(Canvas *cnvs) {
		if(Display::the_canvas==cnvs) Display::the_canvas = 0;
		if(Drawable::prime==cnvs) Drawable::prime = const_cast<Drawable*>(Drawable::dummy);
		if(DrawableWithCache::prime==cnvs) DrawableWithCache::prime = 0;
	}

	Point Canvas::mouse() const {
		Point p = api->left_top();
		return Point(Mouse::uniX-p.x, Mouse::uniY-p.y);
	}
	Point Canvas::mouse(const Point &pp) const {
		Point p = pp;
		p = p + api->left_top();
		return Mouse::uniPosition = p;
	}



	void Canvas::getBubble(const char* ev)
	{
		if(ev==Events::Focus::name) ;
	}


	Canvas * Display::the_canvas;



	Canvas::Geometry::Geometry() {}
	Canvas::Geometry::Geometry(double dist, double horiz, double vert, Canvas &cnvs) {
		dist_cm = dist;
		horiz_cm = horiz;
		vert_cm = vert;
		horiz_pix = cnvs.getWidth();
		vert_pix = cnvs.getHeight();
		horiz_pix_per_cm = horiz_pix / horiz_cm;
		vert_pix_per_cm = vert_pix / vert_pix;
	}
	const double Canvas::Geometry::pixels(double visual_angle) {
		return tan(visual_angle/360.0*2.0*PI) * dist_cm * horiz_pix_per_cm;
	}



//	void Display::flip(void) { the_canvas->flip(); }
	void Display::flip(int and_wait_N_vsyncs) { the_canvas->flip(and_wait_N_vsyncs); }
	void Display::flipAndWait(int and_wait_N_vsyncs) { the_canvas->flip(and_wait_N_vsyncs); }
	void Display::flipAfter(int frame) { the_canvas->flipAfter(frame); }

		//	obsolete
		void Display::displayFrame() { the_canvas->flip(); }
		void Display::displayFrameWithWait(int num_frames_to_wait) { the_canvas->flip(num_frames_to_wait); }
//	void Display::clear(Color col, Canvas::TargetSurface target) { the_canvas->clear(col, target); }
//	void Display::clear(Canvas::TargetSurface target) { the_canvas->clear(target); }
	void Display::clear(Color col, TargetSurface target) { the_canvas->clear(col, (Canvas::TargetSurface)target); }
	void Display::clear(TargetSurface target) { the_canvas->clear((Canvas::TargetSurface)target); }
	void Display::setClearColor(Color col) { the_canvas->setClearColor(col); }

	////////	DISPLAY GRAPHIC ELEMENT   ////////
	void Display::copy(Rectangle &source, const Rectangle &target, bool doesdeletesource, const Color &delcol) { the_canvas->copy(source, target, doesdeletesource, delcol); }
	void Display::pix(const double x, const double y, const Color &col) { the_canvas->pix(x, y, col); }
	void Display::pix(const Point &po, const Color &col) { the_canvas->pix(po, col); }
	void Display::pix(int dotsCnt, double x[], double y[], const Color col[]) { the_canvas->pix(dotsCnt, x, y, col); }
	void Display::pix(int dotsCnt, double x[], double y[], const Color &col) { the_canvas->pix(dotsCnt, x,y, col); }
	void Display::pix(int dotsCnt, const Point po[], const Color col[]) { the_canvas->pix(dotsCnt, po, col); }
	void Display::line(double x1, double y1, double x2, double y2, const Color &col) { the_canvas->line(x1, y1, x2, y2, col); }
	void Display::line(const Point &po1, const Point &po2, const Color &col) { the_canvas->line(po1, po2, col); }
	void Display::line(double x1, double y1, double x2, double y2, const Stroke &strk) { the_canvas->line(x1, y1, x2, y2, strk); }
	void Display::line(const Point &po1, const Point &po2, const Stroke &strk) { the_canvas->line(po1, po2, strk); }
	void Display::rect(const Rectangle &rect, const Color &col) { the_canvas->rect(rect, col); }
	void Display::rect(const int nRects, const Rectangle *rec, const Color &col) { the_canvas->rect(nRects,rec,col); }
	void Display::rect(const int nRects, const Rectangle *rec, const Color *col) { the_canvas->rect(nRects,rec,col); }
	void Display::rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col) { the_canvas->rect(nRectsBegin,nRectsEnd,rec,col); }
	void Display::rect(const Rectangle &rect, const Stroke &strk) { the_canvas->rect(rect, strk); }
	void Display::rect(const int nRects, const Rectangle *rec, const Stroke &strk) { the_canvas->rect(nRects,rec,strk); }
	void Display::rect(const int nRects, const Rectangle *rec, const Stroke *strk) { the_canvas->rect(nRects,rec,strk); }
	void Display::rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Stroke *strk) { the_canvas->rect(nRectsBegin,nRectsEnd,rec,strk); }
	void Display::oval(Rectangle &rect, const Color &col) { the_canvas->ellipse(rect, col); }
	void Display::oval(Rectangle &rect, const Stroke &strk) { the_canvas->ellipse(rect, strk); }
	void Display::ellipse(Rectangle &rect, const Color &col) { the_canvas->ellipse(rect, col); }
	void Display::ellipse(Rectangle &rect, const Stroke &strk) { the_canvas->ellipse(rect, strk); }
	void Display::ellipse(Ellipse &ell, const Color &col) { the_canvas->ellipse(ell, col); }
	void Display::ellipse(Ellipse &ell, const Stroke &strk) { the_canvas->ellipse(ell, strk); }
	void Display::polygon(Point *vertices, unsigned int nVertices, const Color &col) { the_canvas->polygon(vertices, nVertices, col); }
	void Display::polygon(Point *vertices, unsigned int nVertices, const Stroke &strk) { the_canvas->polygon(vertices, nVertices, strk); }
	void Display::drawPixel(double x, double y, const Color &col) { the_canvas->pix(x, y, col); }
	void Display::drawPixel(const Point &po, const Color &col){ the_canvas->pix(po,col); }
	void Display::drawPixel(int dotsCnt, double x[], double y[], const Color col[]) { the_canvas->pix(dotsCnt, x, y, col); }
	void Display::drawPixel(int dotsCnt, double x[], double y[], const Color &col) { the_canvas->pix(dotsCnt, x, y, col); }
	void Display::drawPixel(int dotsCnt, const Point po[], const Color col[]) { the_canvas->pix(dotsCnt, po, col); }
	void Display::drawLine(double x1, double y1, double x2, double y2, const Color &col) { the_canvas->line(x1, y1, x2, y2, col); }
	void Display::drawLine(const Point &po1, const Point &po2, const Color &col) { the_canvas->line(po1, po2, col); }
	void Display::fillRect(const Rectangle &rect, const Color &col) { the_canvas->rect(rect, col); }
	void Display::fillRect(const int nRects, const Rectangle *rec, const Color &col) { the_canvas->rect(nRects,rec,col); }
	void Display::fillRect(const int nRects, const Rectangle *rec, const Color *col) { the_canvas->rect(nRects,rec,col); }
	void Display::fillRect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col) { the_canvas->rect(nRectsBegin,nRectsEnd,rec,col); }
	void Display::fillOval(Rectangle &rect, const Color &col) { the_canvas->oval(rect, col); }
	void Display::drawPolygon(Point *vertices, unsigned int nVertices, const Color &col) { the_canvas->polygon(vertices, nVertices, col); }

	void Display::copy(const Rectangle &source, const Rectangle &target, bool doesdeletesource, const Color &delcol) { the_canvas->copy(source, target, doesdeletesource, delcol); }
	void Display::to(Image &img, const Rectangle &srcrect) { the_canvas->to(img, srcrect); }
//	void Display::to(Image &img, const Rectangle &srcrect, const Rectangle &tgtrect) { the_canvas->to(img, srcrect, tgtrect); }
	void Display::drawImage(const Image &img) { the_canvas->drawImage(img); }
	void Display::drawImage(const Image &img, const double left, const double top) { the_canvas->drawImage(img, left, top); }

	////////	DISPLAY UTILITIES   ////////
	//	FPS Checker
	void Display::initFPS() { the_canvas->initFPS(); }
	void Display::watchFPS() { the_canvas->watchFPS(); }
	void Display::ignoreFPS() { the_canvas->ignoreFPS(); }
	void Display::showFPS() { the_canvas->showFPS(); }
	void Display::hideFPS() { the_canvas->hideFPS(); }
	int Display::lastFailedFrames() { return the_canvas->lastFailedFrames(); }
		//	obsolete
		void Display::enableFPSChecker() { the_canvas->enableFPSChecker(); }	//	obsolete
		void Display::disableFPSChecker() { the_canvas->disableFPSChecker(); }	//	obsolete
		void Display::enableDisplayingFPS() { the_canvas->enableDisplayingFPS(); }	//	obsolete
		void Display::disableDisplayingFPS() { the_canvas->disableDisplayingFPS(); }	//	obsolete

	void Display::progressbar(Rectangle &inrect, Color fillcol, Color empcol) { the_canvas->progressbar(inrect, fillcol, empcol); }
	void Display::progressbar(double l, double t, double r, double b, Color fillcol, Color empcol) { the_canvas->progressbar(l, t, r, b, fillcol, empcol); }
	void Display::progressbar(double percentage) { the_canvas->progressbar(percentage); }

	//void Display::var(const int number, const double x, const double y, const Color col, const bool fillForward) { the_canvas->var(number, x, y, col, fillForward); }
	void Display::var_(const std::string number, const double x, const double y, const Color &col, const bool fillForward) { the_canvas->var_(number, x, y, col, fillForward); }
	int Display::msg(const char* string, const double x, const double y, const Color col, const int horiz_align, const double max_width) { return the_canvas->msg(string, x, y, col, horiz_align, max_width); }
	int Display::msg(const std::string &string, const double x, const double y, const Color col, const int horiz_align, const double max_width) { return the_canvas->msg(string, x, y, col, horiz_align, max_width); }
	//void Display::checkVar(const int number, const double x, const double y, const Color col, const bool fillForward) { the_canvas->var(number, x, y, col, fillForward); }
	int Display::showMessage(const char* string, const double x, const double y, const Color col, const int align, const double max_width) { return the_canvas->msg(string, x, y, col, align, max_width); }
	int Display::showMessage(const std::string &string, const double x, const double y, const Color col, const int align, const double max_width) { return the_canvas->msg(string, x, y, col, align, max_width); }
		//	obsolete
		//void Display::varcheck(int number, double x, double y, Color col, bool fillForward) { the_canvas->var(number, x, y, col, fillForward); }	//	obsolete
		void Display::message(const char* string, const double x, const double y, const Color col) { the_canvas->msg(string, x, y, col); }	//	obsolete
	int Display::msg(Letters &letters, const double x, const double y, const Color &col, const int horiz_align, const double max_width)  { return the_canvas->msg(letters, x, y, col, horiz_align, max_width); }
	int Display::msg(const std::wstring &string, const double x, const double y, const Color &col, const int horiz_align, const double max_width) { return the_canvas->msg(string, x, y, col, horiz_align, max_width); }


	void Display::setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b) { the_canvas->setGammaValue(gamma_r, gamma_g, gamma_b); }
	void Display::setGammaTable(const std::vector<double> &table_r,const std::vector<double> &table_g, const std::vector<double> &table_b) { the_canvas->setGammaTable(table_r, table_g, table_b); }

	////////	GET DISPLAY PROPERTY	////////
	int Display::getWidth() { return the_canvas->getWidth();}
	int Display::getHeight() { return the_canvas->getHeight(); }
	int Display::getColorDepth() { return the_canvas->getColorDepth();}
	double Display::getRefreshRate() { return the_canvas->getRefreshRate(); }
	double Display::getHcenter() { return the_canvas->getHcenter(); }
	double Display::getVcenter() { return the_canvas->getVcenter(); }
	Point Display::getCenter() { return the_canvas->getCenter(); }

/*
	Display::READ_ONLY_X_::operator double() { return getHcenter(); };
	Display::READ_ONLY_Y_::operator double() { return getVcenter(); };
	Display::READ_ONLY_CENTER_::operator Point() { return Point(getHcenter(),getVcenter()); };
	Display::READ_ONLY_CENTER_ Display::center;
	Display::READ_ONLY_REFRESH_::operator double() { return getRefreshRate(); }
	Display::READ_ONLY_REFRESH_ Display::RefreshRate;
*/



}	/*	<- namespace Psycholops 	*/

