#ifndef CALIB_CALIBRATION_UNIT_H
#define CALIB_CALIBRATION_UNIT_H

#include "Calibration\Projector.h"

using namespace std;
using namespace CALIB;

//Initial coefficient for display area adjustment
//Používá se pro získání vektoru pro posun hrany oblasti displeje
//Původní velikost vektoru hrany se násobí tímto koeficientem
#define INITIAL_SHIFT_COEFFICIENT 10  //nesmi se pridavat f na konec retezce tzn. nesmi byt 0.1f
//Zlomek puvodniho vektoru, ktery se pouzije pro zmenu velikosti oblasit displeje
#define INITIAL_VACTOR_FRAGMENT 0.01
#define DISPLAY_BORDER_WIDTH 1
#define PROJECTOR_SHIFT_COEFFICIENT 0.25f

namespace CALIB
{	
	class CalibrationUnit
	{
		public:
			CalibrationUnit(int projectorsCount,int projectorsInRow,int width,int height);
			~CalibrationUnit();	

			void SetCameraImageSize(int weight, int height) {	this->cameraImageWidth = weight; this->cameraImageHeight = height; }
			void CalculateHomographyDisplay(int projectorIndex,CvMat* displayPoints,CvMat* projectorPoints);
			CvMat *  GetPoints(int projectorIndex,int coordSystem);
			CvMat *  TransformPoints(int projectorIndex,int homogType,CvMat * points);
			CvMat *  GetHomography(int projectorIndex ,int type, bool as4x4 = false);
			std::vector<CvMat*> * GetAdjacentProjectroHomographies(int projectorIndex);
			void ResetCalibration();
			bool CalibrateDisplay(int baseProjectorIndex = -1);
			/**
			 * Calculates overlap polygons between all projectors.
			 * Calculates camera-projector homography from overlapping points
			 */
			bool CalculateOverlapPolygons();
			geometry::Polygon2Df* CombineProjectorPolygons();
			IplImage * CombineProjectorAreasIntoImage(int projectorsCount = 0,CvScalar color = cvScalar(UCHAR_MAX),bool addValues = false);
			Projector * GetProjector(int index);
			void calculateHomography(vector<geometry::Vector2Df> * srcPlanePoints, vector<geometry::Vector2Df> * dstPlanePoints,int homographyType,int projectorIndex);
			bool Test();
			void CalculateLuminanceAttenuation();
		protected:
			vector<Projector*> projectors;
			Projector* display;
			int cameraImageWidth;
			int cameraImageHeight;
			int count;
			int cols;
			int rows;

			void addProjector(Projector * projector)	{ this->projectors.push_back(projector); }
			/**
			 * p1 Projector #1 index.
			 * p2 Projector #2 index.
			 * h12 Homography from projector 1 to 2
			 */
			void calculatePPHomography(int p1,int p2,CvMat * h12);
			bool calculatePDHomography(int pIndex);
			bool calculatePDHomographyAllProj(int baseProjectorIndex);
			void calculateHomography(CvMat* srcPlanePoints, CvMat* dstPlanePoints,int homographyType,int projectorIndex);

			void adjustDisplayRatioScale(vector<geometry::Vector2Df> * displayPoints,float  projectorWidth,float projectorHeight);
			//cyklus while posun <= 2
		    //*zkopiruj body polygonu
			//*Pro kazdou hranu noveho polygonu proved
			//** Posun body hrany o velikost posun
			//** Zkontroluj jestli je hrana uvnitr
			//** Pokud ano ulozit
			//** Pokud ne prepsat puvodni hodnotou
			void adjustDisplayArea(vector<geometry::Vector2Df> * displayPoints,IplImage* projectorUnionImage,geometry::Polygon2Df* projectorUnionPolygon);
			bool shiftLine(IplImage* projectorUnionImage,geometry::Polygon2Df *projectorUnionPolygon,geometry::Vector2Df * lp1,geometry::Vector2Df * lp2,geometry::Vector2Df pShift1,geometry::Vector2Df pShift2,bool add = false);
			bool pointsInsidePolygon(IplImage* projectorUnitImage,geometry::Vector2Df p1,geometry::Vector2Df p2);
			bool pointsInsidePolygon(IplImage* projectorUnitImage,vector<geometry::Vector2Df> points);
			bool lineIntersectPolygon(geometry::Polygon2Df* polygon,geometry::Vector2Df* p1,geometry::Vector2Df* p2);
			void shiftDisplayCornerPointsIntoCenter(vector<geometry::Vector2Df> * cornerPoints,int projectorIndex);
			vector<geometry::Vector2Df> * prepareOriginalDisplayCornerPoints(Projector * projector);
			void calculateDisplayTransformation(Projector * projector,int projectorIndex);
			int getBaseProjectorIndex();
	};
}; 

#endif
		
