#include "verb.h"

#include <iostream> //Xperimental -- for debug only

#include "utf8utf16.h"

#include "boost/regex.hpp"
#include "boost/algorithm/string/regex.hpp"


namespace VB
{

	std::vector<VerbRecord> VerbRecordArr;

	std::vector<VerbParamsTableRecord> VerbParamsTable;


	VerbRecord::VerbRecord()
		: canBePrefixed(false)
		, canBeNotPrefixed(false)
		, canBePerfect(false)
		, canBeImperfect(false)
	{

	}

	VerbRecord::VerbRecord(std::wstring line)
	{
		std::vector<std::wstring> lineArr;

		boost::split_regex(lineArr, line, boost::wregex(L"	"));

		infinitive = lineArr[1];

		canBePrefixed = lineArr[2] == L"1" ? true : false;
		canBeNotPrefixed = lineArr[3] == L"1" ? true : false;

		canBePerfect = lineArr[4] == L"1" ? true : false;
		canBeImperfect = lineArr[5] == L"1" ? true : false;

		for (int i = 0; i < 3; i++)
		{
			TranslationUnit translationUnit;

			translationUnit.meaning = lineArr[6 + i * 3];
			translationUnit.comment = lineArr[6 + i * 3 + 1];
			translationUnit.example = lineArr[6 + i * 3 + 2];

			if (translationUnit.meaning != L"")
			{
				translationUnitArr.push_back(translationUnit);
			}
		}

	}



	VerbParams WStringToVerbParams(std::wstring str)
	{
		if (str == L"VP_INFINITIVE")
		{
			return VP_INFINITIVE;
		}
		else if (str == L"VP_PAST_MALE_SINGULAR")
		{
			return VP_PAST_MALE_SINGULAR;
		}
		else if (str == L"VP_PAST_FEMALE_SINGULAR")
		{
			return VP_PAST_FEMALE_SINGULAR;
		}
		else if (str == L"VP_PAST_NEUTER_SINGULAR")
		{
			return VP_PAST_NEUTER_SINGULAR;
		}
		else if (str == L"VP_PAST_PLURAL")
		{
			return VP_PAST_PLURAL;
		}
		else if (str == L"VP_PRESENT_FIRSTPERSON_SINGULAR")
		{
			return VP_PRESENT_FIRSTPERSON_SINGULAR;
		}
		else if (str == L"VP_PRESENT_SECONDPERSON_SINGULAR")
		{
			return VP_PRESENT_SECONDPERSON_SINGULAR;
		}
		else if (str == L"VP_PRESENT_THIRDPERSON_SINGULAR")
		{
			return VP_PRESENT_THIRDPERSON_SINGULAR;
		}
		else if (str == L"VP_PRESENT_FIRSTPERSON_PLURAL")
		{
			return VP_PRESENT_FIRSTPERSON_PLURAL;
		}
		else if (str == L"VP_PRESENT_SECONDPERSON_PLURAL")
		{
			return VP_PRESENT_SECONDPERSON_PLURAL;
		}
		else if (str == L"VP_PRESENT_THIRDPERSON_PLURAL")
		{
			return VP_PRESENT_THIRDPERSON_PLURAL;
		}
		
		std::cout << "Error in WStringToVerbParams" << std::endl;
		return VP_INFINITIVE;
	}

	std::wstring VerbParamsToWString(VerbParams verbParams)
	{
		if (verbParams == VP_INFINITIVE)
		{
			return L"VP_INFINITIVE";
		}
		else if (verbParams == VP_PAST_MALE_SINGULAR)
		{
			return L"VP_PAST_MALE_SINGULAR";
		}
		else if (verbParams == VP_PAST_FEMALE_SINGULAR)
		{
			return L"VP_PAST_FEMALE_SINGULAR";
		}
		else if (verbParams == VP_PAST_NEUTER_SINGULAR)
		{
			return L"VP_PAST_NEUTER_SINGULAR";
		}
		else if (verbParams == VP_PAST_PLURAL)
		{
			return L"VP_PAST_PLURAL";
		}
		else if (verbParams == VP_PRESENT_FIRSTPERSON_SINGULAR)
		{
			return L"VP_PRESENT_FIRSTPERSON_SINGULAR";
		}
		else if (verbParams == VP_PRESENT_SECONDPERSON_SINGULAR)
		{
			return L"VP_PRESENT_SECONDPERSON_SINGULAR";
		}
		else if (verbParams == VP_PRESENT_THIRDPERSON_SINGULAR)
		{
			return L"VP_PRESENT_THIRDPERSON_SINGULAR";
		}
		else if (verbParams == VP_PRESENT_FIRSTPERSON_PLURAL)
		{
			return L"VP_PRESENT_FIRSTPERSON_PLURAL";
		}
		else if (verbParams == VP_PRESENT_SECONDPERSON_PLURAL)
		{
			return L"VP_PRESENT_SECONDPERSON_PLURAL";
		}
		else if (verbParams == VP_PRESENT_THIRDPERSON_PLURAL)
		{
			return L"VP_PRESENT_THIRDPERSON_PLURAL";
		}

		std::cout << "Error in VerbParamsToWString" << std::endl;
		return L"";
	}

