#include "ChipMonkCoordinator.h"
#include <stdio.h>
#include "CHipMonkUtilities.h"
//#include "SoundCoordinator.h"
#include "HoughTransform.h"
//#include <e32base.h>
#include "BmpFuncs.h"
//#include "ChipmonkCamera.h"
//#include "ChipmonkAppView.h"
#include "RawLine.h"
//#define __VERBOSE

int CountFoundInDictionaryWordsInTheLastRegion(COcrTextPage& textPage, Dictionary* pDict, int nMinWordLenght)
{
	if (textPage.empty())
		return 0;
	int nWord = 0, nNoWord = 0;
	COcrTextRegion *pTextRegion = (COcrTextRegion*) *textPage.rbegin();
	for(COcrTextRegion::iterator i = pTextRegion->begin(); i != pTextRegion->end(); ++i){
		COcrTextLine *pTextLine = (COcrTextLine*) *i;
		wstring sLine;
		pTextLine->GetText(sLine);
		int nW = 0, nNoW = 0;
		pDict->CountFoundWords((const WCHAR*)sLine.c_str(), nW, nNoW, nMinWordLenght);
		nWord += nW;
		nNoWord += nNoW;
	}

	return nWord;
}

CChipMonkCoordinator::CChipMonkCoordinator() :
	m_pRawImageBuff(NULL),
	m_pGreyImage(NULL),
	m_uMaxRawImageSize(0),
	m_uRawImageSize(0), 
	m_uRawImageWidth(0), 
	m_uRawImageHeight(0),
	m_nBusyBeepCount(0),
	m_eProcessingState(CChipMonkCoordinator::eIdle) {
}

CChipMonkCoordinator::~CChipMonkCoordinator() {
	//if(m_pChipmonkCamera) delete m_pChipmonkCamera;
	if(m_pRawImageBuff) delete [] m_pRawImageBuff;
	if(m_pGreyImage) cvReleaseImage(&m_pGreyImage);
	//if(m_pSoundCoordinator) delete m_pSoundCoordinator;
	//if(m_pTimer) delete m_pTimer;
	//if(m_pTimerCallback) delete m_pTimerCallback;
	if(m_pRawlines) delete m_pRawlines;
}

BOOL CChipMonkCoordinator::LoadRawImage(const char *sRawImageFileName) {
	FILE *pF = fopen(sRawImageFileName, "rb");
	if(!pF) {
		return FALSE;
	}
	fseek(pF, 0, SEEK_END);
	m_uRawImageSize = (int)ftell(pF);
	if(m_uRawImageSize > m_uMaxRawImageSize) {
		if(m_pRawImageBuff) {
			delete [] m_pRawImageBuff;
		}
		m_pRawImageBuff = new UCHAR[m_uRawImageSize];
		if(m_pRawImageBuff) {
			m_uMaxRawImageSize = m_uRawImageSize;
		}
		else {
			m_uMaxRawImageSize = 0;
			fclose(pF);
			return FALSE;
		}
	}
	fseek(pF, 0, SEEK_SET);
	fread(m_pRawImageBuff, 1, m_uRawImageSize, pF);
	fclose(pF);
	return TRUE;
}

BOOL CChipMonkCoordinator::PlayText(const WCHAR *pText) {
	//if(m_pSoundCoordinator) {
	//	m_pSoundCoordinator->Say((wchar_t*)pText);
	//}
	m_pOS->Speak(pText);
	return TRUE;
}

//BOOL CChipMonkCoordinator::NssTtsPlayText(const char *pText)
//{
//	TTtsStyle 		iStyle;
//	TTtsStyleID 	iStyleId;
//	CTtsParsedText *iParsedText = CTtsParsedText::NewL();
///*
//	if ( m_pSoundCoordinator->m_pTtsUtility->NumberOfStyles() > 0 )
//	{
//		// Delete style if exists
//		m_pSoundCoordinator->m_pTtsUtility->DeleteStyle( iStyleId );
//	}
//*/
//	if ( iParsedText->NumberOfSegments() > 0 )
//	{
//		// Remove existing segment from parsed text structure
//		iParsedText->DeleteSegmentL( 0 );
//	}
//
//	// Set iStyle
//	iStyle.iQuality = ETtsQualityHighOnly;
//	iStyle.iLanguage = KTtsUndefinedLanguage;
//	iStyle.iRate = 75;
//	iStyle.iNlp = FALSE;
//	// Add style
//	iStyleId = m_pSoundCoordinator->m_pTtsUtility->AddStyleL( iStyle );
//	// Initialise with current text and settings.
//
//	TTtsSegment iSegment(iStyleId);
//	
//	string str;
//	str.clear();
//	str.append(pText);
//	
//	wstring ws;
//	Str2WStr(str, ws);
//		
//	TPtrC16 ptr;
//	ptr.Set((TUint16 *)ws.c_str(), ws.length());
//	iParsedText->SetTextL(ptr);
//
//	iSegment.SetTextPtr( iParsedText->Text() );
//	iParsedText->AddSegmentL(iSegment, 0);
//	
//	m_pSoundCoordinator->m_pTtsUtility->OpenParsedTextL( *iParsedText );
//	//The command to start playing
//	m_pSoundCoordinator->m_pTtsUtility->Play();
//			
//	return TRUE;	
//}
//

//TInt TimerCallbackProc(TAny *aPtr) {
//	CChipMonkCoordinator *pChipMonkCoordinator = (CChipMonkCoordinator*)aPtr;
//	pChipMonkCoordinator->OnTimer();
//	return 0;
//}

DWORD WINAPI TimerCallbackProc(void *aPtr) {
	CChipMonkCoordinator *pChipMonkCoordinator = (CChipMonkCoordinator*)aPtr;
	for(;;) {
		pChipMonkCoordinator->OnTimer();
		Sleep(200);
	}
	return 0;
}

