#include "BlahoDetector.h"
#include <windows.h>
#include <vcl.h>

using namespace std;
using namespace ee;

TBlahoDetector::TBlahoDetector()
: faceDetectorFilename( AnsiString(ExtractFilePath(Application->ExeName) + "haarcascade_frontalface_alt.xml").c_str()),
	faceDetectorCascade( (CvHaarClassifierCascade*)cvLoad( faceDetectorFilename.c_str(),0,0,0)),
	storage( NULL),
	frameGray( NULL),
	frameSmall( NULL),
	frameSmallLast( NULL),
	differenceImage( NULL),
	differenceThreshold( 50),
	differenceAreaThreshold( 0.05),
	faceDetectionImageScale( 0.5),
	camera(1)
{
	if( faceDetectorCascade == NULL){
		cerr<< "Unable to open face cascade: " << faceDetectorFilename << endl;
//		return -1;
	}

	storage = cvCreateMemStorage( 0);
	//cvNamedWindow( AnsiString(AnsiString("skin") + IntToStr(camera)).c_str() );
	cvNamedWindow( AnsiString(AnsiString("result") + IntToStr(camera)).c_str());
}

TBlahoDetector::TBlahoDetector(int Camera)
: faceDetectorFilename( AnsiString(ExtractFilePath(Application->ExeName) + "haarcascade_frontalface_alt.xml").c_str()),
	faceDetectorCascade( (CvHaarClassifierCascade*)cvLoad( faceDetectorFilename.c_str(),0,0,0)),
	storage( NULL),
	frameGray( NULL),
	frameSmall( NULL),
	frameSmallLast( NULL),
	differenceImage( NULL),
	differenceThreshold( 40),
	differenceAreaThreshold( 0.05),
	faceDetectionImageScale( 0.5),//pro <1 pojede rychlej
	camera(Camera)
{
	if( faceDetectorCascade == NULL){
		cerr<< "Unable to open face cascade: " << faceDetectorFilename << endl;
//		return -1;
	}

	storage = cvCreateMemStorage( 0);
	//cvNamedWindow( AnsiString(AnsiString("skin") + IntToStr(camera)).c_str());
	cvNamedWindow( AnsiString(AnsiString("result") + IntToStr(camera)).c_str());
}

void TBlahoDetector::Init()
{
	TParameters Parameters;
	Parameters.push_back(TParameter("Person", "A"));
	InsertMessage(0, "Start Speaking", Parameters);

	Parameters.clear();
	Parameters.push_back(TParameter("X1", "0"));
	Parameters.push_back(TParameter("Y1", "0"));
	Parameters.push_back(TParameter("X2", "320"));
	Parameters.push_back(TParameter("Y2", "0"));
	Parameters.push_back(TParameter("X3", "320"));
	Parameters.push_back(TParameter("Y3", "240"));
	Parameters.push_back(TParameter("X4", "0"));
	Parameters.push_back(TParameter("Y4", "240"));
	InsertMessage(0, "Prezentation Board", Parameters);

	lastMovementTime = 0;
	lastFaceTime = 0;
	noFace = true;
	lastFacesTotal = 0;
}


void TBlahoDetector::Do(int Time, TImg &Img)
{
	IplImage *frameorig = cvCreateImageHeader( cvSize( Img.GetWidth(), Img.GetHeight()), IPL_DEPTH_8U, 4);
	frameorig->imageDataOrigin = frameorig->imageData = (char *)Img.GetBitmap();

	IplImage *frame;
	frame = cvCloneImage(frameorig);


	//IplImage *frame = cvCreateImageHeader( cvSize( Img.GetWidth(), Img.GetHeight()), IPL_DEPTH_8U, 4);
	//frame->imageDataOrigin = frame->imageData = (char *)Img.GetBitmap();


	if( !frameGray)
		frameGray = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U,1);

	if(!frameSmall)
		frameSmall = cvCreateImage(cvSize(cvRound(frame->width * faceDetectionImageScale),cvRound(frame->height * faceDetectionImageScale)),IPL_DEPTH_8U,1);

	if(!frameSmallLast)
		frameSmallLast = cvCreateImage(cvSize(cvRound(frame->width * faceDetectionImageScale),cvRound(frame->height * faceDetectionImageScale)),IPL_DEPTH_8U,1);

	if(!differenceImage)
		differenceImage = cvCreateImage(cvSize(cvRound(frame->width * faceDetectionImageScale),cvRound(frame->height * faceDetectionImageScale)),IPL_DEPTH_8U,1);

	cvCvtColor( frame, frameGray, CV_BGRA2GRAY);

	cvResize( frameGray, frameSmall, CV_INTER_NN);


	// get the difference
	cvAbsDiff( frameSmall, frameSmallLast, differenceImage);
	cvThreshold( differenceImage, differenceImage, differenceThreshold, 128,CV_THRESH_BINARY);
	double differenceArea = cvCountNonZero( differenceImage) /(double)( differenceImage->width * differenceImage->height);

