// TextPage.h: interface for the COcrTextPage class.
//
//////////////////////////////////////////////////////////////////////
#ifndef __TEXT_PAGE_H_
#define __TEXT_PAGE_H_

#include "Dictionary.h"
#include <set>
#include <deque>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

//#define REGION_DEBUG
#define	INSERT_PAUSE

#define BOLD_FEATURE		1
#define ITALIC_FEATURE		2
#define HEADING_FEATURE		4
#define EMBEDDED_FEATURE	8
#define FLOATING_FEATURE	0x10
#define LOW_CONFIDENCE		0x20
#define PARTIALLY_OCRED		0x40
#define COMPLETELY_OCRED	0x80
#define FORCE_SINGLE		0x100
#define PARTIALY_NOISE		0x200
#define WHITE_ON_BLACK		0x400
#define DO_NOT_FILTER		0x800
#define NEW_LINE			0x1000

class COcrBasicTextRegion : public CRect, public vector<COcrBasicTextRegion *> {
	COcrBasicTextRegion *m_pParent;
protected:
	UINT m_flgFeatures;
public:
	COcrBasicTextRegion(CRect rect = CRect(0, 0, 0, 0), COcrBasicTextRegion *pParent = NULL);
	COcrBasicTextRegion(const COcrBasicTextRegion & btr);
		
	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const = 0;
	virtual ~COcrBasicTextRegion();

	COcrBasicTextRegion *GetParent();
	const COcrBasicTextRegion *GetParent()const;
	void SetParent(COcrBasicTextRegion *pParent);
	void SetTextFeature(UINT nFeature, bool bOn = true);
	bool GetTextFeature(UINT nFeature)const;
	void SetTextFeatures(UINT nFeatures);
	UINT GetTextFeatures()const;

	virtual BOOL GetText(wstring & sText) const;

	virtual BOOL GetTaggedText(wstring & sText) const;

	virtual void GetFilteredText(wstring & sText, Dictionary *pDict = NULL) const;

	virtual void clear();
	BOOL SaveToDisk(const char *sFileName)const;
	BOOL SaveTextToDisk(const char *sFileName)const;

	BOOL DumpToFile(FILE *pFile)const;

	virtual void Merge(COcrBasicTextRegion *pBtr);

	virtual COcrBasicTextRegion *Split(UINT nSplit);
	virtual void Linearize(vector<COcrBasicTextRegion *> & vLine);

	virtual UCHAR GetConfidence()const;

	BOOL Swap(int nPos1, int nPos2);
	virtual UINT size()const;
	virtual int GetHeight()const;
	virtual int GetMeanY()const;

	virtual UINT GetFeatures()const;

	virtual void OffsetRect(int x, int y);

	virtual void OffsetRect(CPoint p);

	virtual iterator erase(iterator i);
	
	const COcrBasicTextRegion *GetTheRootParent()const;

	void UpdateBoundBox(){
		SetRectEmpty();
		for(iterator i = begin(); i != end(); ++i){
			if(*i)UnionRect(*this, **i);
		}
	}

	virtual bool ProofText(const COcrBasicTextRegion & tr){
		CRect intrRect;
		if(!intrRect.IntersectRect(*this, tr)){
			return false;
		}
		bool bRet = false;
		for(iterator i = begin(); i != end(); ++i){
			for(const_iterator j = tr.begin(); j != tr.end();){
				if(*i && *j){
					if((*i)->ProofText(**j)){
						j = tr.begin();
						bRet = true;
					}
					else{
						++j;
					}
				}
			}
		}
		if(bRet){
			UpdateBoundBox();
		}
		return bRet;
	}

	virtual void Copy(const COcrBasicTextRegion *pBtr);

	//void *operator new(size_t s)const;
};