//TInt ImageProcessProc(TAny* param){
//	for(;;){
//		CChipMonkCoordinator *pChipMonkCoordinator = (CChipMonkCoordinator*)param;
//		pChipMonkCoordinator->ProcessImage();
//		pChipMonkCoordinator->SuspendImageProcessThread();
//	}
//	return 0;
//}

 DWORD WINAPI ImageProcessProc(void* param){
	CChipMonkCoordinator *pChipMonkCoordinator = (CChipMonkCoordinator*)param;
    pChipMonkCoordinator->SuspendImageProcessThread();
	for(;;){
		pChipMonkCoordinator->ProcessImage();
		pChipMonkCoordinator->SuspendImageProcessThread();
	}
	return 0;
}

 BOOL CChipMonkCoordinator::Init(COSBase *pOS) {//CChipmonkAppView *pView) {

    m_pOS = pOS;
	//m_pView = pView;
	m_eProcessingState = eIdle;
	m_pRawlines = new CRawLines;
	m_nCurrentRawLineIndx = -1;
	//m_pSoundCoordinator = new CSoundCoordinator(this);
	//m_pSoundCoordinator->Init();
	PlayText((const WCHAR*)(L"Wellcome to the Chipmonk application from ABISEE."));

	//NssTtsPlayText("read this text during initialization");	
		
	if(!m_ocr.Init()) {
		PlayText((const WCHAR*)(L"Cannot initialize OCR."));	
		return FALSE;
	}
	//m_imageProcessThread.Create(_L("ImageProcessThread"), 
	//		ImageProcessProc, 0xA000, &User::Heap(), this);
	m_imageProcessThread = CreateThread( NULL, 0, ImageProcessProc, this, 0, NULL);
	SetThreadPriority(m_imageProcessThread, THREAD_PRIORITY_BELOW_NORMAL);
	//m_imageProcessThread.SetPriority(EPriorityLess);
	//m_timerCriticalSection.CreateLocal();
	//m_eventQCriticalSection.CreateLocal();
	//m_ocrCriticalSection.CreateLocal();
	//m_pTimerCallback = new TCallBack(TimerCallbackProc, this);
	//m_pTimer = CPeriodic::NewL(CPeriodic::EPriorityStandard);
	//if(m_pTimer) {
	//	m_pTimer->Start(200000, 200000, *m_pTimerCallback);
	//}
	CreateThread( NULL, 0, TimerCallbackProc, this, 0, NULL);
	//m_pChipmonkCamera = new CChipmonkCamera(this);
	//if(!m_pChipmonkCamera || !m_pChipmonkCamera->Init()) {
	//	return FALSE;
	//}
	return TRUE;
}

static void CalcPreprocParams(const IplImage *pImg, int & nThreshold, int & nBverWThreshold, int & nOcrThreshold){
	int pHist[256];
	int nCount = BuildImageHistogram(pImg, 4, pHist);
	int nOnePercentPixels = nCount / 100;
	int nSum = 0;
	int nBright = 255, nDark = 0;
	for(; nBright >= 0 && nSum < nOnePercentPixels; --nBright){
		nSum += pHist[nBright];
	}
	for(nSum = 0; nDark < 256 && nSum < nOnePercentPixels; ++nDark){
		nSum += pHist[nDark];
	}
	
	//if(nBright >= 200 && nDark < 12){
	//	nThreshold = 20;
	//	nBverWThreshold = 30;
	//	nOcrThreshold = int(0.7 * 256);
	//	return;
	//}
	
	if(nBright >= 150){
		nThreshold = 15;
		nBverWThreshold = 25;
		nOcrThreshold = int(0.9 * 256);
		return;
	}
	if(nBright >= 100){
		nThreshold = 10;
		nBverWThreshold = 15;
		nOcrThreshold = int(0.95 * 256);
		return;
	}
	nThreshold = 5;
	nBverWThreshold = 5;
	nOcrThreshold = int(0.98 * 256);
}


BOOL CChipMonkCoordinator::PreprocessImage(vector<int> & vAngles,
								UCHAR** pp1bppBoW, UCHAR** pp1bppWoB, 
								int & nATThreshold, int & nBverWThreshold, int & nOcrThreshold) {
	if (g_bCancelProcessing)
		return TRUE;

	if(!OpenJPG2Gray(m_pRawImageBuff, m_uRawImageSize, 
		m_uRawImageWidth, m_uRawImageHeight, 
		FALSE, TRUE, 
		&m_pGreyImage)) {
			return FALSE;
	}

	if (g_bCancelProcessing)
		return TRUE;
	//m_ocrProcessingParams.ResetEvents();
	CalcPreprocParams(m_pGreyImage, nATThreshold, nBverWThreshold, nOcrThreshold);
	if(!*pp1bppBoW) *pp1bppBoW = new UCHAR[m_pGreyImage->height * m_pGreyImage->width / 8];
	if(!*pp1bppWoB) *pp1bppWoB = new UCHAR[m_pGreyImage->height * m_pGreyImage->width / 8];
	int nBoW = 0, nWoB = 0;
	AdaptiveThresholdCB(m_pGreyImage, 21, nATThreshold, *pp1bppBoW, *pp1bppWoB, nBoW, nWoB);
#ifdef __VERBOSE
	SaveaBMP(*pp1bppBoW, "c:\\Data\\tmp\\img_bow.bmp", m_pGreyImage->width, m_pGreyImage->height, 1, true, m_pGreyImage->width / 8);
	SaveaBMP(*pp1bppWoB, "c:\\Data\\tmp\\img_wob.bmp", m_pGreyImage->width, m_pGreyImage->height, 1, true, m_pGreyImage->width / 8);
#endif
	if(!m_houghTransform.GetRotationAngles((char*)((nBoW < nWoB) ? *pp1bppBoW : *pp1bppWoB), 
			m_pGreyImage->width, m_pGreyImage->height, vAngles)){
				return  FALSE;
	}
	return TRUE;
}

