#ifndef __CHIPMONK_COORDINATOR_H__
#define  __CHIPMONK_COORDINATOR_H__

#include "ChipMonkTypes.h"
#include <vector>
#include <string>
#include "afxmt.h"
#include <deque>
//#include <e32std.h>
#include "RawLine.h"
#include "Ocr.h"
//#include <fbs.h>

using namespace std;

#include "HoughTransform.h"

//class CSoundCoordinator;
//class CPeriodic;
//class TCallBack;
//class CChipmonkCamera;
//class CChipmonkAppView;

class COSBase {
public:
	virtual void DrawText(const WCHAR *pText) = 0;
	virtual void DisplayPageInfo(const WCHAR *pText) = 0;
	virtual void Speak(const WCHAR *pText) = 0;
	virtual void DingSound() = 0;
};

struct COcrProcessingParams  {
	COCR *m_pOcr;
	CRawLines* m_pLines;
	vector<CRawLine*> *m_pDrivingVector;
	list<CRawLine*> m_listNotOcredRawLines;
	list<CRawLine*>::iterator m_itNextRawLineToOcr;
	const ImgRotationInfo* m_pIri;
	const UCHAR* m_p8bppImg;
	int m_nThreshold;
	int m_nUpSideUpWords, m_nUpSideDownWords;
	bool m_bUpSideDown;
	int m_nMargins, m_nFixCurvatureOptimalLinesCount;
	int m_nMinWordLenght;
	int m_nEnoughFoundWords;
	bool m_bDegraded;
	map<pair<int, int>, int> m_mapParLine2GlobLine;


	COcrProcessingParams(COCR *pOcr = NULL, 
		CRawLines* pLines = NULL, 
		vector<CRawLine*> *pDrivingVector  = NULL,
		const ImgRotationInfo *pIri  = NULL,
		const UCHAR* p8bppImg = NULL, 
		int nThreshold = 0) :
		m_pOcr(pOcr),
		m_pLines(pLines),
		m_pDrivingVector(pDrivingVector),
		m_pIri(pIri),
		m_p8bppImg(p8bppImg),
		m_nThreshold(nThreshold),
		m_nUpSideUpWords(0), m_nUpSideDownWords(0),
		m_bUpSideDown(FALSE) { 
		m_nMargins = 16;
		m_nFixCurvatureOptimalLinesCount = 7;
		m_nMinWordLenght = 4;
		m_nEnoughFoundWords = 4;
		m_bDegraded = true;
		m_itNextRawLineToOcr = m_listNotOcredRawLines.end();
	}

	void Set(COCR *pOcr, 
		CRawLines* pLines, 
		vector<CRawLine*> *pDrivingVector,
		const ImgRotationInfo *pIri,
		const UCHAR* p8bppImg, 
		int nThreshold) {
			m_pOcr = pOcr;
			m_pLines = pLines;
			m_pDrivingVector = pDrivingVector;
			m_pIri = pIri;
			m_p8bppImg = p8bppImg;
			m_nThreshold = nThreshold;
			m_nUpSideUpWords = m_nUpSideDownWords = 0;
			m_bUpSideDown = FALSE; 
			m_nMargins = 16;
			m_nFixCurvatureOptimalLinesCount = 7;
			m_nMinWordLenght = 4;
			m_nEnoughFoundWords = 4;
			m_bDegraded = true;
			m_itNextRawLineToOcr = m_listNotOcredRawLines.end();
	}

	void SetPageOrientation(bool bUpSideDown) {
		m_bUpSideDown = bUpSideDown;
		m_listNotOcredRawLines.assign(m_pDrivingVector->begin(), m_pDrivingVector->end());
		m_itNextRawLineToOcr = m_listNotOcredRawLines.begin();
		for(int i = 0; i <  int(m_pDrivingVector->size()); ++i) {
			CRawLine *pRl = m_pDrivingVector->at(i);
			if(pRl) {
				m_mapParLine2GlobLine.insert(pair<pair<int, int>, int> (
					pair<int, int>(pRl->m_nParagraphIndx, pRl->m_nLineIndx), i));
			}
		}
	}

	void clear() {
		m_listNotOcredRawLines.clear();
		m_itNextRawLineToOcr = m_listNotOcredRawLines.end();
		m_mapParLine2GlobLine.clear();
	}

	bool SetNextLineToOcr(int nParagraphInd, int nLineIndx); 
};

typedef enum {eEventNone = 0, eEventZonningDone, eEventOcrChunkDone, eEventOcrDone} EChipMonkEventType;

class CChipMonkEvent : public CEventBase{
public:
	CChipMonkEvent(int nId) :
	CEventBase(nId) {}
	~CChipMonkEvent(){}
};