	VerbConjunction WStringToVerbConjunction(std::wstring str)
	{
		if (str == L"VC_FIRST_ET")
		{
			return VC_FIRST_ET;
		}
		else if (str == L"VC_FIRST_AT")
		{
			return VC_FIRST_AT;
		}
		else if (str == L"VC_FIRST_OT")
		{
			return VC_FIRST_OT;
		}
		else if (str == L"VC_FIRST_IT")
		{
			return VC_FIRST_IT;
		}
		else if (str == L"VC_FIRST_YT")
		{
			return VC_FIRST_YT;
		}
		else if (str == L"VC_FIRST_YAT")
		{
			return VC_FIRST_YAT;
		}
		else if (str == L"VC_SECOND_IT")
		{
			return VC_SECOND_IT;
		}
		else if (str == L"VC_SECOND_ET")
		{
			return VC_SECOND_ET;
		}
		else if (str == L"VC_SECOND_AT")
		{
			return VC_SECOND_AT;
		}


		std::cout << "Error in WStringToVerbConjunction" << std::endl;
		return VC_FIRST_ET;
	}

	bool VerbIsInDictionary(std::wstring verbInfinitive)
	{
		for (auto& verb : VerbRecordArr)
		{
			if (verb.infinitive == verbInfinitive)
			{
				return true;
			}
		}

		return false;
	}

	VerbRecord GetVerbRecordFromDictionary(std::wstring verbInfinitive)
	{
		for (auto& verb : VerbRecordArr)
		{
			if (verb.infinitive == verbInfinitive)
			{
				return verb;
			}
		}

		std::cout << "Error in GetVerbRecordFromDictionary" << std::endl;
		return VerbRecord();
	}

	std::wstring cutSelfEndingIfPossible(std::wstring& verb)
	{
		if (verb.substr(verb.size() - 2, 2) == L"ся")
		{
			verb.erase(verb.size() - 2, 2);
			return L"ся";
		}
		if (verb.substr(verb.size() - 2, 2) == L"сь")
		{
			verb.erase(verb.size() - 2, 2);
			return L"сь";
		}

		return L"";
	}

	std::vector<std::wstring> GetAllVerbEndingArr()
	{
		std::vector<std::wstring> result;
		result.push_back(L"еть");
		result.push_back(L"ать");
		result.push_back(L"оть");
		result.push_back(L"ить");
		result.push_back(L"уть");
		result.push_back(L"ять");
		result.push_back(L"ел");
		result.push_back(L"ал");
		result.push_back(L"ол");
		result.push_back(L"ил");
		result.push_back(L"ул");
		result.push_back(L"ял");
		result.push_back(L"ела");
		result.push_back(L"ала");
		result.push_back(L"ола");
		result.push_back(L"ила");
		result.push_back(L"ула");
		result.push_back(L"яла");
		result.push_back(L"ело");
		result.push_back(L"ало");
		result.push_back(L"оло");
		result.push_back(L"ило");
		result.push_back(L"уло");
		result.push_back(L"яло");
		result.push_back(L"ели");
		result.push_back(L"али");
		result.push_back(L"оли");
		result.push_back(L"или");
		result.push_back(L"ули");
		result.push_back(L"яли");
		result.push_back(L"ею");
		result.push_back(L"аю");
		result.push_back(L"ю");
		result.push_back(L"яю");
		result.push_back(L"у");
		result.push_back(L"еешь");
		result.push_back(L"аешь");
		result.push_back(L"ешь");
		result.push_back(L"яешь");
		result.push_back(L"ишь");
		result.push_back(L"еет");
		result.push_back(L"ает");
		result.push_back(L"ет");
		result.push_back(L"яет");
		result.push_back(L"ит");
		result.push_back(L"еем");
		result.push_back(L"аем");
		result.push_back(L"ем");
		result.push_back(L"яем");
		result.push_back(L"им");
		result.push_back(L"еете");
		result.push_back(L"аете");
		result.push_back(L"ете");
		result.push_back(L"яете");
		result.push_back(L"ите");
		result.push_back(L"еют");
		result.push_back(L"ают");
		result.push_back(L"ют");
		result.push_back(L"ут");
		result.push_back(L"яют");
		result.push_back(L"ят");


		return result;
	}

	std::set<VerbEndingDivision> getPossibleVerbEndingDivisionSet(std::wstring verb)
	{
		std::set<VerbEndingDivision> result;

		auto allVerbEndingArr = GetAllVerbEndingArr();

		for (auto ending : allVerbEndingArr)
		{
			if (boost::ends_with(verb, ending))
			{
				std::wstring nounBase = boost::replace_last_copy(verb, ending, "");

				result.insert({ nounBase, ending });
			}
		}

		return result;
	}