void CChipMonkCoordinator::OnTimer() {
	static BOOL bBusy = FALSE;
	if(bBusy) {//m_timerCriticalSection.IsBlocked() || m_eventQCriticalSection.IsBlocked()) {
		return;
	}
	//m_timerCriticalSection.Wait();
	CSingleLock sl(&m_timerCriticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		bBusy = TRUE;
		if(m_eProcessingState == ePreprocessing || m_eProcessingState == eZonning) {
			if(m_nBusyBeepCount == 0) {
				//WriteTimeStampToLog("BEEP", false, m_eProcessingState);
				//m_pSoundCoordinator->PlayFixedSound(BUSY_BEEP);
				m_pOS->DingSound();
			}
			m_nBusyBeepCount = (m_nBusyBeepCount + 1) % 10;
		}
		CEventBase *pEvent = NULL;
		CSingleLock slev(&m_eventQCriticalSection); //m_eventQCriticalSection.Wait();
		slev.Lock();
		if(slev.IsLocked()) {
			if(m_eventQ.empty()) {
				//m_eventQCriticalSection.Signal();
				//m_timerCriticalSection.Signal();
				bBusy = FALSE;
				return;
			}
			pEvent = m_eventQ.front();
			m_eventQ.pop_front();
			//m_eventQCriticalSection.Signal();
			slev.Unlock();
		}
		switch(pEvent->GetId()) {
	case EVENT_ZONNING_DONE: 
		{

			//WriteTimeStampToLog("EVENT_ZONNING_DONE", false, m_eProcessingState);

			UINT uSize = m_ocrProcessingParams.m_pDrivingVector->size();
			if(uSize > 0){
				//if(m_ocrProcessingParams.m_bUpSideDown) {
				//	m_nCurrentRawLineIndx = uSize - 1;
				//}
				//else {
				m_nCurrentRawLineIndx = 0;
				//}
				COcrTextPage textPage;
				wstring sText;
				while(m_nCurrentRawLineIndx >= 0 && m_nCurrentRawLineIndx < int(uSize) &&
					GetRawLineText(*m_ocrProcessingParams.m_pDrivingVector->at(m_nCurrentRawLineIndx), 
					textPage, m_ocrProcessingParams)) {
						textPage.GetFilteredText(sText, 0, NULL, Dictionary::Instance());
						AddText(sText, 
							m_ocrProcessingParams.m_pDrivingVector->at(m_nCurrentRawLineIndx)->m_nParagraphIndx);
						WriteStringToLog("EVENT_ZONNING_DONE");
						WriteStringToLog(sText);
						WriteIntToLog(m_nCurrentRawLineIndx);
						//if(m_ocrProcessingParams.m_bUpSideDown) {
						//	--m_nCurrentRawLineIndx;
						//}
						//else {
						++m_nCurrentRawLineIndx;
						//}
				}
			}
		}
		WriteStringToLog("eEventZonningDone");
		break;
	case EVENT_PAGE_INFO_READY:
		//WriteTimeStampToLog("EVENT_PAGE_INFO_READY", false, m_eProcessingState);
		DisplayText((const WCHAR*)m_ocredText.GetEntireText().c_str());
		break;
	case EVENT_OCR_CHUNK_DONE: 

		//WriteTimeStampToLog("EVENT_OCR_CHUNK_DONE", false, m_eProcessingState);

		if(m_nCurrentRawLineIndx >= 0) {
			UINT uSize = m_ocrProcessingParams.m_pDrivingVector->size();
			if(uSize > 0) {
				COcrTextPage textPage;
				wstring sText;
				while(m_nCurrentRawLineIndx >= 0 && m_nCurrentRawLineIndx < int(uSize) &&
					GetRawLineText(*m_ocrProcessingParams.m_pDrivingVector->at(m_nCurrentRawLineIndx), 
					textPage, m_ocrProcessingParams)) {
						textPage.GetFilteredText(sText, 0, NULL, Dictionary::Instance());

						WriteStringToLog("EVENT_OCR_CHUNK_DONE");
						WriteStringToLog(sText);
						WriteIntToLog(m_nCurrentRawLineIndx);
						AddText(sText, 
							m_ocrProcessingParams.m_pDrivingVector->at(m_nCurrentRawLineIndx)->m_nParagraphIndx);
						//if(m_ocrProcessingParams.m_bUpSideDown) {
						//	--m_nCurrentRawLineIndx;
						//}
						//else {
						++m_nCurrentRawLineIndx;
						//}
				}
			}
		}
		break;
	case EVENT_OCR_DONE:

		//WriteTimeStampToLog("EVENT_OCR_DONE", false, m_eProcessingState);

		WriteStringToLog("eEventOcrCompleteDone");
		PlayText((const WCHAR*)m_ocredText.GetPendingSentence().c_str());
		if(m_eProcessingState == eIdle){
			//m_pSoundCoordinator->PlayFixedSound(CHIMES_SOUND);
			//m_pChipmonkCamera->StartPreview();
		}
		break;
	case EVENT_SPEAKING_DONE:

		//WriteTimeStampToLog("EVENT_SPEAKING_DONE", false, m_eProcessingState);

		if(m_eProcessingState == eReadingText){// && !m_pChipmonkCamera->IsPreviewOn()){
			//m_pSoundCoordinator->PlayFixedSound(CHIMES_SOUND);
			//m_pChipmonkCamera->StartPreview();
			m_eProcessingState = eIdle;
			if(g_bCancelProcessing == TRUE) {
				SetEvent(new CChipMonkEvent(EVENT_PROCESS_CANCELED));
			}
		}
		break;
	case EVENT_PROCESS_CANCELED:

		//WriteTimeStampToLog("EVENT_PROCESS_CANCELED", false, m_eProcessingState);

		PlayText((const WCHAR*)L"Canceled");
		//m_pChipmonkCamera->StartPreview();
		break;
	case EVENT_SPEAKING_NEW:

		//WriteTimeStampToLog("EVENT_SPEAKING_NEW", false, m_eProcessingState);

		//OnSpeakingNew();
		break;
	case EVENT_START_PREVIEW:

		//WriteTimeStampToLog("EVENT_START_PREVIEW", false, m_eProcessingState);

		//m_pChipmonkCamera->StartPreview();		
		break;
	default:
		WriteStringToLog("eEventUnknown");
		break;
		}
		delete pEvent;
		//PlayText((const WCHAR*)(L"Event done"));
		bBusy = FALSE;
	}
	//m_timerCriticalSection.Signal();
}

void CChipMonkCoordinator::OnOpenImage(const char* sImageFileName) {
	m_sImageFileName = sImageFileName;
	//m_pChipmonkCamera->StopPreview();
	ResumeImageProcessThread();
}
void CChipMonkCoordinator::OnSpeakingNew() {
	//m_pView->ScrolTextLineDown();
}
void CChipMonkCoordinator::SuspendImageProcessThread() {
	SuspendThread(m_imageProcessThread);
	//m_imageProcessThread.Suspend();
}

void CChipMonkCoordinator::ResumeImageProcessThread() {
	g_bCancelProcessing = FALSE;
	ResumeThread(m_imageProcessThread);
	//m_imageProcessThread.Resume();
}

