/*
 *  psychlops_io_display_Win32.cpp
 *  Psychlops Standard Library (Win32)
 *
 *  Last Modified 2009/03/02 by Kenchi HOSOKAWA
 *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */


#include <string>
#include <windows.h>
#include "../../core/graphic/psychlops_g_canvas.h"
#include "psychlops_io_display_Win32.h"



namespace Psychlops {

	Displays APIDisplayProperties::displays;

	BOOL CALLBACK APIDisplayProperties::DisplayEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
		APIDisplayProperties *api = new APIDisplayProperties;
		api->monitor_ = hMonitor;
		//api.display_ = CreateDC("DISPLAY".ptr, hMonitor, null, null);
		Display monitor(api);
		displays.push_back(monitor);
		return TRUE;
	}


	APIDisplayProperties::APIDisplayProperties() :
		display_(0)
//		calibration_mode_(Color.CalibrationMode.NONE);
	{}

	APIDisplayProperties::~APIDisplayProperties() {
		if(display_ != 0) DeleteDC(display_);
	}

	Displays APIDisplayProperties::emumDisplays() {
		displays.clear();
		EnumDisplayMonitors(NULL, NULL, &DisplayEnumProc, 0);
		return displays;
	}


	void APIDisplayProperties::getInfo(int &width, int &height, int &color_depth, double &refresh_rate, std::string& name, Rectangle& area) {
		char info_[sizeof(MONITORINFOEXA)];
		LPMONITORINFOEXA info = (LPMONITORINFOEXA)&info_;
		info->cbSize = (DWORD)sizeof(MONITORINFOEXA);
		GetMonitorInfoA(monitor_, info);
		width = info->rcMonitor.right - info->rcMonitor.left;
		height = info->rcMonitor.bottom - info->rcMonitor.top;
		area.set(info->rcWork.left, info->rcWork.top, info->rcWork.right, info->rcWork.bottom);

		primary_ = info->dwFlags;
		name = info->szDevice;
		display_ = CreateDC("DISPLAY", (char*)info->szDevice, (LPCTSTR)0, (const DEVMODE*)0);
		color_depth  = GetDeviceCaps(display_, BITSPIXEL);
		refresh_rate = GetDeviceCaps(display_, VREFRESH);
	}
/*
	// Hardware Gamma Settings : requires CGDirectDisplayID(target_display_)
	void APIDisplayProperties::setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b) {
		OSErr err;
		saveGammaValue();
		err = CGSetDisplayTransferByFormula( did,
											0.0, 1.0, (1.0/gamma_r),
											0.0, 1.0, (1.0/gamma_g),
											0.0, 1.0, (1.0/gamma_b));
		//				0.0, 1.0, (1.0/gamma_r)*savedRedGamma_,
		//				0.0, 1.0, (1.0/gamma_g)*savedGreenGamma_,
		//				0.0, 1.0, (1.0/gamma_b)*savedBlueGamma_);
		if(err!=kCGErrorSuccess) throw Exception(typeid(*this), "API ERROR", "Failed to set color calibration table for the video renderer.");
		gamma_mode_ = Color::GAMMA_VALUE;
	}
	void APIDisplayProperties::setGammaTable(const std::vector<double> &table_r, const std::vector<double> &table_g, const std::vector<double> &table_b) {
		OSErr err;
		if(table_r.size()!=256 || table_g.size()!=256 || table_b.size()!=256)
			throw Exception(typeid(*this), "Gamma Table Error", "Table size is out of order (not 256).");
		int num_steps = table_r.size();
		saveGammaValue();
		CGGammaValue *(table[3]);
		for(int i=0; i<3; i++) table[i] = new CGGammaValue[num_steps];
		for(int j=0; j<num_steps; j++) {
			table[0][j] = (CGGammaValue)table_r[j];
			table[1][j] = (CGGammaValue)table_g[j];
			table[2][j] = (CGGammaValue)table_b[j];
		}
		err = CGSetDisplayTransferByTable(did, num_steps, table[0], table[1], table[2]);
		if(err!=kCGErrorSuccess) throw Exception(typeid(*this), "API ERROR", "Failed to set color calibration table for the video renderer.");
		gamma_mode_ = Color::TABLE;
		for(int i=0; i<3; i++) delete [] table[i];
	}
	void APIDisplayProperties::setGammaTable(const CGGammaValue * const table_r, const CGGammaValue * const table_g, const CGGammaValue * const table_b, const int num_steps) {
		OSErr err;
		saveGammaValue();
		err = CGSetDisplayTransferByTable(did, num_steps, table_r, table_g, table_b);
		gamma_mode_ = Color::TABLE;
	}
	void APIDisplayProperties::saveGammaValue() {
		OSErr err;
		if(gamma_mode_==Color::NOTHING) {
			err = CGGetDisplayTransferByFormula( did,
												&savedRedMin_, &savedRedMax_, &savedRedGamma_,
												&savedGreenMin_, &savedGreenMax_, &savedGreenGamma_,
												&savedBlueMin_, &savedBlueMax_, &savedBlueGamma_);
		}
	}
	void APIDisplayProperties::destroyGammaSettings() {
		OSErr err;
		switch(gamma_mode_) {
			case Color::GAMMA_VALUE:
			case Color::TABLE:
			default:
				err = CGSetDisplayTransferByFormula( did,
													savedRedMin_, savedRedMax_, savedRedGamma_,
													savedGreenMin_, savedGreenMax_, savedGreenGamma_,
													savedBlueMin_, savedBlueMax_, savedBlueGamma_);
				break;
		}
		gamma_mode_ = Color::NOTHING;
	}

*/
	const std::vector<Display> Display::list() {
		return APIDisplayProperties::emumDisplays();
	}
#ifndef MONITORINFOF_PRIMARY
#define MONITORINFOF_PRIMARY 1
#endif
/*
	const Display Display::main() {
		int width, height, color_depth;
		double refresh_rate;
		std::string name;
		Rectangle area;

		Displays d = APIDisplayProperties::emumDisplays();
		int i=0;
		for(i=0; i<d.size(); i++) {
			d[i].api_->getInfo(width, height, color_depth, refresh_rate, name, area);
			if(d[i].api_->primary_ == MONITORINFOF_PRIMARY) break;
		}
		if(i>=d.size()) i=0;
		return d[i];
	}
*/

	Display::Display(APIDisplayProperties *apid) : api_(apid) {
		apid->getInfo(width, height, color_depth, refresh_rate, name, area);
	}
	void Display::refreshInfo()
	{
		api_->getInfo(width, height, color_depth, refresh_rate, name, area);
	}






}	/*	<- namespace Psycholops 	*/



