#include "EnglishDictionary.h"

CEnglishDictionary::~CEnglishDictionary() {
}

void CEnglishDictionary::ConvertToLower(WCHAR &c)const{
	if(c >= 'A' && c <= 'Z'){
		c += ('a' - 'A');
	}
}

WCHAR CEnglishDictionary::ToLower(WCHAR c)const{
	if(c >= 'A' && c <= 'Z'){
		return c + ('a' - 'A');
	}
	if(c >= 'a' && c <= 'z'){
		return c;
	}
	if(c == '\''){
		return '\'';
	}
	if(c >= '0' && c <= '9'){
		return c;
	}
	return 0;
}

int CEnglishDictionary::GettLetterIndx(WCHAR c) const {
	int nIndx = c - 'a';
	if(nIndx >= 0){
		return nIndx;
	}
	return c - 'A';
}

CEnglishDictionary::CEnglishDictionary(void)
{
	m_nNUM_OF_LETTERS = 26;
	m_pDict = NULL;
	m_pWords = NULL;
	m_pIndx = new IndxEntry[m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS];
	m_pTwoLetWords = new BOOL[m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS];
	memset(m_pTwoLetWords, 0, m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS * sizeof(BOOL));
	m_pOneLetWords = new BOOL[m_nNUM_OF_LETTERS];
	memset(m_pOneLetWords, 0, m_nNUM_OF_LETTERS * sizeof(BOOL));
	AddToShortWords((WCHAR*)L"I", 1);
	AddToShortWords((WCHAR*)L"a", 1);	
	m_nLangIndx = RTK_ENGLISH;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

BOOL CEnglishDictionary::Init(const char *installDir)
{
	m_vRepalcement.resize(3);
/*
	m_vRepalcement[0].first = ")"; m_vRepalcement[0].second.push_back("j");  m_vRepalcement[0].second.push_back("i"); m_vRepalcement[0].second.push_back("l");
	m_vRepalcement[1].first = "("; m_vRepalcement[1].second.push_back("c");  m_vRepalcement[1].second.push_back("i"); m_vRepalcement[1].second.push_back("l");
	m_vRepalcement[2].first = "|"; m_vRepalcement[2].second.push_back("i");  m_vRepalcement[2].second.push_back("l");
	m_vRepalcement[3].first = "l"; m_vRepalcement[3].second.push_back("i");
	m_vRepalcement[4].first = "i"; m_vRepalcement[4].second.push_back("l");
	m_vRepalcement[5].first = "I"; m_vRepalcement[5].second.push_back("l");
	m_vRepalcement[6].first = ";"; m_vRepalcement[6].second.push_back("i");
	m_vRepalcement[7].first = ";"; m_vRepalcement[7].second.push_back("i");
	m_vRepalcement[8].first = "(x)"; m_vRepalcement[8].second.push_back("oo");
	m_vRepalcement[9].first = "(x"; m_vRepalcement[9].second.push_back("oo");
	m_vRepalcement[10].first = "x)"; m_vRepalcement[10].second.push_back("oo");
	m_vRepalcement[11].first = "ci"; m_vRepalcement[11].second.push_back("d");
	m_vRepalcement[12].first = "cj"; m_vRepalcement[12].second.push_back("d");
	m_vRepalcement[13].first = "d"; m_vRepalcement[13].second.push_back("ci"); m_vRepalcement[13].second.push_back("cj");
*/
	m_vRepalcement[0].first = L"/"; m_vRepalcement[0].second.push_back(L"i");
	m_vRepalcement[1].first = L"ll"; m_vRepalcement[1].second.push_back(L"Li");  m_vRepalcement[1].second.push_back(L"H");
	m_vRepalcement[2].first = L"li"; m_vRepalcement[2].second.push_back(L"H");

	/////////////////////////
	string fileName(installDir);
	fileName += "\\words.txt";
	FILE *fp = fopen(fileName.c_str(), "rb");
	if (!fp)
		return FALSE;

	fseek(fp, 0, SEEK_END);
	int nSize = ftell(fp);
	int nChars = nSize/sizeof(WCHAR) - 1;
	m_pDict = new WCHAR[nChars + 1];
	DWORD dwRead = 0;
	fseek(fp, 0, SEEK_SET);
	fread(m_pDict, 1, sizeof(WCHAR), fp);
	fread(m_pDict, 1, nSize - sizeof(WCHAR), fp);
	fclose(fp);

	m_pDict[nChars] = '#';

	for(WCHAR *pD = m_pDict, *pDend = m_pDict + nChars; pD < pDend; ++pD) {
		ConvertToLower(*pD);
	}

	int nWords = CountWords(m_pDict, nChars);
	m_pWords = new PWCHAR[nWords];

	WCHAR *pCurrWord = m_pDict;
	WCHAR **pWords = m_pWords;
	IndxEntry *pIndx = m_pIndx;
	nWords = 0;
	int nLength;
	WCHAR pFirst3Letters[3];
	for(IndxEntry *pEnd = pIndx + m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS * m_nNUM_OF_LETTERS; pIndx < pEnd; ++pIndx){
		pIndx->m_nFirst = pIndx->m_nLast = -1;
	}
	pIndx = m_pIndx;
	for(int i=0; i<m_nNUM_OF_LETTERS; ++i){
		for(int j=0; j<m_nNUM_OF_LETTERS; ++j){
			for(int k=0; k<m_nNUM_OF_LETTERS; ++k, ++pIndx){
				while((nLength = WordLength(pCurrWord)) < 3){
					AddToShortWords(pCurrWord, nLength);
					pCurrWord = GetNextWord(pCurrWord);
				}
				pIndx->m_nFirst = -1;
				while(pCurrWord){
					GetFirst3Letters(pCurrWord, pFirst3Letters);
					if(GettLetterIndx(pFirst3Letters[0]) !=  i 
					|| GettLetterIndx(pFirst3Letters[1]) !=  j
					|| GettLetterIndx(pFirst3Letters[2]) !=  k){
						break;
					}
					if(pIndx->m_nFirst == -1){
						pIndx->m_nFirst = nWords;
					}
					pIndx->m_nLast = nWords;
					*pWords++ = pCurrWord;
					if((pCurrWord = GetNextWord(pCurrWord)) == NULL){
						return TRUE;
					}
					++nWords;
				}
			}
		}
	}

	return TRUE;
}

BOOL CEnglishDictionary::InWordValidCharacter(WCHAR c) const {
	return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c == '\'') || (c==':') || (c=='-') || (c=='—') || (c=='.');
}

