// http://akelpad.sourceforge.net/forum/viewtopic.php?p=8153#8153
// Description(1033): Works with users menu (menu autogenerated from parameter files). Script implemented as the library for using in other scripts.
// Description(1049): Библиотека функций для работы с пользовательскими параметризированными меню
// Version: 5.0 (2015.04.10)
// Author: VladSh
//
/// Getting the value selected in the user menu (getSelectedMenuItem function)
//
// Menu automatically generated from the parameter files.
// Settings are located in files <current script name>.param in the directory "[AkelPad]\AkelFiles\Plugs\Scripts\Params\"
//
/// Получение значения, выбранного в пользовательском меню (функция getSelectedMenuItem)
//
// Меню автоматически формируются из соответствующего скрипту файла параметров.
// Параметры размещается в файлах <имя запускаемого скрипта>.param в директории "[AkelPad]\AkelFiles\Plugs\Scripts\Params\"
//
// Имена параметров, передаваемых в аргументах вызывающих скриптов:
// 	-pExt - расширение файла параметров (если pFile не указан, то имя будет браться из имени запущенного скрипта); поддерживаются:
// 		• "txt"  - каждая строка файла = строка меню;
// 		• "ini"  - <надпись пункта меню> = <значение> (без уголков);
// 		• "json" - настройки в формате json с указанными именами шаблонов настроек (см. -pID)
// 	-pFile - имя файла параметров (с расширением), по которому будет формироваться меню; если не передано, то будет определено по имени запускаемого скрипта
// 	-pID - шаблон определённых настроек из json-файла
// 	-place - место экрана, где будет выведено меню, - значение для pPOS_PLACE (см. ниже) либо идентификатор кнопки тулбара, передавать который в виде -place="%m %i"
// 	-ignore1menu ([0]/1) - если в файле параметров одна строка и bIgnoreMenu = 1, тогда меню выводиться не будет
// 	-debug ([0]/1) - выводить расширенную информацию о возможных ошибках в панель Log-плагина

var hWndMain = AkelPad.GetMainWnd();
if (hWndMain) {
	if (! AkelPad.Include("ShowMenu.js")) WScript.Quit();
	var fso = new ActiveXObject('Scripting.FileSystemObject');
	var WshShell = new ActiveXObject('WScript.Shell');
	var pScriptName = WScript.ScriptName;
	var bIniExist = 0;
	var parser_exts = "txt, ini, json";
	var opts = {'pFile': AkelPad.GetArgValue('pFile', ""),
	            'pExt': AkelPad.GetArgValue('pExt', ""),
	            'pID': AkelPad.GetArgValue('pID', "")};
	var bIgnoreMenu = AkelPad.GetArgValue('ignore1menu', 0);
	var bDebug = AkelPad.GetArgValue('debug', false);
}

//Functions