class COcrTextCharacter  : public COcrBasicTextRegion {
	WCHAR m_char;
	UCHAR m_confidence;
public:
	COcrTextCharacter(WCHAR c, CRect rect, COcrBasicTextRegion *pParent, 
		UCHAR confidence = 0, UINT nFeatures = 0); 
	virtual BOOL GetText(wstring & sText)const;
	inline WCHAR GetChar()const; 
	virtual inline UCHAR GetConfidence()const;
	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const;
	virtual void Linearize(vector<COcrBasicTextRegion *> & vLine);
	virtual UINT size()const;
	virtual int GetHeight()const;
	virtual UINT GetFeatures()const;
	virtual BOOL GetTaggedText(wstring & sText)const;
	virtual void GetFilteredText(wstring & sText, Dictionary *pDict = NULL)const;
	virtual bool ProofText(const COcrBasicTextRegion & tr){
		const COcrTextCharacter & tc = (const COcrTextCharacter &)tr;
		CRect intrRect;
		if(!intrRect.IntersectRect(*this, tc)){
			return false;
		}
		int nIntArea = intrRect.Width() * intrRect.Height();
		int nMaxArea = max(Width() * Height(), tc.Width() * tc.Height());
		if(nIntArea * 3 >= nMaxArea){
			if(tc.m_confidence < m_confidence){
				m_char = tc.m_char;
				m_confidence = tc.m_confidence;
				CopyRect(tc);
				return true;
			}
		}
		return false;
	}

};

struct ProofLineTextRef{ 
	int m_nPos;  
	COcrTextCharacter *m_pTc; 
	bool m_bStart;
	bool operator < (const ProofLineTextRef & pltr)const{return  m_nPos < pltr.m_nPos;}
	ProofLineTextRef(): m_nPos(-1), m_pTc(NULL), m_bStart(true) {}
	ProofLineTextRef(COcrTextCharacter *pTc, bool bStart): m_nPos(bStart ? pTc->left : pTc->right), m_pTc(pTc), m_bStart(bStart) {}
	ProofLineTextRef(const ProofLineTextRef & pltr): m_nPos(pltr.m_nPos), m_pTc(pltr.m_pTc), m_bStart(pltr.m_bStart) {}
}; 

class COcrTextWord : public COcrBasicTextRegion {
public:
	COcrTextWord(CRect rect, COcrBasicTextRegion *pParent);
	void AddTextCharacter(WCHAR c, CRect rect, UCHAR confidence = 0, UINT nFeatures = 0);
	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const;
	virtual COcrBasicTextRegion *Split(UINT nSplit);
	virtual void GetFilteredText(wstring & sText, Dictionary *pDict = NULL) const;
};

class COcrTextLine : public COcrBasicTextRegion {
public:
	COcrTextLine(CRect rect, COcrBasicTextRegion *pParent);
	void AddTextWord(CRect rect);
	void AddTextCharacterToTheLastTextWord(WCHAR c, CRect rect, UCHAR confidence = 0, UINT nFeatures = 0);
	
	virtual BOOL GetText(wstring & sText) const;

	virtual BOOL GetTaggedText(wstring & sText) const;
	virtual void GetFilteredText(wstring & sText, Dictionary *pDict = NULL) const;
	virtual void GetFilteredText(wstring & sText, Dictionary *pDict, vector<int> *pWords) const;
	virtual void clear();
	BOOL MarkLowConfidenceParts(int nConfThreshold, int nWindow);
	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const;
	virtual COcrBasicTextRegion *Split(UINT nSplit);
	void AddToLineTextRefSet(set<ProofLineTextRef> & setPLTR)const{
		for(const_iterator i = begin(); i != end(); ++i){
			if(*i){//word
				for(const_iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
					if(*j){//character
						setPLTR.insert(ProofLineTextRef((COcrTextCharacter*)*j, true));
						setPLTR.insert(ProofLineTextRef((COcrTextCharacter*)*j, false));
					}
				}
			}
		}
	}


	virtual bool ProofText(const COcrBasicTextRegion & tr){
		set<ProofLineTextRef> setPLTR;
		AddToLineTextRefSet(setPLTR);
		((const COcrTextLine &)tr).AddToLineTextRefSet(setPLTR);
		set<COcrTextCharacter*> setCurrenChars;
		for(set<ProofLineTextRef>::iterator i = setPLTR.begin(); i != setPLTR.end(); ++i){
			if(i->m_bStart){
				setCurrenChars.insert(i->m_pTc);
			}
			else{
				setCurrenChars.erase(i->m_pTc);
			}

		}
		return true;
	}