BOOL CEnglishDictionary::ValidCharacter(WCHAR c) const {
	return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')
		|| c=='/' || c=='\\' || c=='~' || c=='\'' || c=='\"' || c=='`' || c=='&' || c=='%' || c== '@' || c=='#'
		|| c==' ' || c=='-' || c == '—' || c=='$' || c=='.' || c==',' || c=='\n' || c=='\r' || c==':' || c=='?' || c==';' || c=='(' || c==')'
		|| c=='•' || c=='^' || c=='>' || c=='<' || c=='!' || c=='«' || c=='»';
}

BOOL CEnglishDictionary::SpellCheck(wstring & sWord, BOOL bSpeaking) {
	if(IsANumber(sWord)){
		return TRUE;
	}
	if(LookUp((WCHAR*)sWord.c_str())){
		return TRUE;
	}

	if(sWord == L"<") {
		sWord = L"less";
		return TRUE;
	}

	if(sWord[0] == L'<') {
		sWord = sWord.substr(1);
		return TRUE;
	}

	if(sWord == L"ff") {
		sWord = L"if";
		return TRUE;
	}

	if( sWord == L"m" ) {
		sWord = L"in";
		return TRUE;
	}

	if( sWord == L"L" ) {
		sWord = L"I";
		return TRUE;
	}

	if(bSpeaking){
		if( (sWord==L"ABISEE") || (sWord==L"ABISee") || (sWord==L"abisee") || (sWord==L"ABISee,") ) {
			sWord = L"A B I See";
			return TRUE;
		}

		if(sWord==L"www.abisee.com")  {
			sWord = L"www.A B I See.com";
			return TRUE;
		}
	}

	if( (sWord.length() > 4) && (sWord.substr(sWord.length() - 3, 3) == L"lng") ) {
		sWord[sWord.length() - 3] = 'i'; 
		if(LookUp((WCHAR*)sWord.c_str())){
			return TRUE;
		}
	}

	int i;
	vector<pair<int, int> > vPositions;
	for(i = 0; i <  m_vRepalcement.size(); ++i){
		int nPos;
		if((nPos = sWord.find(m_vRepalcement[i].first)) != string::npos){
			vPositions.push_back(pair<int, int> (nPos, i));
		}
	}

	//if(vPositions.size()  < 1 || vPositions.size() > 2){
	//	return FALSE;
	//}

	if(vPositions.size() == 1){
		int nPos = vPositions.front().first;
		int nIndx = vPositions.front().second;
		int nLn = m_vRepalcement[nIndx].first.length();
		for(vector<wstring>::const_iterator j = m_vRepalcement[nIndx].second.begin(); j != m_vRepalcement[nIndx].second.end(); ++j){
			wstring sCandidate = sWord.substr(0, nPos) + *j + sWord.substr(nPos + nLn);
			if(LookUp((WCHAR*)sCandidate.c_str())) {
				sWord = sCandidate;
				return TRUE;
			}
		}
	}

	wstring sWrd;
	if(!sWord.empty()){
		if(ValidCharacter(sWord[0])){
			sWrd += sWord[0];
		}
		int nWrdLn = sWord.length();
		for(i = 1; i < nWrdLn - 1; ++i){
			if(InWordValidCharacter(sWord[i])){
				sWrd += sWord[i];
			}
		}
		if(nWrdLn > 1 && ValidCharacter(sWord[nWrdLn -1 ])){
			sWrd += sWord[sWord.length() - 1];
		}
		sWord.assign(sWrd);
	}
	TrimString(sWord);
	return FALSE;
}