	std::set<std::pair<VerbParams, VerbConjunction>> getAllPossibleVerbParamsAndConjunctions(std::wstring ending)
	{
		std::set<std::pair<VerbParams, VerbConjunction>> result;

		for (auto& vTableRecord : VerbParamsTable)
		{
			for (int i = 0; i < VC_SIZE; i++)
			{
				if (vTableRecord.verbConjunctionTable[i].ending == ending)
				{
					result.insert({ vTableRecord.verbParams, vTableRecord.verbConjunctionTable[i].conjunction });
				}
			}

		}

		return result;
	}

	std::wstring GetVerbInfinitive(std::wstring modifiedBase, VerbConjunction verbConjunction)
	{
		return modifiedBase + VerbParamsTable[0].verbConjunctionTable[static_cast<int>(verbConjunction)].ending;
	}

	std::set<VerbStruct> RecognizeVerb(std::wstring verb)
	{
		std::set<VerbStruct> result;

		std::wstring selfEnding = cutSelfEndingIfPossible(verb);

		auto verbEndingDivisionArr = getPossibleVerbEndingDivisionSet(verb);

		for (auto verbEndingDivision : verbEndingDivisionArr)
		{
			std::wstring verbBase = verbEndingDivision.base;
			std::wstring verbEnding = verbEndingDivision.ending;
	
			std::wstring modifiedBase = (verbBase);
			std::wstring modifiedEnding = (verbEnding);

			std::set<std::pair<VerbParams, VerbConjunction>> possibleParams = getAllPossibleVerbParamsAndConjunctions(modifiedEnding);

			for (auto& verbParams : possibleParams)
			{

				std::wstring verbInfinitive = GetVerbInfinitive(modifiedBase, verbParams.second);

				if (VerbIsInDictionary(verbInfinitive))
				{
					VerbRecord vr = GetVerbRecordFromDictionary(verbInfinitive);

					VerbStruct vs;

					vs.verbParams = verbParams.first;

					vs.selfEnding = selfEnding;

					vs.verbRecord = vr;

					result.insert(vs);
				}
				
			}
		}

		return result;
	}


	void LoadVerbConjunctionTable()
	{

		VerbParamsTable.clear();

#ifdef _WIN32
		std::ifstream f("C:/Workplace/ChineseJournal/rudict/verb_conjunction.txt");

#else
		std::ifstream f("/home/devuser/workplace/rudict/verb_conjunction.txt");
#endif

		std::string line;
		std::wstring wline;

		if (f.is_open())
		{

			std::cout << "File found!" << std::endl;

			std::vector<VerbConjunctionTableRecord> currentVerbConjunctionTable;
			std::wstring currentVerbParams;
			std::wstring currentVerbConjunction;

			getline(f, line); //Skip one line

			while (getline(f, line))
			{
				std::vector<std::string> lineArr;

				boost::split_regex(lineArr, line, boost::regex("	"));

				if (lineArr[0] != "")
				{
					if (currentVerbParams == L"")
					{
						currentVerbParams = string_to_wstring(lineArr[0]);
					}
					else
					{
						VerbParamsTable.push_back(VerbParamsTableRecord{ WStringToVerbParams(currentVerbParams), currentVerbConjunctionTable });

						currentVerbParams = string_to_wstring(lineArr[0]);

						currentVerbConjunctionTable.clear();
					}

				}

				if (lineArr[1] != "")
				{
					currentVerbConjunction = string_to_wstring(lineArr[1]);
				}

				std::wstring ending = string_to_wstring(lineArr[2]);

				//std::set<std::wstring> endingsSet;
				//boost::split_regex(endingsSet, ending, boost::regex(", "));

				currentVerbConjunctionTable.push_back({
					WStringToVerbConjunction(currentVerbConjunction),
					ending
				});

			}
			//Add last one
			if (currentVerbParams != L"")
			{
				VerbParamsTable.push_back(VerbParamsTableRecord{ WStringToVerbParams(currentVerbParams), currentVerbConjunctionTable });
			}

			f.close();
		}
		else
		{
			std::cout << "file not found!" << std::endl;
		}


	}



	void LoadFrequentWordSet()
	{


#ifdef _WIN32
		std::ifstream f("C:/Workplace/ChineseJournal/rudict/frequent_verbs_2000.txt");

#else
		std::ifstream f("/home/devuser/workplace/rudict/frequent_verbs_2000.txt");
#endif

		std::string line;
		std::wstring wline;

		if (f.is_open())
		{

			getline(f, line); //Skip one line

			std::cout << "File found!" << std::endl;
			while (getline(f, line))
			{

				wline = string_to_wstring(line);
				VerbRecord verbRecord(wline);

				VerbRecordArr.push_back(verbRecord);

			}
			f.close();
		}
		else
		{
			std::cout << "file not found!" << std::endl;
		}


	}

}