	virtual void Copy(const COcrBasicTextRegion *pOtl);
};

class COcrTextRegion : public COcrBasicTextRegion{
protected:
	wstring m_history;
	set<const COcrTextRegion*> m_xOverlapingRegions;
	int m_nAlreadyOcredLines;
public:
	COcrTextRegion(CRect rect, COcrBasicTextRegion *pParent);
	void AddTextLine(CRect rect);
	void AddTextWordToTheLastTextLine(CRect rect);
	void AddTextCharacterToTheLastTextWord(WCHAR c, CRect rect, UCHAR confidence = 0, UINT nFeatures = 0);
	void SetHistory(wstring text);
	virtual wstring GetHistory();
	virtual int GetLineSpacing(unsigned int n);
	bool CheckText(COcrBasicTextRegion *pTr, Dictionary* pDict)const;
	void SetLineConfidences(Dictionary* pDict);
	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const;
	virtual COcrBasicTextRegion *Split(UINT nSplit);
	void AddOverlapingRegion(COcrTextRegion* pRegion);
	virtual BOOL GetText(wstring & sText) const;

	bool CheckIfOverlaped(int startTop, int startBottom, const COcrTextRegion *pEndRegion, set<const COcrTextRegion*> & alreadyChecked)const;
	bool IsVerticalySeparated(const COcrTextRegion *pRegion)const;

	bool operator < (const COcrTextRegion & tr)const;
	void RecalBoundBox();
	int GetNextNotOcredLineIndx()const;
	void SetNextNotOcredLineIndx(int nNextNotOcredLineIndx);
};

inline CRect RotateRect180(CRect rect, int nWidth, int nHeight);

class COcrTextPage : public COcrBasicTextRegion{
	vector<COcrBasicTextRegion *> m_vLine;
public:
	COcrTextPage(CRect rect = CRect(0, 0, 0, 0), COcrBasicTextRegion *pParent = NULL);

	virtual COcrBasicTextRegion* New(COcrBasicTextRegion *pParent)const;
	virtual COcrBasicTextRegion *Split(UINT nSplit);
	void AddRegion(CRect rect);
	void AddLineToLastRegion(CRect rect);
	void AddWordToLastLine(CRect rect);
	void AddCharacterToTheLastWord(WCHAR c, CRect rect, UCHAR confidence = 0, UINT nFeatures = 0);
	virtual BOOL GetText(wstring & sText) const;
	BOOL GetText(wstring & wsText);
	void Add(const COcrTextPage & textPage);
	
	COcrBasicTextRegion *GetCharacterObject(int nPos);

	void SplitRegions();

	void SplitRegionsByHeight1();
	void SplitRegionsByHeight2(int multiplier);

	void SplitRegionsBySpacing(int multiplier);

	void SplitRegionsByWordCount(UINT maxWordsPerLineTimes2, UINT maxLines);

	iterator SplitRegion(COcrBasicTextRegion* pBtr, UINT nSplit, UINT textFeature, wstring historyText);

	int GetTaggedText(wstring& sText, UINT nBegin = 0, const_iterator *piend = NULL, 
		bool bAppendTag = false);

	void GetFilteredText(wstring& sText, UINT nBegin = 0, const_iterator *piend = NULL, Dictionary *pDict = NULL);
	void GetFilteredText(wstring& sText, UINT nBegin, const_iterator *piend, 
		Dictionary *pDict, vector<int> *pWords);

	void SetLineConfidences(Dictionary* pDict = NULL);
	
	void AddFeatureToLastRegion(UINT nFeature);
	void SetBoundRectOfTheLastRegion(CRect rect);

	void Rotate180(int nImgWidth, int nImgHeight);
	
	void Reverse();

	void RecalBoundBoxes();
	iterator SubstSplitedRegion(iterator iregion, COcrTextPage &newRegions);

	void AddTextFeatureToRegions(UINT nFeature);

	BOOL GetText(UINT nFirst, UINT nLast, wstring & sText);
	void MergeNotEmpty(COcrBasicTextRegion *pBtr);
};

#endif // __TEXT_PAGE_H_