int CChipMonkCoordinator::ProcessImage() {
	m_nBusyBeepCount = 0;
	m_eProcessingState = ePreprocessing;
	EPageOrientation eOrientation = eUnKnown;
	m_nCurrentRawLineIndx = -1;
	m_ocredText.Reset();
	//if(m_pView) {
	//	m_pView->ClearText();
	//}

	vector<int> vAngles;
	vector<pair<CRawLines*, int> > vRawLinesArc;
	UCHAR *p1bppBoW = NULL, *p1bppWoB = NULL;
	int nAvgLineSize = 0;

	if(!m_sImageFileName.empty()) {
		if(!LoadRawImage(m_sImageFileName.c_str())) {
			return FALSE;
		}
	}

	WriteStringToLog("ProcessImage 1");

	if(g_bCancelProcessing) {
		goto PROCESS_IMAGE_CLEAN_UP;
	}

	int nATThreshold, nBverWThreshold, nOcrThreshold;
	if(!PreprocessImage(vAngles, &p1bppBoW, &p1bppWoB, nATThreshold, nBverWThreshold, nOcrThreshold)) {
		goto PROCESS_IMAGE_CLEAN_UP;
	}
	
	WriteStringToLog("ProcessImage 2");

	m_eProcessingState = eZonning;
	if(g_bCancelProcessing) {
		goto PROCESS_IMAGE_CLEAN_UP;
	}
	for(vector<int>::const_iterator i = vAngles.begin(); i != vAngles.end(); ++i){
		m_houghTransform.FillRotationInfo(*i, m_pGreyImage->width, m_pGreyImage->height, m_iri);
		m_pRawlines->clear();
		int nActualAngle;
		nAvgLineSize = 
			LocateTextLines((UCHAR*)m_pGreyImage->imageData, 
					p1bppBoW, p1bppWoB, m_iri, nBverWThreshold, *m_pRawlines, 
					nActualAngle);

#ifdef __VERBOSE
		m_pRawlines->Print("c:\\Data\\tmp\\RawLines.txt");
#endif
		if(nAvgLineSize == -2){//wrong rotation angle
			m_houghTransform.FillRotationInfo(*i + nActualAngle, m_pGreyImage->width, m_pGreyImage->height, m_iri);
			nAvgLineSize = LocateTextLines((UCHAR*)m_pGreyImage->imageData, p1bppBoW, p1bppWoB, m_iri, nBverWThreshold, *m_pRawlines, nActualAngle);
		}
		if(g_bCancelProcessing) {
				goto PROCESS_IMAGE_CLEAN_UP;
		}
		if (nAvgLineSize == 0){
			continue;
		}
		if(nAvgLineSize < 0){
			break;
		}
		if(g_bCancelProcessing) {
			goto PROCESS_IMAGE_CLEAN_UP;
		}
			//Locate done
		if(!m_pRawlines->AnalyzePage(m_iri, 10, 30)) {
			continue;
		}
		if(!m_pRawlines->SetForceSingleOrderAndRegularOrder()) {
			continue;
		}
		PreparePageInfo();
		SetPageInfoReadyEvent();
		 
		m_eProcessingState = eInitOcring;
		InitalizeOcrProcessingParams(&m_ocr, *m_pRawlines, m_iri, (UCHAR*)m_pGreyImage->imageData, 
				nOcrThreshold, FALSE);
		eOrientation = GetPageOrientation();
		if(g_bCancelProcessing) {
			goto PROCESS_IMAGE_CLEAN_UP;
		}
			
		if(eOrientation == eUnKnown) {
			if(!m_pRawlines->NoText()){
				vRawLinesArc.push_back(pair<CRawLines*, int>(m_pRawlines, m_iri.nAngle));
				m_pRawlines = new CRawLines;
			}
		}
		else {
			SetZonningDoneEvent();
			OCRRawTextLines();
			break;
		}
	}

	WriteStringToLog("ProcessImage 3");

	if(eOrientation == eUnKnown) {
		CRawLines *pBestRawLines = m_pRawlines;
		int nBestAngle = m_iri.nAngle;
		BOOL bUpsideDown = FALSE;
		wstring sText;
		GetText(sText);
		UINT nMaxLength = sText.length();
		vector<pair<CRawLines*, int> >::iterator j;
		for(j = vRawLinesArc.begin(); j != vRawLinesArc.end(); ++j) {
			GetText(sText, j->first, TRUE);
			if(sText.length() > nMaxLength) {
			nMaxLength = sText.length();
				pBestRawLines = j->first;
				nBestAngle = j->second;
				bUpsideDown = TRUE;
			}
			GetText(sText, j->first, FALSE);
			if(sText.length() > nMaxLength) {
				nMaxLength = sText.length();
				pBestRawLines = j->first;
				nBestAngle = j->second;
				bUpsideDown = FALSE;
			}
		}
		if(pBestRawLines != m_pRawlines) {
			delete m_pRawlines;
			m_pRawlines = pBestRawLines;
		}
		for(j = vRawLinesArc.begin(); j != vRawLinesArc.end(); ++j) {
			if(j->first != pBestRawLines) delete j->first;
		}
		m_ocrProcessingParams.m_bUpSideDown = bUpsideDown;
		m_ocrProcessingParams.m_pLines = m_pRawlines;
		m_ocrProcessingParams.m_pDrivingVector = &m_pRawlines->m_vRegularOrder;
	}
	else {
		for(vector<pair<CRawLines*, int> >::iterator j = vRawLinesArc.begin(); j != vRawLinesArc.end(); ++j) {
			delete j->first;
		}
	}

	WriteStringToLog("ProcessImage 4");

PROCESS_IMAGE_CLEAN_UP:
	WriteStringToLog("ProcessImage PROCESS_IMAGE_CLEAN_UP");
	if(g_bCancelProcessing == TRUE) {
		m_eProcessingState = eIdle;
		SetEvent(new CChipMonkEvent(EVENT_PROCESS_CANCELED));
	
	}
	else{
		if(m_eProcessingState != eOcring) {
			SetZonningDoneEvent();
		}
		//if(m_pSoundCoordinator->IsSpeaking()) {
		//	m_eProcessingState = eReadingText;
		//}
		//else {
			m_eProcessingState = eIdle;
		//}
		SetOcrDoneEvent();
	}
	return nAvgLineSize;
}

void CChipMonkCoordinator::SetEvent(CEventBase *pEvent) {
	//m_eventQCriticalSection.Wait();
	CSingleLock sl(&m_eventQCriticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		m_eventQ.push_back(pEvent);
	}
	//m_eventQCriticalSection.Signal();
}

void CChipMonkCoordinator::SetZonningDoneEvent() {
	SetEvent(new CChipMonkEvent(EVENT_ZONNING_DONE));
}

void CChipMonkCoordinator::SetOcrDoneEvent() {
	SetEvent(new CChipMonkEvent(EVENT_OCR_DONE));
}
void CChipMonkCoordinator::SetSpeakingNewEvent() {
	SetEvent(new CChipMonkEvent(EVENT_SPEAKING_NEW));
}
void CChipMonkCoordinator::SetPageInfoReadyEvent()
	{
	SetEvent(new CChipMonkEvent(EVENT_PAGE_INFO_READY));		
	}
void CChipMonkCoordinator::PreparePageInfo()
	{
	int nSections, nTotalWords, nTextAreaFrac, nColumns, nHeaders;
	m_pRawlines->GetPageDescription(nSections, nTotalWords, nTextAreaFrac,
							   nColumns, nHeaders);
	WCHAR num_val[16];
	wstring s = L"Page info: ";
	
	s.append(L"Sections: ");
	swprintf(num_val, L"%d", nSections );
	s.append(num_val);
	
	s.append(L". Words: ");
	swprintf(num_val, L"%d", nTotalWords );
	s.append(num_val);
	
	s.append(L". Columns: ");
	swprintf(num_val, L"%d", nColumns );
	s.append(num_val);
	s.append(L". ");
	m_pOS->DisplayPageInfo(s.c_str());
}

void CChipMonkCoordinator::SetNextOcrChunkDoneEvent() {
	SetEvent(new CChipMonkEvent(EVENT_OCR_CHUNK_DONE));
}

