//this file is part of notepad++
//Copyright (C)2003 Don HO ( donho@altern.org )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

/*
// list MACOCS30 //
const char commandM30[] = "CALLFUNCTION CHECKSUM END ENTRANT GOTO LOCKREADER IF POWEROFF POWERON "
                          "SET SORTANT STATUSPERSO SWITCH UNLOCKREADER";

const char macroM30[]  = "ChangeCode CipherData CreateBinary CreateBinaryCipher CreateDirectoryV1 "
                         "CreateDirectoryV3 CreateFile CreateFilePlein00 CreateFilePleinFF CreateFileSMS "
                         "CreateFileVide CreateRecord CreateRecordCipher Delete DeleteFile DisableChv "
                         "EnableChv Envelope Fetch GenerateKey GetData GetResponse GetStatus Increase "
                         "Install InstallLoad Invalidate KeyCalculus LastLoad Load LockRecord "
                         "MultiCreateBinary MultiCreateRecord MultiLoad MultiUpdateBinary MultiUpdateRecord "
                         "PutData ReadBinary ReadDirectory ReadRecord Rehabilitate RsaInitKeyList RsaAddKeyToList "
                         "RsaSendRequest RsaGetPublicKeyVal RsaGetKeyModulusHash RsaGetAndCutPrivateKeyValue "
                         "RsaWritePrivateKey SetLock SetStatus SelectDF SelectEF Set Sleep StatusCard UpdateBinary "
                         "UpdateBinary2 UpdateRecord UnblockCode VerifyCode VerifyDisabled";

const char commandLabel[] = "ARG1 ARG2 CMD_ISO COMP CIBLE DATA DEST ELSE ETAT FREQ "
                            "IDFUNC LABEL OP PTS SECURITE SOURCE STATUS THEN";

const char macroLabel[] = "Blck Buf Cible CipherKey Cle ClearLen Code Compl CutLen "
                          "Data Dest Diversif DummyBuf ExponentVal FirstRec HiOffset "
                          "ID IndexInList KeyNumber Lg LgCre LgRec LgUp LoOffset "
                          "MaxLg Mode ModSel ModulusLen Nb NbRec NoRec Occur Offset Op "
                          "P1 P3 RBKey RBSize RecNum Source State Subset Target Tag1 Tag2 Type ULg";

// list Pcom //
const char pcomNativeCmd[] = "DEFINE POWER_ON POWER_OFF STEP_ON STEP_OFF LIST_ON LIST_OFF SET_BUFFER INSERT EJECT "
							 "ERROR_BEEP_ON ERROR_BEEP_OFF END_BEEP_ON END_BEEP_ON PATH READER CALL EXECUTE EXIT "
							 "BEGIN_LOOP LOOP INCREASE_BUFFER DECREASE_BUFFER APPEND_BUFFER UNDEFINE ALLUNDEFINE "
							 "IFDEF ELSE ENDIF IFNDEF LOAD UNLOAD";

const char pcomExtCmd[] = "SET_DATA DISPLAY COMPARE SET_RSA_LEN SET_RSA_NUB SET_RSA_NBITS COMPUTE_RSA_KEYS "
						  "GET_RSA_PUBLIC_KEYS GET_RSA_SIGNATURE VERIFY_RSA_SIGNATURE SHA SET_PRF_SECRET "
						  "SET_PRF_LABEL_SEED PRF SET_PRF_SECRET SET_RSA_PUBLIC_KEYS SET_RADM1 SET_RADM2";

const char pcomDefaultBuf[] = "G H I J K L M N O Q R W";
*/

#include "Parameters.h"
#include <windows.h>


NppParameters * NppParameters::_pSelf = new NppParameters;