function getSelectedMenuItem(pPOS_PLACE, bReturnStructure)
//Параметры:
//	pPOS_PLACE - возможность задавать позицию вывода меню; варианты см. в ShowMenu.js var's POS_...
//	bReturnStructure - в каком виде будет возвращаться результат:
//			false - в виде текста (возврат надписи выбранного пункта меню)
//			true - в виде объекта, содержащего свойства name и options (для сложных случаев)
//		если пользователь может использовать любой вариант меню, то лучше передавать 1, а потом универсально анализировать результат pMenuItem[0]
{
	if (hWndMain) {
		opts.pExt = opts.pExt.toLowerCase();
		if (opts.pExt) {
			// Имя файла в этом случае берём по запускаемому скрипту
			opts.pFile = AkelPad.GetFilePath(pScriptName, 3 /* CPF_FILEBASENAME */) + "." + opts.pExt;
		}
		else {
			checkArg("'-pExt' or '-pFile'", opts.pFile);
			opts.pExt = AkelPad.GetFilePath(opts.pFile, 4 /* CPF_FILEEXT */).toLowerCase();
		}
		if (parser_exts.indexOf(opts.pExt) == -1) {
			if (bDebug) AkelPad.Call("Log::Output", 4, WScript.ScriptName + ': -pExt="' + opts.pExt + '"');
			AkelPad.MessageBox(hWndMain, "Papameter parser is not supported extensions different this: " + parser_exts + "!", WScript.ScriptName, 48);
			WScript.Quit();
		}
		if (opts.pFile.indexOf(":") == -1) {
			opts.pFile = expandPath(opts.pFile);
			if (opts.pFile.indexOf(":") == -1)
				opts.pFile = AkelPad.GetAkelDir(5) + "\\Params\\" + opts.pFile;
		}
		if (fso.FileExists(opts.pFile) == true) {
			var lpItems = [];
			var nItem;
			
			var lpContent = AkelPad.ReadFile(opts.pFile);
			lpContent = lpContent.replace(/\n/g, '\r');
			lpContent = lpContent.replace(/\r{2,}/g, '\r');
			lpContent = trim(lpContent, '\r');
			if (lpContent) {
				var arrContent = [];
				var oContent = {};
				var pItem;
				
				//Определение объекта-парсера
				var Parser = {
					proc_txt: function(lpItems) {
						arrContent = lpContent.split('\r');
						for (nItem = 0; nItem < arrContent.length; ++nItem) {
							pItem = arrContent[nItem];
							if (pItem) {
								lpItems[nItem] = [pItem, MF_NORMAL];
								oContent[pItem] = {'name': pItem, 'options': pItem};
								arrContent[nItem] = oContent[pItem];
							}
						}
						return nItem;
					},
					
					proc_ini: function(lpItems) {
						arrContent = lpContent.split('\r');
						var oRegExp = {
							getPureValue: function(pStr) {
								return trim(pStr, ' \t');
							}
						};
						var iSep;
						var pLabel;
						var pOptions;
						for (nItem = 0; nItem < arrContent.length; ++nItem) {
							pItem = arrContent[nItem];
							if (pItem) {
								iSep = pItem.indexOf('=');
								if (iSep == -1) {
									pItem += '=';
									iSep = pItem.length;
								}
								pLabel = oRegExp.getPureValue(pItem.substr(0, iSep));
								pOptions = oRegExp.getPureValue(pItem.substr(iSep + 1));
								if (!pLabel)
									pOptions = "- опции для " + pLabel + " не заданы -";
								
								lpItems[nItem] = [pLabel, MF_NORMAL];
								oContent[pLabel] = {'name': pLabel, 'options': pOptions};
								arrContent[nItem] = oContent[pLabel];
							}
						}
						return nItem;
					},
					
					proc_json: function(lpItems) {
						try {
							eval("var tmpContent = " + lpContent);
							oContent = tmpContent;
							if (oContent.length == undefined) {
								nItem = 0;
								for (var id in oContent) {
									pItem = oContent[id];
									lpItems[nItem] = [pItem.name, MF_NORMAL];
									arrContent[nItem] = pItem;
									nItem += 1;
								}
							}
							else {
								for (nItem = 0; nItem < oContent.length; ++nItem) {
									pItem = oContent[nItem];
									if (pItem) {
										lpItems[nItem] = [pItem.name, MF_NORMAL];
										arrContent[nItem] = pItem;
									}
									else
										throw "Лишняя запятая, разделяющая объекты в json-файле.";
								}
							}
						}
						catch (e) {
							if (bDebug) AkelPad.Call("Log::Output", 4, WScript.ScriptName + ": " + (e.message || e));
							AkelPad.MessageBox(hWndMain, "Structure of config file " + AkelPad.GetFilePath(opts.pFile, 3 /* CPF_FILEBASENAME */) + "." + opts.pExt + " is invalid!", WScript.ScriptName, 48);
							WScript.Quit();
						}
						return nItem;
					}
				};
				
				//Формирование меню
				nItem = Parser["proc_" + opts.pExt](lpItems);
				
				if (!opts.pID || !oContent[opts.pID]) {	// возвращаем структуру, выбранную в диалоге
					var nEditItem;
					if (opts.pExt == "json")
						nEditItem = "изменить конфигурационный файл...";
					else
						nEditItem = "изменить меню...";
					
					if (!(lpItems.length == 1 && bIgnoreMenu)) {
						//Добавление возможности изменять настроечные файлы параметров
						lpItems[nItem] = ["", MF_SEPARATOR];
						lpItems[nItem + 1] = [nEditItem, MF_NORMAL];
						
						//Вывод меню на экран и получение выбранного Item'а
						if (!isNaN(pPOS_PLACE))		//если не числовое значение, то это константа POS_... из ShowMenu.js
							nItem = ShowMenu(lpItems, pPOS_PLACE, pPOS_PLACE);
						else {		//иначе стартовали из тулбара
							pPOS_PLACE = pPOS_PLACE.split(" ");
							var hToolbarHandle = parseInt(pPOS_PLACE[0]);
							var nToolbarItemID = parseInt(pPOS_PLACE[1]);
							var ptPoint = GetToolbarBottonPos(hToolbarHandle, nToolbarItemID)
							nItem = ShowMenu(lpItems, ptPoint.x, ptPoint.y);
						}
					}
					else
						nItem -= 1;
				
					if (nItem != -1) {
						if (lpItems[nItem][0] != nEditItem) {
							// возвращаем структуру по полученному из диалога номеру элемента меню
							if (!bReturnStructure)
								return arrContent[nItem].options;  //Возвращаем опции выбранного пункта меню
							else
								return arrContent[nItem];          //Возвращаем полностью структуру
						}
						else {
							AkelPad.OpenFile(opts.pFile);    //Открываем файл параметров для внесения изменений
							WScript.Quit();
						}
					}
					else
						return "";
				}
				else {
					// возвращаем структуру по переданному id
					if (!bReturnStructure)
						return oContent[opts.pID].options;  //Возвращаем опции выбранного пункта меню
					else
						return oContent[opts.pID];          //Возвращаем полностью структуру
				}
			}
			else {
				if (AkelPad.MessageBox(hWndMain, "Файл параметров '" + opts.pFile + "' ПУСТ! Открыть его?", pScriptName, 4 /*MB_YESNO*/ + 48 /*MB_ICONEXCLAMATION*/) == 6)
					AkelPad.OpenFile(opts.pFile);
				WScript.Quit();
			}
		}
		else {
			if (AkelPad.MessageBox(hWndMain, "Файл параметров '" + opts.pFile + "' НЕ СУЩЕСТВУЕТ! Создать его?", pScriptName, 4 /*MB_YESNO*/ + 48 /*MB_ICONEXCLAMATION*/) == 6) {
				AkelPad.SendMessage(hWndMain, 273 /*WM_COMMAND*/, 4101 /*IDM_FILE_NEW*/, 0);
				hWndEdit = AkelPad.GetEditWnd();
				AkelPad.SaveFile(hWndEdit, opts.pFile);
			}
			WScript.Quit();
		}
	}
}