BOOL CChipMonkCoordinator::OCRRawTextLines() {
	if(m_ocrProcessingParams.m_pDrivingVector->empty()) {
		return FALSE;
	}
	m_eProcessingState = eOcring;
	while(!g_bCancelProcessing && !m_ocrProcessingParams.m_listNotOcredRawLines.empty()) {
		int nLineIndx, nParagraphIndx;
		CSingleLock sl(&m_ocrCriticalSection);//m_ocrCriticalSection.Wait();
		sl.Lock();
		if(sl.IsLocked()) {
			nParagraphIndx = (*m_ocrProcessingParams.m_itNextRawLineToOcr)->m_nParagraphIndx; 
			nLineIndx = (*m_ocrProcessingParams.m_itNextRawLineToOcr)->m_nLineIndx;
			m_ocrProcessingParams.m_itNextRawLineToOcr = 
				m_ocrProcessingParams.m_listNotOcredRawLines.erase(m_ocrProcessingParams.m_itNextRawLineToOcr);
			sl.Unlock();
		}
			//m_ocrCriticalSection.Signal();
			OcrNextChunk(m_ocrProcessingParams, nParagraphIndx, nLineIndx);
		sl.Lock();
		if(sl.IsLocked()) {
			//m_ocrCriticalSection.Wait();
			if(m_ocrProcessingParams.m_itNextRawLineToOcr == m_ocrProcessingParams.m_listNotOcredRawLines.end()) {
				m_ocrProcessingParams.m_itNextRawLineToOcr = m_ocrProcessingParams.m_listNotOcredRawLines.begin();
			}
			//m_ocrCriticalSection.Signal();
			sl.Unlock();
		}
	}
	return TRUE;
}

void  CChipMonkCoordinator::InitalizeOcrProcessingParams(COCR* ocr, CRawLines& lines, 
								const ImgRotationInfo& iri, const UCHAR* p8bppImg, int nThreshold,
								bool bForceSingleColumn) {
	m_ocrProcessingParams.Set(ocr, &lines, 
		bForceSingleColumn ? &lines.m_vForceSingleOrder : &lines.m_vRegularOrder,
		&m_iri, p8bppImg, nThreshold);
}

EPageOrientation  CChipMonkCoordinator::GetPageOrientation() {
	EPageOrientation eOrientation = GetPageOrientation(m_ocrProcessingParams);
	BOOL bUpsideDown = (eOrientation == eUpSideDown);
	m_pRawlines->SetUpSideDown(bUpsideDown);
	m_ocrProcessingParams.SetPageOrientation(bUpsideDown);
	return eOrientation;
}

EPageOrientation CChipMonkCoordinator::GetPageOrientation(COcrProcessingParams & ocrProcessingParams) {

	int nParagraphs  = m_pRawlines->GetNumOfParagraphs();
	if(m_pRawlines->m_nMainParagraphIndx < 0 || nParagraphs < 1) return eUnKnown;

	EPageOrientation eOrientation = eUnKnown;
	vector<CParagraph*> m_vParagraphs;
	CParagraph *pMainParagraph = m_pRawlines->m_vParagraphs[m_pRawlines->m_nMainParagraphIndx];
	int nStartParagraph = 0, i;
	if(pMainParagraph && pMainParagraph->GetNumTotalWords() > 6 && pMainParagraph->GetTotalNumOfComponents() > 20 &&
		(pMainParagraph->size() > 2 || pMainParagraph->Width() > pMainParagraph->GetHeight() * 30)) {
			for(i = 0; i < nParagraphs; ++i) {
				CParagraph *pP = m_pRawlines->m_vParagraphs[i];
				if(pP) {
					if(pP && pP->GetNumTotalWords() > 6 && pP->GetTotalNumOfComponents() > 20 &&
						(pP->size() > 2 || pP->Width() > pP->GetHeight() * 30)) {
							nStartParagraph = i;
							break;
					}
				}
			}
	}
	
	for(int i = 0; i < nParagraphs; ++i) {
		if((eOrientation = 
			GetParagraphOrientation((i + nStartParagraph) % nParagraphs, ocrProcessingParams)) != eUnKnown) {
			return eOrientation;
		}
	}
	return eOrientation;
}

int CalcStep(int nChunkLines, int nMinChunkLines, int nLines){
	if(nLines <= nChunkLines){
		return nLines;
	}
	for(int nRes = nLines - nChunkLines; 
		nRes != 0 && nRes < nMinChunkLines; 
		--nChunkLines, nRes = nLines - nChunkLines);
	if(nChunkLines < nMinChunkLines) nChunkLines = nLines;
	return nChunkLines;
}

void RotateUpsideDown(vector<CRect> & vOcredLine, int nWidth, int nHeight);
int FromCorrectedY2OriginalY(int nX, int nCorrectedY, int nXCenter, int nYCenter, const LONGLONG *pCoefs, 
							LONGLONG (*GetValueFunction)(LONGLONG, LONGLONG, const LONGLONG *));

bool MatchOcredLines(vector<CRawLine*>::iterator iFirst, vector<CRawLine*>::iterator iLast,
					 COcrTextRegion & otr,
					const CPoint & center, int nOrderX, int nOrderY, const LONGLONG *pCoefs, 
					int nWidth, int nHeight, int nHalfOrigWidth, int nHalfOrigHeight, int nScale, bool bUpSideDown) {

	typedef LONGLONG (*GET_VALUE_FUNCTION)(LONGLONG, LONGLONG, const LONGLONG *);
	GET_VALUE_FUNCTION getValue = NULL;
	if(nOrderX == 1 && nOrderY == 1){
		getValue = CalcYCorrection_1_1;
	}
	else if(nOrderX == 2 && nOrderY == 1){
		getValue = CalcYCorrection_2_1;
	}
	else if(nOrderX == 2 && nOrderY == 2){
		getValue = CalcYCorrection_2_2;
	}
	else if(nOrderX == 3 && nOrderY == 1){
		getValue = CalcYCorrection_3_1;
	}
	else if(nOrderX == 3 && nOrderY == 2){
		getValue = CalcYCorrection_3_2;
	}
	else if(nOrderX == 3 && nOrderY == 3){
		getValue = CalcYCorrection_3_3;
	}
	else{
		getValue = NULL;
	}

	vector<COcrBasicTextRegion*> vOcredLine;
	vector<CRect> vOcred, vOcredCCs;
	UINT uMatch = 0;
	for(COcrTextRegion::iterator i = otr.begin(); i != otr.end(); ++i) {
		vOcredLine.clear();
		vOcredCCs.clear();
		vOcred.clear();
		if(*i) {
			(*i)->Linearize(vOcredLine);
			{for(vector<COcrBasicTextRegion*>::const_iterator k = vOcredLine.begin(); k != vOcredLine.end(); ++k)
				if(*k)vOcred.push_back(**k);
			}
			if(bUpSideDown) {
				RotateUpsideDown(vOcred, (nWidth * nScale) >> SCALE_FXPNT, (nHeight * nScale) >> SCALE_FXPNT);
			}
			int nCenterX = center.x - nHalfOrigWidth;
			for(vector<CRect>::const_iterator j = vOcred.begin(); j != vOcred.end(); ++j) {
				int nLeft = (j->left << SCALE_FXPNT) / nScale;
				int nTop = (j->top  << SCALE_FXPNT) / nScale;;
				int nRight = (j->right  << SCALE_FXPNT) / nScale;
				int nBottom = (j->bottom  << SCALE_FXPNT) / nScale;
				int nYtop = FromCorrectedY2OriginalY(nLeft, nTop, nHalfOrigWidth, nHalfOrigHeight, pCoefs, getValue) + center.y;
				int nYbottom = FromCorrectedY2OriginalY(nRight, nBottom, nHalfOrigWidth, nHalfOrigHeight, pCoefs, getValue) + center.y;
				vOcredCCs.push_back(CRect(nLeft + nCenterX, nYtop, nRight + nCenterX, nYbottom));
			}

			int nOvlp, nMaxOvlp = 0;
			vector<CRawLine*>::iterator match = iLast;
			for(vector<CRawLine*>::iterator j = iFirst; j != iLast; ++j) {
				if(*j) {
					if((nOvlp = (*j)->CalcOverlap(vOcredCCs)) > nMaxOvlp) {
						nMaxOvlp = nOvlp;
						match = j;
					}
				}
			}
			if(nMaxOvlp > 0) {
				if(bUpSideDown) {
					(*match)->m_vOcrTextLinesUSD.push_back((COcrTextLine*)*i);
				}
				else {
					(*match)->m_vOcrTextLinesUSU.push_back((COcrTextLine*)*i);
				}
				++uMatch;
			}
		}
	}
	return uMatch == otr.size();
}

