//---------------------------------------------------------------------------
#include <vcl.h>
#include <SyncObjs.hpp>
#pragma hdrstop
#include "DetectorThread.h"
#include "Detector.h"
#include "Error.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)

//---------------------------------------------------------------------------
__fastcall TDetectorThread::TDetectorThread(TDetector *Detector): TThread(true)
{
	StartEvent = new TEvent(NULL, false, false, "");
	EmptyAllEvent = new TEvent(NULL, true, true, "");
	EmptyOneEvent = new TEvent(NULL, true, true, "");
	CSInput = new TCriticalSection();
	CSResults = new TCriticalSection();
	this->Detector = Detector;
	MaxQueueSize = 0;
}

//---------------------------------------------------------------------------
__fastcall TDetectorThread::~TDetectorThread()
{
	delete StartEvent;
	delete EmptyAllEvent;
	delete EmptyOneEvent;
	delete CSInput;
	delete CSResults;
}

//---------------------------------------------------------------------------
void __fastcall TDetectorThread::Execute()
{
	while (!Terminated)
	{
		if (WaitForSingleObject((HANDLE)StartEvent->Handle, 500) == WAIT_OBJECT_0)
		{
			CSInput->Enter();
			TQueueItem Item(0, NULL);
			if (!Queue.empty())
			{
				Item = Queue.front();
			}
			CSInput->Leave();

			if (Item.Img)
			{
				Detector->Do(Item.Time, *Item.Img);
				CSResults->Enter();
				Detector->Get(ImpExp);
				CSResults->Leave();
			}

			CSInput->Enter();
			if (Queue.empty())
			{
				EmptyOneEvent->SetEvent();
				EmptyAllEvent->SetEvent();
			}
			else
			{
				Queue.pop();
				EmptyOneEvent->SetEvent();
				StartEvent->SetEvent();
			}
			CSInput->Leave();
		}
	}
}

//---------------------------------------------------------------------------
void TDetectorThread::Do(int Time, TImg *Img)
{
	if (MaxQueueSize < 1)
	{
		throw TError("Delka fronty musi byt >0!");
	}

	WaitForSingleObject((HANDLE)EmptyOneEvent->Handle, INFINITE);

	CSInput->Enter();
	Queue.push(TQueueItem(Time, Img));

	if ((int)Queue.size() == MaxQueueSize)
	{
		EmptyOneEvent->ResetEvent();
	}

	EmptyAllEvent->ResetEvent();
	StartEvent->SetEvent();
	CSInput->Leave();
}

//---------------------------------------------------------------------------
void TDetectorThread::Init(int MaxQueueSize)
{
	Break();
	this->MaxQueueSize = MaxQueueSize;
	ImpExp.Clear();
}

//---------------------------------------------------------------------------
void TDetectorThread::Wait()
{
	WaitForSingleObject((HANDLE)EmptyAllEvent->Handle, INFINITE);
}

//---------------------------------------------------------------------------
void TDetectorThread::Break()
{
	CSInput->Enter();
	while (!Queue.empty())
	{
		Queue.pop();
	}
	CSInput->Leave();
	WaitForSingleObject((HANDLE)EmptyAllEvent->Handle, INFINITE);
}

//---------------------------------------------------------------------------
bool TDetectorThread::Done()
{
	return WaitForSingleObject((HANDLE)EmptyAllEvent->Handle, 0) == WAIT_OBJECT_0;
}

//---------------------------------------------------------------------------
void TDetectorThread::Get(TImpExp &Results)
{
	CSResults->Enter();
	Results.CopyEvents(ImpExp);
	ImpExp.Clear();
	CSResults->Leave();
}