function initMenuParams(pPOS_PLACE) {
	var result = false;
	if (hWndMain) {
		var params = getSelectedMenuItem(pPOS_PLACE, false);
		if (params) {
			for (var p in params) {
				opts[p] = AkelPad.GetArgValue(p, "") || params[p] || opts[p] /* ini */ || "";
			}
			result = true;
		}
	}
	return result;
}

function initArgs(pNames) {
	for (var p in pNames) {
		opts[pNames[p]] = AkelPad.GetArgValue(pNames[p], "") || opts[pNames[p]] /* ini */;
	}
}

// low priority
function initIniOptions(pNames) {
	if (bIniExist >= 0) {
		var oSet = AkelPad.ScriptSettings();
		if (oSet.Begin("" /* for current script */ , 0x01 /* POB_READ */)) {
			if (bIniExist == 0) {
				if (!opts['pExt']) pNames.push('pExt');
				if (!opts['pFile']) pNames.push('pFile');
			}
			for (var p in pNames) {
				opts[pNames[p]] = oSet.Read(pNames[p], 3 /*PO_STRING*/) || "";
			}
			oSet.End();
			bIniExist = 1;
		}
	}
	else {
		bIniExist = -1;
	}
}

function checkArg(oTitle, option) {
	if (!option) {
		AkelPad.MessageBox(hWndMain, "Option(s) " + oTitle + " should be set!", WScript.ScriptName, 48);
		WScript.Quit();
	}
}

function expandPath(path) {
	if (path) {
		path = WshShell.ExpandEnvironmentStrings(path);
		path = path.replace("%a", AkelPad.GetAkelDir(0));	//ADTYPE_ROOT
		path = path.replace("%t", AkelPad.GetAkelDir(1) + "\\Tools");
		path = path.replace("%p", AkelPad.GetAkelDir(4));	//ADTYPE_PLUGS
		path = path.replace("%s", AkelPad.GetAkelDir(5));	//ADTYPE_SCRIPTS
		path = path.replace("%i", AkelPad.GetAkelDir(6));	//ADTYPE_INCLUDE
		path = path.replace("%o", AkelPad.GetAkelDir(5) + "\\Params");
	}
	else {
		path = "";
	}
	return path;
}

function checkDirPath(folder) {
	if (!folder || !fso.FolderExists(folder)) {
		AkelPad.MessageBox(hWndMain, "Folder '" + folder + "' does not exist! ", WScript.ScriptName, 48);
		WScript.Quit();
	}
}

function checkFilePath(fTitle, file) {
	if (!file || !fso.FileExists(file)) {
		AkelPad.MessageBox(hWndMain, "Path '" + file + "' is invalid! " + fTitle + " is not found.", WScript.ScriptName, 48);
		WScript.Quit();
	}
}

function trim(pText, chars) {
	return pText.replace(new RegExp("(^[" + chars + "])|([" + chars + "]+$)", "g"), "");
}