void MatchOcredTextLines(CParagraph *pParagraph, COcrChunk *pOcrChunk, bool bUpsideDown) {
	COcrTextPage & textPage = bUpsideDown ? pOcrChunk->m_upSideDownTp : pOcrChunk->m_upSideUpTp;
	if(textPage.empty()) return;
	MatchOcredLines(pParagraph->begin() + pOcrChunk->m_nFirstLine, 
					pParagraph->begin() + pOcrChunk->m_nLastLine,
					*((COcrTextRegion*)textPage.front()),
					pOcrChunk->m_origin ,pOcrChunk->m_nOrderX, pOcrChunk->m_nOrderY, pOcrChunk->m_pCoefs, 
					pOcrChunk->m_bb.Width(), pOcrChunk->m_bb.Height(), 
					pOcrChunk->m_origin.x - pOcrChunk->m_bb.left, 
					pOcrChunk->m_origin.y - pOcrChunk->m_bb.top, pOcrChunk->m_nScale, bUpsideDown);
	if(pParagraph->GetDoNotFilter())  {
		for(COcrTextRegion::iterator i = textPage.front()->begin();
			i != textPage.front()->end(); ++i) {
				if(*i){
					(*i)->SetTextFeature(DO_NOT_FILTER);
				}
		}
	}
}

EPageOrientation CChipMonkCoordinator::GetParagraphOrientation(int nParagraph, COcrProcessingParams & ocrProcessingParams) {
	CParagraph *pParagraph = ocrProcessingParams.m_pLines->m_vParagraphs[nParagraph];
	if(!pParagraph) {
		goto ORIENTATION_UNKNOWN;
	}
	else {
		int nLines = pParagraph->size();
		int nBitmapWidth, nBitmapHeight;
		int nStatus = 0;
		LONGLONG pCoefs[10];
		int nOrderX, nOrderY;
		int nScale;
		CRect bb;
		CPoint origin;
		IplImage *pGreyImg = NULL;
		Dictionary *pDict = Dictionary::Instance();
		
		for(int i = 0; i < nLines && !g_bCancelProcessing;) {
			UCHAR* pBitmap = 
				ocrProcessingParams.m_pLines->GetParagraphNBitmap(nParagraph,
				i, i, ocrProcessingParams.m_p8bppImg, *ocrProcessingParams.m_pIri, 34, ocrProcessingParams.m_nMargins, 
				ocrProcessingParams.m_nThreshold, nBitmapWidth, nBitmapHeight, true, 
				ocrProcessingParams.m_nFixCurvatureOptimalLinesCount, NULL, &pGreyImg,
				0, nStatus, &nOrderX, &nOrderY, pCoefs, &nScale, &bb, &origin);
/* VS 
			if (i == 0)
			SaveaBMP(pBitmap, "c:\\Data\\tmp\\F0.bmp", nBitmapWidth, nBitmapHeight, 1, true, nBitmapWidth / 8);
			if (i == 1)
			SaveaBMP(pBitmap, "c:\\Data\\tmp\\F1.bmp", nBitmapWidth, nBitmapHeight, 1, true, nBitmapWidth / 8);
			if (i == 2)
			SaveaBMP(pBitmap, "c:\\Data\\tmp\\F2.bmp", nBitmapWidth, nBitmapHeight, 1, true, nBitmapWidth / 8);
			if (i == 3)
			SaveaBMP(pBitmap, "c:\\Data\\tmp\\F3.bmp", nBitmapWidth, nBitmapHeight, 1, true, nBitmapWidth / 8);
*/			
					
			if(!pBitmap || g_bCancelProcessing) {
				continue;
			}
			int nFirstLine = i;
			if(nStatus == CANNOT_SUBDIVIDE_THE_PARAGRAPH){
				i = nLines;
			}
			else {
				++i;
			}
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			WriteStringToLog("AddOcrChunk");
			COcrChunk *pOcrChunk = pParagraph->AddOcrChunk(nFirstLine, i, pGreyImg, pBitmap,
				nOrderX, nOrderY, pCoefs, bb, nScale, origin);
			//WriteTimeStampToLog("Recogn 1 beg", false, m_eProcessingState);
			ocrProcessingParams.m_pOcr->Recognize(pBitmap, nBitmapWidth, nBitmapHeight, pOcrChunk->m_upSideUpTp, true);
			//WriteTimeStampToLog("Recogn 1 end", false, m_eProcessingState);
			pOcrChunk->SetOcred(true);
			wstring sText;
			pOcrChunk->m_upSideUpTp.GetText(sText);
			WriteStringToLog("GetText");
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			if(!sText.empty()){
				ocrProcessingParams.m_nUpSideUpWords += 
					CountFoundInDictionaryWordsInTheLastRegion(pOcrChunk->m_upSideUpTp, pDict, ocrProcessingParams.m_nMinWordLenght);
				if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
				MatchOcredTextLines(pParagraph, pOcrChunk, false);
				if(ocrProcessingParams.m_nUpSideUpWords >= ocrProcessingParams.m_nEnoughFoundWords) {
					WriteStringToLog("eUpSideUp");
					SetNextOcrChunkDoneEvent();
					return eUpSideUp;
				}
			}
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			Rotate1bppImgUpsideDown(pBitmap, nBitmapWidth, nBitmapHeight);
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			//WriteTimeStampToLog("Recogn 2 beg", false,m_eProcessingState);
			ocrProcessingParams.m_pOcr->Recognize(pBitmap, nBitmapWidth, nBitmapHeight, pOcrChunk->m_upSideDownTp, true);
			//WriteTimeStampToLog("Recogn 2 end", false,m_eProcessingState);
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			pOcrChunk->SetOcred(true);
			sText.erase();
			pOcrChunk->m_upSideDownTp.GetText(sText);
			if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
			if(!sText.empty()){
				ocrProcessingParams.m_nUpSideDownWords += 
					CountFoundInDictionaryWordsInTheLastRegion(pOcrChunk->m_upSideDownTp, pDict, ocrProcessingParams.m_nMinWordLenght);
				if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
				MatchOcredTextLines(pParagraph, pOcrChunk, true);
				if(g_bCancelProcessing)goto ORIENTATION_UNKNOWN;
				if(ocrProcessingParams.m_nUpSideDownWords >= ocrProcessingParams.m_nEnoughFoundWords) {
					WriteStringToLog("eUpSideDown");
					SetNextOcrChunkDoneEvent();
					return eUpSideDown;
				}
			}
		}
	}
ORIENTATION_UNKNOWN:
	WriteStringToLog("eUnKnown");
	SetNextOcrChunkDoneEvent();
	return eUnKnown;
}