NppParameters::NppParameters():_nbLang(0), _nbFile(0), _pXmlDoc(NULL)
{
	// set the default values
	_toolBarStatus = TB_LARGE;
    _statusBarShow = true;
	_tabStatus = TAB_DRAWTOPBAR | TAB_DRAWINACTIVETAB | TAB_DRAGNDROP;
    _splitterPos = POS_HORIZOTAL;
    _userDefineDlgStatus = UDD_DOCKED;

	_svp[0]._lineNumberMarginShow = true;
	_svp[0]._bookMarkMarginShow = true;
	_svp[0]._folderMarginShow = true;
	_svp[0]._folderStyle = FOLDER_STYLE_BOX;
	_svp[0]._indentGuideLineShow = true;
	_svp[0]._invisibleCharsShow = false;

	_svp[1] = _svp[0];

	for (int i = 0 ; i < NB_LANG ; _langList[i] = NULL, i++);

	const int MAX_LEN = 256;
	char fullPathName[MAX_LEN];
	::GetModuleFileName(NULL, fullPathName, sizeof(fullPathName));
	PathRemoveFileSpec(fullPathName);
	PathAppend(fullPathName, "NotepadPlus.xml");

	_pXmlDoc = new TiXmlDocument(fullPathName);
	bool loadOkay = _pXmlDoc->LoadFile();
	if (!loadOkay)
	{
		::MessageBox(NULL, "Load NotepadPlus.xml failed!", "Configurator",MB_OK);
		delete _pXmlDoc;
		_pXmlDoc = NULL;
		return;
	}
	getAllParametersFromXmlTree();
}

void NppParameters::getAllParametersFromXmlTree()
{
	if (!_pXmlDoc)
		return;

	TiXmlNode *root = _pXmlDoc->FirstChild("NotepadPlus");

	// GUI
	TiXmlNode *node = root->FirstChildElement("GUIConfigs");
	TiXmlElement *element = node->ToElement();

	for (TiXmlNode *childNode = node->FirstChildElement("GUIConfig");
		childNode ;
		childNode = childNode->NextSibling("GUIConfig") )
	{
		feedGUIParameters(childNode);
	}

	// Keywords of language
	node = root->FirstChildElement("Languages");
	for (TiXmlNode *childNode = node->FirstChildElement("Language");
		childNode ;
		childNode = childNode->NextSibling("Language") )
	{
		feedKeyWordsParameters(childNode);
	}

	//History
	node = root->FirstChildElement("History");

	//Prendre toutes les allocation familliale de ses enfants
	feedFileListParameters(node);

	//Abondonner (ou plus radicalement, tuer) sa femme et ses enfants
	root->RemoveChild(node);

	//Trouver une jeune fille qui n'a pas d'enfant
	TiXmlElement HistoryNode("History");

	//se marrier avec cette jeune fille 
	root->InsertEndChild(HistoryNode);
}


void NppParameters::feedFileListParameters(TiXmlNode *node)
{
	if (_nbFile < NB_MAX_FILE)
	{
		TiXmlElement *element = node->ToElement();
		int maxNbFile;
		//element->Attribute("MaxNbFile", &maxNbFile);

		for (TiXmlNode *childNode = node->FirstChildElement("File");
			childNode ;
			childNode = childNode->NextSibling("File") )
		{
			_LRFileList[_nbFile] = new std::string((childNode->FirstChild())->Value());
			_nbFile++;
		}
	}
}

void NppParameters::writeHistory(const char *fullpath)
{
	TiXmlNode *historyNode = (_pXmlDoc->FirstChild("NotepadPlus"))->FirstChildElement("History");
	TiXmlElement recentFileNode("File");
	TiXmlText fileNameFullPath(fullpath);
	recentFileNode.InsertEndChild(fileNameFullPath);

	(historyNode->ToElement())->InsertEndChild(recentFileNode);
}

int NppParameters::getLangIDFromStr(const char *langName) const
{
	std::string str(langName);
	if (str == "c")
		return LANG_C;
	else if (str == "cpp")
		return LANG_CPP;
	else if (str == "java")
		return LANG_JAVA;
	else if (str == "rc")
		return LANG_RC;
	else if (str == "html")
		return LANG_HTML;
	else if (str == "javascript")
		return LANG_JS;
	else if (str == "php")
		return LANG_PHP;
	else if (str == "macocs30")
		return LANG_M30;
	else if (str == "pcom")
		return LANG_PCOM;
	else
		return LANG_UNKNOWN;
}

int NppParameters::getIndexFromStr(const char *indexName) const
{
	std::string str(indexName);

	if (str == "instre1")
		return LANG_INDEX_INSTR;
	else if (str == "instre2")
		return LANG_INDEX_INSTR2;
	else if (str == "type1")
		return LANG_INDEX_TYPE;
	else if (str == "type2")
		return LANG_INDEX_TYPE2;
	else
		return -1;
}
 
