#ifndef FACEDETECTION_H_
#define FACEDETECTION_H_

#define PATH_TO_IMAGES PATH_IMAGES

#include <Windows.h>
#include "VideoDisplay.h"
#include "VideoCapture.h"
#include <atlimage.h>
#include <fstream>

#include "Resource.h"

#include "opencv2/core.hpp"
//#include "opencv2/core/opencl/opencl_info.hpp"
//#include "opencv2/core/opencl/ocl_defs.hpp"
//#include "opencv2/core/opencl/opencl_svm.hpp"

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/hal/interface.h"
#include "opencv2/imgproc.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/features2d.hpp"



//Tracking
#include "opencv2/tracking/tracking.hpp"

#include "templateMatching.h"

#include "EigenFaceDetector.h"

using namespace cv;

namespace thermoCamera
{
	struct Tracker {
		Ptr<cv::Tracker> tracker;
		bool tracked;
		cv::Rect rectFace;
		int frequency;
		float temp;
		float tempPrevious;
		bool updated;
		cv::Point pointTemp;
		cv::TickMeter timer;
	};

	struct Face {
		cv::Rect rectangle;
		bool tracked;
		int frequency;
		float temp;
		cv::Point pointTemp;
	};


	/**
	* @class FaceDetector
	* @brief Face detection in thermal vision, detection foreheads, eyes etc.
	* @author Matej Roman (student of BUT)
	*/
	class FaceDetector {

	public:
		/**
		* Standard contructor
		*/
		FaceDetector();

		/**
		* Destructor
		*/
		~FaceDetector();

		void Init(HWND hWnd);

		/**
		* Get left of the image
		*/
		int getLeft();

		/**
		* Get top of the image
		*/
		int getTop();

		/**
		* Get width of the image
		*/
		int getWidth();

		/**
		* Get height of the image
		*/
		int getHeight();

		/**
		* Get number of faces (rectangles for drawing)
		*/
		int getNumOfRect();

		int getNumOfTrackers();

		double GetTimerOfTracker(int index);

		float GetTemperatureOfTracker(int index);

		bool IsSetRelativeTemp() { return _isSetRelativeTemp; }

		/**
		* Active face detection
		*/
		void setActive();

		void setWidthOut(int widhtOut) { _widthOut = widhtOut; }

		void setHeightOut(int heightOut) { _heightOut = heightOut; }

		void SetRelativeTemp() { _isSetRelativeTemp = true; }

		void ResetRelativeTemp() { _isSetRelativeTemp = false; }

		/**
		* Deactive face detection
		*/
		void resetActive();

		void ResetNumOfTrackers() { _trackers.clear(); }

		/**
		* Flag for video: play, pause, stop
		*/
		bool isActive();

		void TemplateMatching(HBITMAP hBitMap, thermoCamera::VideoDisplay& video, int width, int height);

		void DetectGlass(HBITMAP hBitMap, thermoCamera::VideoCapture* video, int width, int height);

		void LBP(HBITMAP hBitMap, thermoCamera::VideoDisplay& video,int width, int height);

		void LBPDetector(HBITMAP hBitMap, thermoCamera::VideoCapture* video, int width, int height);

		void FindFace(HBITMAP hBitMap, thermoCamera::VideoDisplay& video, int width, int height);

		void SetPathClasiffier(const TCHAR* path);

		void Tracking(thermoCamera::VideoDisplay& video);

		cv::UMat K_means(cv::UMat Input, int K);

		// Face rectangle
		cv::Rect getFaceRectangle(int whichRect);

		void DrawFaceRectangle(HWND& hWnd, HDC& hdc) const;

		void DrawTempFace(HWND& hWnd, thermoCamera::VideoDisplay& video, HDC& hdc) const;


	private:

		bool _active;

		bool _isSetRelativeTemp;

		bool _showOpenCVWin;

		int _thresholdFrequency;

		float _thresholdTemperture;

		int _left;

		int _top;

		int _width;

		int _widthOut;

		int _heightOut;

		int _height;

		float _tempFace;

		cv::Point _locFaceTemp;

		HBITMAP _hbitmap;

		#if UNICODE	
			std::wstring _pathToClassifier;
		#else
			std::string _pathToClassifier;
		#endif

		std::vector<cv::Rect> _faceRectangle;

		std::vector<cv::Rect> _foreheadRect;

		std::vector<cv::Point> _pointsOfTemperature;

		std::vector<float> _tempOfFace;

		tempMatch::TemplateMatching _tempMatch;

		std::vector<Tracker> _trackers;

		int _rectAreMissing;

		std::vector<Face> _faces;

		int _percentOveralpped;

		const char* _nameWin = "My video";

		void _MeasureForehead(thermoCamera::VideoCapture** video, std::vector<cv::Rect>& rectOfFaces);

		void _TrackingFace(cv::UMat& img, bool show);

		void _ValidateTrackingObjectFaces();

		void _ValidateTrackingObject();

		void _DestroyRedundantRectangles();

		bool _FindForehead(cv::UMat& input, cv::Rect& faceRect, cv::Rect& outRect,int num, bool show);

		void _GetTempOfFace(HWND hWnd, HDC hdc, POINT p, int num, thermoCamera::VideoDisplay* VideoCapture) const;

		void _StretchWindow(cv::Rect& input, cv::UMat& img, int newWidth, int newHeight);

		void _StretchWindow(cv::Rect& input, cv::Mat& img, int newWidth, int newHeight);

		void _loadImageFromBitmap(HBITMAP hBitmap, cv::UMat& inputImg, thermoCamera::VideoDisplay* video,int flag);

		bool _localizeEye( cv::UMat& img,cv::Rect& face,thermoCamera::VideoDisplay* video,bool show);

		bool _localizeGlass(cv::UMat& img, cv::Rect& rect, thermoCamera::VideoCapture** video, bool show);

		void _transformLinear2D(int& x, int& y, int& xReal, int& yReal, float inlox, float inupx, float outlox, float outupx, float inloy, float inupy, float outloy, float outupy);

		// ttps://www.geeksforgeeks.org/find-two-rectangles-overlap/
		bool _isOverLapped(cv::Rect rect1, cv::Rect rect2, int percent);

		bool _isOverLapped(cv::Rect rect1, RECT rect2);

		bool _intersection(const cv::Rect& rect1,const cv::Rect& rect2, int percentage);

		void _tempOutwithRect(HDC& hdc, POINT p, TCHAR* text, COLORREF color);

		void _CImageToMat(CImage& cimage, Mat& mat);

		void _hwnd2mat(HBITMAP hBitMap, HDC BackBuffer,cv::UMat& src);

		std::string _ws2s(const std::wstring& s);

		std::wstring _s2ws(const std::string& s);


		// Eigenfaces

		const char* locationOfMean = "C:\\Images\\Locations\\mean.yml";
		const char* locationOfWeights = "C:\\Images\\Locations\\weight.yml";
		const char* locationOfEigenVectors = "C:\\Images\\Locations\\eigenvectors.yml";
		const char* locationOfMaxWeight = "C:\\Images\\Locations\\maxWeight.txt";

		thermoCamera::EigenFaceDetector _eigenDetector;

	};
}

#endif