void CChipMonkCoordinator::GetText(wstring &sText, CRawLines *pRawLines, BOOL bUpsideDown){
	Dictionary *pDict = Dictionary::Instance();
	WCHAR sDev[512];
	sText.clear();
	int nParagraph = 0;
	if(!pRawLines) pRawLines = m_pRawlines;
	vector<CParagraph*> pParagraphs = pRawLines->m_vParagraphs;
	if(bUpsideDown) {
		for(vector<CParagraph*>::reverse_iterator i = pParagraphs.rbegin(); i != pParagraphs.rend(); ++i) {
			if(*i) {
				wstring sPar;
				for(CParagraph::reverse_iterator j = (*i)->rbegin(); j != (*i)->rend(); ++j) {
					if(*j) {
						vector<COcrTextLine*> & vLines = (*j)->m_vOcrTextLinesUSD;
						wstring sT;
						for(vector<COcrTextLine*>::iterator k = vLines.begin(); k != vLines.end(); ++k) {
							if(*k) {
								(*k)->GetFilteredText(sT, pDict);
								sPar += sT;
							}
						}
					}
				}
				if(!sPar.empty()) {
					// swprintf(sDev, L"\r\n--- Paragraph %d -----------------------------\r\n\r\n", ++nParagraph);
					swprintf((wchar_t*)sDev, 512, L"\r\n\r\n", ++nParagraph);
					sText += (wchar_t*)sDev;
					sText += sPar;
				}
			}
		}
	}
	else {
		for(vector<CParagraph*>::iterator i = pParagraphs.begin(); i != pParagraphs.end(); ++i) {
			if(*i) {
				wstring sPar;
				for(CParagraph::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
					if(*j) {
						vector<COcrTextLine*> & vLines = (*j)->m_vOcrTextLinesUSU;
						for(vector<COcrTextLine*>::iterator k = vLines.begin(); k != vLines.end(); ++k) {
							wstring sT;
							if(*k) {
								(*k)->GetFilteredText(sT, pDict);
								sPar += sT;
							}
						}
					}
				}
				if(!sPar.empty()) {
					//swprintf(sDev, L"\r\n--- Paragraph %d -----------------------------\r\n\r\n", ++nParagraph);
					swprintf((wchar_t*)sDev, 512, L"\r\n\r\n", ++nParagraph);
					sText += (wchar_t*)sDev;
					sText += sPar;
				}
			}
		}
	}
}

void CChipMonkCoordinator::GetText(wstring &sText, CRawLines *pRawLines){
	GetText(sText, pRawLines, m_ocrProcessingParams.m_bUpSideDown);
}

bool CChipMonkCoordinator::OcrNextChunk(COcrProcessingParams & ocrProcessingParams, int nParagraph, int nLineIndex, 
							int nOptChunkLines, int nMinChunkLines) {
					
							
	CParagraph *pParagraph = ocrProcessingParams.m_pLines->m_vParagraphs[nParagraph];
	if(pParagraph->OCredAlready(nLineIndex)) {
		return true;
	}
	int nStatus = 0;
	int nOrderX = 0, nOrderY = 0, nScale;
	CRect bb;
	CPoint origin;
	LONGLONG pCoefs[10];
	int nBitmapWidth, nBitmapHeight;
	UCHAR* pBitmap = NULL;
	IplImage *pGreyImg = NULL;
	COcrTextPage *pTp = NULL;
	int nFirstLine, nLastLine, nLines, nChunkLines, nFl, nLl;
	COcrChunk *pOcrChunk = NULL;
	
	if(g_bCancelProcessing) {goto OcrNextChunkCLEAN_UP;}
	for(nFirstLine = nLineIndex; nFirstLine >= 0 && !pParagraph->OCredAlready(nFirstLine); --nFirstLine);
	++nFirstLine;
	for(nLastLine = nLineIndex; nLastLine < (int)pParagraph->size() && !pParagraph->OCredAlready(nLastLine); ++nLastLine);
	nLines = nLastLine - nFirstLine;
	nChunkLines = 0;
	nFl = nFirstLine;
	for(;;) {
		nChunkLines = CalcStep(nOptChunkLines, nMinChunkLines, nLines);
		if(nFl + nChunkLines > nLineIndex) {
			break;
		}
		nFl += nChunkLines;
		nLines -= nChunkLines;
	}
	nLl = nFl + nChunkLines - 1;
	if(g_bCancelProcessing) {
		goto OcrNextChunkCLEAN_UP;
	}
	pBitmap = 
		ocrProcessingParams.m_pLines->GetParagraphNBitmap(nParagraph,
			nFl, nLl, ocrProcessingParams.m_p8bppImg, *ocrProcessingParams.m_pIri, 34, ocrProcessingParams.m_nMargins, 
			ocrProcessingParams.m_nThreshold, nBitmapWidth, nBitmapHeight, true, 
			ocrProcessingParams.m_nFixCurvatureOptimalLinesCount, NULL, &pGreyImg,
				0, nStatus, &nOrderX, &nOrderY, pCoefs, &nScale, &bb, &origin);
	if(g_bCancelProcessing) {goto OcrNextChunkCLEAN_UP;}
	if(!pBitmap) {
		return false;
	}
	if(nStatus != CANNOT_SUBDIVIDE_THE_PARAGRAPH){
			nFirstLine = nFl;
			nLastLine = nLl + 1;
	}
	pOcrChunk = pParagraph->AddOcrChunk(nFirstLine, nLastLine, pGreyImg, pBitmap,
		nOrderX, nOrderY, pCoefs, bb, nScale, origin);
	if(g_bCancelProcessing) {goto OcrNextChunkCLEAN_UP;}
	if(ocrProcessingParams.m_bUpSideDown) {
		pTp = &pOcrChunk->m_upSideDownTp;
		Rotate1bppImgUpsideDown(pBitmap, nBitmapWidth, nBitmapHeight);
	}
	else {
		pTp = &pOcrChunk->m_upSideUpTp;
	}
	if(g_bCancelProcessing) {goto OcrNextChunkCLEAN_UP;}
	ocrProcessingParams.m_pOcr->Recognize(pBitmap, nBitmapWidth, nBitmapHeight, *pTp, 
		ocrProcessingParams.m_bDegraded);
	pOcrChunk->SetOcred(true);
	if(g_bCancelProcessing) {goto OcrNextChunkCLEAN_UP;}
	MatchOcredTextLines(pParagraph, pOcrChunk, ocrProcessingParams.m_bUpSideDown);

OcrNextChunkCLEAN_UP:
	SetNextOcrChunkDoneEvent();					
	return true;
}