class COcredText : public vector<wstring> {
	//RCriticalSection m_criticalSection;
	CCriticalSection m_criticalSection;
	wstring m_sPendingSentence;
	wstring m_sEntireText;
	int m_nLastParagraph;
public:
	COcredText();
	
	~COcredText();
	
	int AddLineOfText(int nParagraph, const wstring & sText);
	void Reset();
	wstring GetPendingSentence();
	wstring GetEntireText();
};

class CChipMonkCoordinator : public CCoordinatorBase{
	UCHAR *m_pRawImageBuff;
	IplImage *m_pGreyImage;
	UINT m_uMaxRawImageSize, m_uRawImageSize, m_uRawImageWidth, m_uRawImageHeight;
	//CSoundCoordinator* m_pSoundCoordinator;
	CHoughTransform m_houghTransform;
	//CPeriodic *m_pTimer;
	//TCallBack *m_pTimerCallback;
	//RCriticalSection m_timerCriticalSection;
	//RThread m_imageProcessThread;
	CCriticalSection m_timerCriticalSection;
	HANDLE m_imageProcessThread;
	string m_sImageFileName;
	
	CRawLines *m_pRawlines;
	ImgRotationInfo m_iri;
	
	//RCriticalSection m_eventQCriticalSection;
	CCriticalSection m_eventQCriticalSection;
	deque<CEventBase*> m_eventQ;
	COcrProcessingParams m_ocrProcessingParams;
	//RCriticalSection m_ocrCriticalSection;
	CCriticalSection m_ocrCriticalSection;
	
	COCR m_ocr;
	
	int m_nCurrentRawLineIndx;
	COcredText m_ocredText;
	//CChipmonkCamera *m_pChipmonkCamera;
	int m_nBusyBeepCount;
	//CChipmonkAppView *m_pView;
	COSBase *m_pOS;
public:
	typedef enum { eIdle = 0, ePreprocessing, eZonning, eInitOcring, eOcring, eReadingText} EProcessingState;
private:
	EProcessingState m_eProcessingState;

public:

	CChipMonkCoordinator();
	
	~CChipMonkCoordinator();
	
	BOOL Init(COSBase *pOS);//CChipmonkAppView *pView);
	BOOL LoadRawImage(const char *sRawImageFileName);
	BOOL ProcessImage();
	BOOL PlayText(const WCHAR *pText);
	//BOOL NssTtsPlayText(const char *pText);
	BOOL PreprocessImage(vector<int> & vAngles,
						UCHAR** pp1bppBoW, UCHAR** pp1bppWoB, 
						int & nATThreshold, int & nBverWThreshold, int & nOcrThreshold);
	void OnTimer();
	void OnOpenImage(const char* sImageFileName);
	void SetSpeakingNewEvent();
	void OnSpeakingNew();
	void ResumeImageProcessThread();
	void SuspendImageProcessThread();
	void SetEvent(CEventBase *pEvent);
	void SetZonningDoneEvent();
	void SetOcrDoneEvent();
	void SetNextOcrChunkDoneEvent();
	void SetPageInfoReadyEvent();	
	void PreparePageInfo();
	BOOL OCRRawTextLines();
	void  InitalizeOcrProcessingParams(COCR* ocr, CRawLines& lines, 
									const ImgRotationInfo& iri, const UCHAR* p8bppImg, int nThreshold,
									bool bForceSingleColumn);
	EPageOrientation  GetPageOrientation();
	EPageOrientation GetPageOrientation(COcrProcessingParams & ocrProcessingParams);
	EPageOrientation GetParagraphOrientation(int nParagraph, COcrProcessingParams & ocrProcessingParams);
	void GetText(wstring & sText,CRawLines *pRawLines = NULL);
	void GetText(wstring &sText, CRawLines *pRawLines, BOOL bUpsideDown);
	bool OcrNextChunk(COcrProcessingParams & ocrProcessingParams, int nParagraph, int nLineIndex, 
						int nOptChunkLines = 2, int nMinChunkLines = 1);
	BOOL GetRawLineText(CRawLine & rawLine, COcrTextPage& textPage, 
			COcrProcessingParams & ocrProcessingParams);
	void AddText(wstring sText, int nParagraph);
	//BOOL StartCamera();
	void ProcessStillCameraImage();
	//BOOL TakeImage();
	//void CancelCameraFocus();
	EProcessingState GetState() const;
	void CancelProcess();
	//CSoundCoordinator *GetSoundCoordinator();
	//void DrawBitmap(CFbsBitmap* pBitmap);
	void DisplayText(const WCHAR *pText);
};
#endif // __CHIPMONK_COORDINATOR_H__
