#ifndef CALIB_PROJECTOR_H
#define CALIB_PROJECTOR_H

#include "Helper\Cvh.h"
#include "Helper\GL.h"
#include "Helper\Common.h"
#include <vector>
#include <map>
/** Homography matrix dimension.*/
#define HOMOG_DIM 3
#define CORNER_COUNT 4

using namespace std;
using namespace CALIB;

#define PROJ_FILENAME_PREFIX "var/Projector_hom_"
#define PROJ_LIGHTMAPFILE_PREFIX "var/lightMap_"
#define PROJ_FILENAME_SUFIX ".txt"
#define PROJ_LIGHTMAPFILE_SUFIX ".jpg"
#define NONE_INDEX -1

namespace CALIB
{	
	enum HomogType
	{
		NONE = -1,
		PD = 0,     //Projector - Display
		DP = 1,     //Display - projector
		PK = 2,     //Projector to keystone
		KP = 3,     //Keystone to projector
		PCO = 4,    // Projector - camera - overlepped points
		CPO = 5,	// Projector - camera - overlepped points
		PC = 6,		//Projector - camera
		CP = 7,		//Camera - projector -- upper boundry
	};

	enum Corner 
	{
		U_L = 0,
		U_R = 1,
		B_R = 2,
		B_L = 3
	};

	enum CoordinateSystem 
	{
		PROJECTOR = 0,
		CAMERA = 1,
		DISPLAY = 2,
		PROJECTOR_KEYSTONE = 3,
	};

	enum PointsType
	{
		DETECTED,
		PROJECTED
	};

	struct COLOR
	{
	     float R;
	     float G;
	     float B;
	};

	/** Internal parameters matrix dimension.*/
	class Projector
	{	
		public:
			Projector(int index,int width,int height);
			~Projector();
		protected:
			/** Camera-projector homography */
			int width;
			int height;
			int index;
			vector<CvMat*> homography;	
			CvMat * cornerPoints;	
			std::vector<geometry::Vector2Df>* pointsDetected;
			std::vector<geometry::Vector2Df>* pointsProjected;
			/** Projector display polygon,overlap polygon **/
			map<int,geometry::Polygon2Df*> polygons;
			IplImage * lightMap;
			IplImage * overlapImage;
			GLuint lightTextureId;
			bool calibrated;
			COLOR luminanceAttenuation;

			//storage for warped mesh points
			std::vector<geometry::Vector2Df> pointsMesh;
			//original positions of points in mesh
			std::vector<geometry::Vector2Df> pointsMeshOriginal;
			std::vector<geometry::Vector2Df> pointsMeshTexture;
			int meshRows;
			int meshCols;

			void initPolygons();
			void initCornerPoints();
			std::string getFilename(int type,string prefix = "",string suffix = "");
			void calculateHomography(CvMat * srcPlanePointsCv, CvMat * dstPlanePointsCv,int homographyType);
			void calculateHomography(vector<geometry::Vector2Df> * srcPlanePoints, vector<geometry::Vector2Df> * dstPlanePoints,int homographyType);
			geometry::Vector2Df * calculateKeystoneRatio();
			void calculateKeystoneCorrection();
			std::vector<int> * getOverlapPointsIndexes(int overlappedProjectorIndex);
		public:
			int GetWidth() { return this->width; }
			int GetHeight() { return this->height; }
			COLOR GetLuminanceAttenuation() { return this->luminanceAttenuation; }
			void SetLuminanceAttenuationR(float value) { this->luminanceAttenuation.R = value; }
			void SetLuminanceAttenuationG(float value) { this->luminanceAttenuation.G = value; }
			void SetLuminanceAttenuationB(float value) { this->luminanceAttenuation.B = value; }

			void InitDisplayBase();
			void SetHomography(int type,CvMat * value);
			CvMat * GetHomography(int type);
			void CountDisplayHomography(CvMat * cameraDisplayHomography,CvMat * displayCameraHomography);
			vector<geometry::Vector2Df> * TranformPoints(int homographyType,vector<geometry::Vector2Df> * src);
			void TranformPoints(int homographyType,CvMat * src,CvMat * dst);
			std::vector<geometry::Vector2Df> * GetCornerPointsVector(int coordSystem);
			CvMat * GetCornerPoints(int coordSystem);
			geometry::Polygon2Df * GetSelfPolygon();
			geometry::Polygon2Df * GetPolygon(int index);
			std::vector<geometry::Vector2Df> * GetPolygonPoints(int index,int homographyType = HomogType::NONE);
			void SetPolygon(int index,geometry::Polygon2Df * polygon);
			void Save();
			void Load();

			void SetPoints(int type,std::vector<geometry::Vector2Df> * points);
			std::vector<geometry::Vector2Df> * GetPoints(int type,int overlappedProjectorIndex = NONE_INDEX);
			bool CalculateHomographyCamera(int overlappedProjectorIndex = NONE_INDEX,bool calcKeystone = false);
			void SetCalibrated(bool calibrated)		{	this->calibrated = calibrated; }
			bool IsCalibrated()		{	return this->calibrated;	}
			void SetLightMap(IplImage * image);/* { this->lightMap = image;}*/
			float GetKeystoneDistortionValue();
			IplImage * GetLightMap() {	return this->lightMap; }
			GLuint GetLightMapTexture();
			void CalculateOvelapImage();

			std::vector<geometry::Vector2Df> * GetPointsMesh() { return &this->pointsMesh; }
			std::vector<geometry::Vector2Df> * GetPointsMeshOriginal() { return &this->pointsMeshOriginal; }
			std::vector<geometry::Vector2Df> * GetPointsMeshTexture() { return &this->pointsMeshTexture; }
			void SetMeshRows(int rows) { this->meshRows = rows; }
			void SetMeshCols(int cols) { this->meshCols = cols; }
			int GetMeshRows() { return this->meshRows; }
			int GetMeshCols() { return this->meshCols; }
	};

}; 

#endif