void NppParameters::feedKeyWordsParameters(TiXmlNode *node)
{
	if (_nbLang < NB_LANG)
	{
		TiXmlElement *element = node->ToElement();
		const char *name = element->Attribute("name");

		_langList[_nbLang] = new Lang(getLangIDFromStr(name));

		for (TiXmlNode *childNode = node->FirstChildElement("Keywords");
			childNode ;
			childNode = childNode->NextSibling("Keywords") )
		{
			const char *indexName = (childNode->ToElement())->Attribute("name");
			const char *keyWords = (childNode->FirstChild())->Value();
			_langList[_nbLang]->setWords(keyWords, getIndexFromStr(indexName));
		}
		_nbLang++;
	}
}

void NppParameters::feedGUIParameters(TiXmlNode *node)
{
	TiXmlElement *element = node->ToElement();
	std::string name = element->Attribute("name");

	std::string valueString;

	if (name == "ToolBar")
	{
		valueString = (node->FirstChild())->Value();
		if (valueString == "hide")
			_toolBarStatus = TB_HIDE;
		else if (valueString == "small")
			_toolBarStatus = TB_SMALL;
		else if (valueString == "large")
			_toolBarStatus = TB_LARGE;
	} 
	else if (name == "StatusBar")
	{
		valueString = (node->FirstChild())->Value();
		if (valueString == "hide")
			_statusBarShow = false;
		else if (valueString == "show")
			_statusBarShow = true;
	}
	else if (name == "TabBar")
	{
		bool isFailed = false;
		int oldValue = _tabStatus;

		valueString = element->Attribute("dragAndDrop");
		if (valueString == "yes")
			_tabStatus = TAB_DRAGNDROP;
		else if (valueString == "no")
			_tabStatus = 0;
		else
			isFailed = true;

		valueString = element->Attribute("drawTopBar");
		if (valueString == "yes")
			_tabStatus |= TAB_DRAWTOPBAR;
		else if (valueString == "no")
			_tabStatus |= 0;
		else
			isFailed = true;

		valueString = element->Attribute("drawInactiveTab");
		if (valueString == "yes")
			_tabStatus |= TAB_DRAWINACTIVETAB;
		else if (valueString == "no")
			_tabStatus |= 0;
		else
			isFailed = true;

		if (isFailed)
			_tabStatus = oldValue;
	}

	else if (name == "ScintillaViewsSplitter")
	{
		valueString = (node->FirstChild())->Value();
		if (valueString == "vertical")
			_splitterPos = POS_VERTICAL;
		else if (valueString == "horizontal")
			_splitterPos = POS_HORIZOTAL;
	}
	else if (name == "UserDefineDlg")
	{
		bool isFailed = false;
		int oldValue = _userDefineDlgStatus;

		valueString = (node->FirstChild())->Value();
		if (valueString == "hide")
			_userDefineDlgStatus = 0;
		else if (valueString == "show")
			_userDefineDlgStatus = UDD_SHOW;
		else 
			isFailed = true;

		std::string attribStr = element->Attribute("position");
		if (attribStr == "docked")
			_userDefineDlgStatus |= UDD_DOCKED;
		else if (attribStr == "undocked")
			_userDefineDlgStatus |= 0;
		else 
			isFailed = true;

		if (isFailed)
			_userDefineDlgStatus = oldValue;
	}
}

void NppParameters::getWordList(std::string & wordList, int langID, int typeIndex) const
{
	Lang *pLang = getLangFromID(langID);
	if (!pLang)
	{
		::MessageBox(NULL, "langID n'existe pas! There will be no effect", "From getWordList()", MB_OK);
		return;
	}
    const char *str = pLang->getWords(typeIndex);
    if (!str)
    {
		::MessageBox(NULL, "There's no string in the index! no effect", "From getWordList()", MB_OK);
		return;
	}
	wordList = str;
}

void NppParameters::addWordList(std::string & wordList, int langID, int typeIndex) const
{
	Lang *pLang = getLangFromID(langID);
	if (!pLang)
	{
		::MessageBox(NULL, "langID n'existe pas! There will be no effect", "From addWordList()", MB_OK);
		return;
	}
    const char *str = pLang->getWords(typeIndex);
    if (!str)
    {
		::MessageBox(NULL, "There's no string in the index! no effect", "From addWordList()", MB_OK);
		return;
	}
    wordList.append(" ");
    wordList.append(str);
}