//	cvCvtColor( differenceImage, frame, GRAY2CV_BGRA);

	if( differenceArea > differenceAreaThreshold){

		if ((lastMovementTime<1000)||(Time-lastMovementTime>1000)){
			//movement event
			TParameters Parameters;
			InsertMessage(Time, "Prezentation Exchange", Parameters);
		}
		lastMovementTime = Time;
		//tvorba difference framu
		//cvThreshold( differenceImage, differenceImage, differenceThreshold, 255, CV_THRESH_BINARY);
	}
	//cvCvtColor( differenceImage, frame, CV_GRAY2BGRA);


	/* Detect faces */
	cvClearMemStorage( storage);
//	double t = (double)cvGetTickCount();
	CvSeq *faces = cvHaarDetectObjects( frameSmall, faceDetectorCascade, storage, 1.25, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,cvSize( 30, 30));
//	t = (double)cvGetTickCount() - t;
//    cout<<"detection time = "<<t/((double)cvGetTickFrequency()*1000.0)<<endl;

	if(faces && faces->total>0){
		for(int i=0;i<(faces?faces->total:0);i++){
			CvRect* r=(CvRect*)cvGetSeqElem(faces, i);
			CvPoint p[2];
			p[0]=cvPoint(cvRound(r->x/faceDetectionImageScale),cvRound(r->y/faceDetectionImageScale));
			p[1]=cvPoint(cvRound((r->x+r->width)/faceDetectionImageScale),cvRound((r->y+r->height)/faceDetectionImageScale));

			for(int k=0;k<2;k++){
				if(p[k].x<0)p[k].x=0;
				if(p[k].y<0)p[k].y=0;
				if(p[k].x>=frame->width)p[k].x=frame->width-1;
				if(p[k].y>=frame->height)p[k].y=frame->height-1;
			}
			/*draw rectangle where face was detected*/
			cvRectangle( frame, p[0], p[1], cvScalar(255,0,0), 2);

		}
#if 1
		//if (noFace || ((faces->total != lastFacesTotal) &&
		//	((lastFaceTime<1000) || (Time-lastFaceTime>1000))))
		if ((noFace) && (Time-lastFaceTime>1000))
		{
			//face event
			TParameters Parameters;
			InsertMessage(Time, "Prezentation Exchange", Parameters);
			//Parameters.push_back(TParameter("Person", IntToStr(camera)));
			//InsertMessage(Time, "Start speaking", Parameters);

			noFace = false;
		}
		lastFaceTime = Time;
#else
			// event output
			TParameters Parameters;
			Parameters.push_back(TParameter("Object", FloatToStr(float(rand() % 3 + 1))));
			Parameters.push_back(TParameter("CenterX", FloatToStr(float(rand() % 320 + 1))));
			Parameters.push_back(TParameter("CenterY", FloatToStr(float(rand() % 240 + 1))));
			Parameters.push_back(TParameter("DivergenceX", FloatToStr(float(rand() % 100 + 1))));
			Parameters.push_back(TParameter("DivergenceY", FloatToStr(float(rand() % 100 + 1))));
			Parameters.push_back(TParameter("Size", FloatToStr(float(rand() % 300 + 1))));
			InsertMessage(Time, "Teacher", Parameters);
#endif

	}
	// no face detected
	else
	{
		/*if (noFace == false)
		{
			TParameters Parameters;
			Parameters.push_back(TParameter("Person", IntToStr(camera)));
			InsertMessage(Time, "Stop speaking", Parameters);
		} */
		noFace = true;
	}
	lastFacesTotal = faces->total;

	cvShowImage( AnsiString(AnsiString("result") + IntToStr(camera)).c_str(), frame);
//	cvWaitKey( 10);


	// exchange the last and the current image
	IplImage * tempImage = frameSmallLast;
	frameSmallLast = frameSmall;
	frameSmall = tempImage;

	cvReleaseImageHeader(&frameorig);
	cvReleaseImage(&frame);

/*
	if ((camera >= 1 && camera <= 11) && (GetTickCount() % 391 < 7))
	{
		TParameters Parameters;
		Parameters.push_back(TParameter("Object", FloatToStr(float(rand() % 3 + 1))));
		Parameters.push_back(TParameter("CenterX", FloatToStr(float(rand() % 320 + 1))));
		Parameters.push_back(TParameter("CenterY", FloatToStr(float(rand() % 240 + 1))));
		Parameters.push_back(TParameter("DivergenceX", FloatToStr(float(rand() % 100 + 1))));
		Parameters.push_back(TParameter("DivergenceY", FloatToStr(float(rand() % 100 + 1))));
		Parameters.push_back(TParameter("Size", FloatToStr(float(rand() % 300 + 1))));
		InsertMessage(Time, "Teacher", Parameters);
	}

	if ((camera >= 1 && camera <= 11) && (GetTickCount() % 519 < 3))
	{
		TParameters Parameters;
		InsertMessage(Time, "Prezentation Exchange", Parameters);
	}*/

}   


TBlahoDetector::~TBlahoDetector(){

	if( faceDetectorCascade != NULL){
		//cvRelease( &faceDetectorCascade);
	}

	if( storage != NULL){
		//cvReleasesorage( &storage);
	}

	cvReleaseImage( &frameGray);
	cvReleaseImage( &frameSmall);
}