BOOL CChipMonkCoordinator::GetRawLineText(CRawLine & rawLine, COcrTextPage& textPage, 
		COcrProcessingParams & ocrProcessingParams) {
	CParagraph *pParagraph = ocrProcessingParams.m_pLines->m_vParagraphs[rawLine.m_nParagraphIndx];
	if(g_bCancelProcessing) return FALSE;
	textPage.clear();
	if(pParagraph->OCredAlready(rawLine.m_nLineIndx)) {
		textPage.AddRegion(rawLine);
		vector<COcrTextLine*> *pOcrTextLines = 
			ocrProcessingParams.m_bUpSideDown ? &rawLine.m_vOcrTextLinesUSD : &rawLine.m_vOcrTextLinesUSU;
		for(vector<COcrTextLine*>::iterator i = pOcrTextLines->begin(); i != pOcrTextLines->end(); ++i) {
			if(*i) {
				if(g_bCancelProcessing) return FALSE;
				textPage.AddLineToLastRegion(**i);
				textPage.front()->back()->Copy(*i);
			}
		}
		if(g_bCancelProcessing) return FALSE;
		textPage.AddTextFeatureToRegions(COMPLETELY_OCRED);
		return TRUE;
	}
	
	//ocrProcessingParams.SetNextLineToOcr(rawLine.m_nParagraphIndx, rawLine.m_nLineIndx);
	return FALSE;
}

COcredText::COcredText() : m_nLastParagraph(-1) {
	//m_criticalSection.CreateLocal();
}

COcredText::~COcredText() {
}

void COcredText::Reset() {
	//m_criticalSection.Wait();
	CSingleLock sl(&m_criticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		m_nLastParagraph = -1;
		m_sPendingSentence.erase();
		m_sEntireText.erase();
		clear();
		//m_criticalSection.Signal();
	}
}

wstring COcredText::GetPendingSentence() {
	wstring sText;
	//m_criticalSection.Wait();
	CSingleLock sl(&m_criticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		sText = m_sPendingSentence;
		//m_criticalSection.Signal();
	}
	return sText;
}

wstring COcredText::GetEntireText() {
	wstring sText;
	//m_criticalSection.Wait();
	CSingleLock sl(&m_criticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		sText = m_sEntireText;
		//m_criticalSection.Signal();
	}
	return sText;
}

int COcredText::AddLineOfText(int nParagraph, const wstring & sText) {
	//m_criticalSection.Wait();
	int  nCount = 0;
	CSingleLock sl(&m_criticalSection);
	sl.Lock();
	if(sl.IsLocked()) {
		m_sEntireText += sText;
		if(m_nLastParagraph < 0) {
			m_nLastParagraph = nParagraph;
		}
		else if(m_nLastParagraph != nParagraph) {
			m_nLastParagraph = nParagraph;
			push_back(m_sPendingSentence);
			m_sPendingSentence.erase();
			++nCount;
		}
		int nStart = 0;

		for(int nPos = FindEndOfSentence(sText, nStart); nPos >= 0 && 
			nStart < (int)sText.length(); nPos = FindEndOfSentence(sText, nStart)) {
				m_sPendingSentence += sText.substr(nStart, nPos - nStart + 1);
				push_back(m_sPendingSentence);
				++nCount;
				m_sPendingSentence.erase();
				nStart = nPos + 1;	
		}
		if(nStart < (int)sText.length()) {
			m_sPendingSentence += sText.substr(nStart);
		}
		//m_criticalSection.Signal(
	}
	return nCount;
}

void CChipMonkCoordinator::AddText(wstring sText, int nParagraph) {
	int nNewSentences = m_ocredText.AddLineOfText(nParagraph, sText);
	int nSentences = (int)m_ocredText.size();
	//WriteTimeStampToLog("Dspl beg", false, m_eProcessingState);
	DisplayText((const WCHAR*)m_ocredText.GetEntireText().c_str());
	//WriteTimeStampToLog("Dspl end", false, m_eProcessingState);
	for(int i = 0; i < nNewSentences; ++i) {
		PlayText((const WCHAR*)m_ocredText[nSentences - nNewSentences + i].c_str());
	}
}

//BOOL CChipMonkCoordinator::StartCamera() {
//	m_pChipmonkCamera->StartPreview();
//	return TRUE;
//}
//
//void CChipMonkCoordinator::ProcessStillCameraImage() {
//	m_sImageFileName.erase();
//	ResumeImageProcessThread();
//}

//BOOL CChipMonkCoordinator::TakeImage() {
//	if(m_uRawImageSize < 2000000) {
//		if(m_pRawImageBuff) {
//			delete [] m_pRawImageBuff;
//		}
//		m_pRawImageBuff = new UCHAR[m_uRawImageSize =  2000000];
//	}
//	if(m_pChipmonkCamera) {
//		m_pChipmonkCamera->TakeStillImage(eHighResolution, m_pRawImageBuff, 2000000);
//	}
//	return TRUE;
//}

//void CChipMonkCoordinator::CancelCameraFocus() {
//	if(m_pChipmonkCamera) {
//		m_pChipmonkCamera->CancelFocus();
//	}
//}

CChipMonkCoordinator::EProcessingState CChipMonkCoordinator::GetState() const {
	return m_eProcessingState;
}

void CChipMonkCoordinator::CancelProcess() {
	g_bCancelProcessing = TRUE;
	//m_pSoundCoordinator->Stop();
}

//CSoundCoordinator *CChipMonkCoordinator::GetSoundCoordinator() {
//	return m_pSoundCoordinator;
//}

//void CChipMonkCoordinator::DrawBitmap(CFbsBitmap* pBitmap) {
//	if(m_pView) {
//		m_pView->DrawBitmap(pBitmap);
//	}
//}
//
void CChipMonkCoordinator::DisplayText(const WCHAR *pText) {
	if(m_pOS) {
		m_pOS->DrawText(pText);
	}
}

