/*
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.
*/

#include "ShortcutMapper.h"
#include "Notepad_plus.h"

void ShortcutMapper::initBabyGrid() {
	RECT rect;
	getClientRect(rect);
	_babygrid.init(_hInst, _hSelf, IDD_BABYGRID_ID1);
	_babygrid.reSizeTo(rect);
	_babygrid.hideCursor();
	_babygrid.makeColAutoWidth();
	_babygrid.setColsNumbered(false);
	_babygrid.setColWidth(0, 27);
}

void ShortcutMapper::fillOutBabyGrid()
{
	NppParameters *nppParam = NppParameters::getInstance();
	vector<ScintillaKeyMap> &skms = nppParam->getScintillaKeyList();
	int nbScitillaMsg = skms.size();
	_pAccel = nppParam->getAccelerator();
	_babygrid.setLineColNumber(_pAccel->_nbAccelItems + nbScitillaMsg, 2);
	_babygrid.setText(0, 1, "Name");
	_babygrid.setText(0, 2, "Shortcut");

	int i = 0 ;
	for ( ; i < _pAccel->_nbAccelItems ; i++)
	{
		unsigned char vFlg = _pAccel->_pAccelArray[i].fVirt;
		string shortcut = (vFlg & FCONTROL)?"Ctrl+":"";
		shortcut += (vFlg & FALT)?"Alt+":"";
		shortcut += (vFlg & FSHIFT)?"Shift+":"";
		string key;
		getKeyStrFromVal((unsigned char)_pAccel->_pAccelArray[i].key, key);
		shortcut += key;
		_babygrid.setText(i+1, 2, shortcut.c_str());

		string shortcutName;
		getNameStrFromCmd(_pAccel->_pAccelArray[i].cmd, shortcutName);
		_babygrid.setText(i+1, 1, shortcutName.c_str());
	}

	for (size_t j = 0 ; i < _pAccel->_nbAccelItems + nbScitillaMsg ; i++, j++)
	{
		_babygrid.setText(i+1, 1, skms[j]._name);
		_babygrid.setText(i+1, 2, skms[j].toString().c_str());
	}
}

BOOL CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_INITDIALOG :
		{
			initBabyGrid();
			fillOutBabyGrid();
			_babygrid.display();
			
			goToCenter();

			return TRUE;
		}

		case WM_COMMAND : 
		{
			switch (wParam)
			{
				case IDCANCEL :
				{
					::EndDialog(_hSelf, -1);
					return TRUE;
				}
				case IDOK :
				{
					::EndDialog(_hSelf, 0);
					return TRUE;
				}

				case IDM_BABYGRID_MODIFY :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					int row = _babygrid.getSelectedRow();

					if (row <= _pAccel->_nbAccelItems)
					{
						ACCEL accel = _pAccel->_pAccelArray[row-1];
						string shortcutName;
						DWORD cmdID = _pAccel->_pAccelArray[row-1].cmd;
						ShortcutType st = getNameStrFromCmd(cmdID, shortcutName);
						if (st != TYPE_PLUGINCMD)
						{
							Shortcut shortcut(shortcutName.c_str(), (accel.fVirt & FCONTROL) != 0, (accel.fVirt & FALT) != 0, (accel.fVirt & FSHIFT) != 0, (unsigned char)accel.key);
							shortcut.init(_hInst, _hSelf);
							shortcut.setNameReadOnly(!(st == TYPE_CMD));
						
							if (shortcut.doDialog() != -1)
							{
								// Update the key map
								_pAccel->_pAccelArray[row-1].fVirt = FVIRTKEY | (shortcut._isCtrl?FCONTROL:0) | (shortcut._isAlt?FALT:0) | (shortcut._isShift?FSHIFT:0);
								_pAccel->_pAccelArray[row-1].key = shortcut._key;
								_pAccel->reNew();
								
								// Update the GUI
								string sc = shortcut.toString();
								_babygrid.setText(row, 2, sc.c_str());

								// Add (or update) shortcut to vector in order to save what we have done
								if (st == TYPE_CMD)
								{
									bool found = false;
									vector<CommandShortcut> & shortcutList = nppParam->getUserShortcuts();

									for (size_t i = 0 ; i < shortcutList.size() ; i++)
									{
										if (cmdID == shortcutList[i].getID())
										{
											shortcutList[i].copyShortcut(shortcut);
											/*shortcutList[i]._isCtrl = shortcut._isCtrl;
											shortcutList[i]._isAlt = shortcut._isAlt;
											shortcutList[i]._isShift = shortcut._isShift;
											shortcutList[i]._key = shortcut._key;*/
											found = true;
										}
									}
									if (!found)
										shortcutList.push_back(CommandShortcut(cmdID, shortcut));

									::SendMessage(_hParent, WM_CMDLIST_MODIFIED, (WPARAM)sc.c_str(), cmdID);
								}
								else if (st == TYPE_MACRO)
								{
									vector<MacroShortcut> & theMacros = nppParam->getMacroList();
									const int i = cmdID-ID_MACRO;
									theMacros[i].copyShortcut(shortcut);
									/*strcpy(theMacros[i]._name, shortcut._name);
									theMacros[i]._isCtrl = shortcut._isCtrl;
									theMacros[i]._isAlt = shortcut._isAlt;
									theMacros[i]._isShift = shortcut._isShift;
									theMacros[i]._key = shortcut._key;*/

									HMENU hMenu = ::GetSubMenu(::GetMenu(_hParent), MENUINDEX_MACRO);
									::ModifyMenu(hMenu, cmdID, MF_BYCOMMAND, cmdID, theMacros[i].toMenuItemString().c_str());

									::SendMessage(_hParent, WM_MACROLIST_MODIFIED, 0, 0);
								}
								else if (st == TYPE_USERCMD)
								{
									vector<UserCommand> & theUserCmds = nppParam->getUserCommandList();
									const int i = cmdID-ID_USER_CMD;
									theUserCmds[i].copyShortcut(shortcut);
									/*
									strcpy(theUserCmds[i]._name, shortcut._name);
									theUserCmds[i]._isCtrl = shortcut._isCtrl;
									theUserCmds[i]._isAlt = shortcut._isAlt;
									theUserCmds[i]._isShift = shortcut._isShift;
									theUserCmds[i]._key = shortcut._key;
									*/
									HMENU hMenu = ::GetSubMenu(::GetMenu(_hParent), MENUINDEX_RUN);
									::ModifyMenu(hMenu, cmdID, MF_BYCOMMAND, cmdID, theUserCmds[i].toMenuItemString().c_str());

									::SendMessage(_hParent, WM_USERCMDLIST_MODIFIED, 0, 0);
								}
								_babygrid.setText(row, 1, shortcut._name);
							}
						}
					}
					else // Scintilla Key shortcut
					{
						vector<ScintillaKeyMap> & scintillaShortcuts = nppParam->getScintillaKeyList();
						const int index = row - _pAccel->_nbAccelItems - 1;
						ScintillaKeyMap scintillaSc = scintillaShortcuts[index];
						scintillaSc.init(_hInst, _hSelf);
						scintillaSc.setNameReadOnly(false);

						if (scintillaSc.doDialog() != -1)
						{
							// Add this modification into the list to save it later
							bool found = false;
							vector<ScintillaKeyMap> & userDefScintillaKeys = nppParam->getScintillaModifiedKeys();
							for (size_t i = 0 ; i < userDefScintillaKeys.size() ; i++)
							{
								if (scintillaSc.getID() == userDefScintillaKeys[i].getID())
								{
									userDefScintillaKeys[i].copyShortcut(scintillaSc);
									found = true;
								}
							}
							if (!found)
								userDefScintillaKeys.push_back(scintillaSc);

							// remap the key
							::SendMessage(_hParent, WM_BIND_SCINTILLAKEY, scintillaSc.toKeyDef(), scintillaSc.getScintillaKey());
							::SendMessage(_hParent, WM_CANCEL_SCINTILLAKEY, scintillaShortcuts[index].toKeyDef(), 0);
							
							// update the key in the scintilla key list
							scintillaShortcuts[index].copyShortcut(scintillaSc);

							// if this shortcut is linked to a menu item, change to shortcut string in menu item
							if (int cmdID = scintillaShortcuts[index].getMenuCmdID())
							{
								HMENU hMenu = ::GetMenu(_hParent);
								::ModifyMenu(hMenu, cmdID, MF_BYCOMMAND, cmdID, scintillaShortcuts[index].toMenuItemString(cmdID).c_str());
							}

							// Update UI
							_babygrid.setText(row, 2, scintillaSc.toString().c_str());

							::SendMessage(_hParent, WM_SCINTILLAKEY_MODIFIED, 0, 0);
						}
					}
					return TRUE;
				}
				case IDM_BABYGRID_DELETE :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					if (::MessageBox(_hSelf, "Are you sure to delete this shortcut?", "Are you sure?", MB_OKCANCEL) == IDOK)
					{
						const int row = _babygrid.getSelectedRow();
						DWORD cmdID = _pAccel->_pAccelArray[row-1].cmd;
						
						// Menu data
						int erasePos;
						size_t posBase;
						size_t nbElem;
						HMENU hMenu;

						if ((cmdID >= ID_MACRO) && (cmdID < ID_MACRO_LIMIT))
						{
							vector<MacroShortcut> & theMacros = nppParam->getMacroList();
							vector<MacroShortcut>::iterator it = theMacros.begin();
							erasePos = cmdID - ID_MACRO;
							theMacros.erase(it + erasePos);
							_pAccel->uptdateShortcuts();
							_babygrid.clear();
							fillOutBabyGrid();
							
							// preparing to remove from menu
							posBase = 3;
							nbElem = theMacros.size();
							hMenu = ::GetSubMenu(::GetMenu(_hParent), MENUINDEX_MACRO);

							::SendMessage(_hParent, WM_MACROLIST_MODIFIED, 0, 0);
						}
						else if ((cmdID >= ID_USER_CMD) && (cmdID < ID_USER_CMD_LIMIT))
						{
							vector<UserCommand> & theUserCmds = nppParam->getUserCommandList();
							vector<UserCommand>::iterator it = theUserCmds.begin();
							erasePos = cmdID - ID_USER_CMD;
							theUserCmds.erase(it + erasePos);
							_pAccel->uptdateShortcuts();
							_babygrid.clear();
							fillOutBabyGrid();
							
							// preparing to remove from menu
							posBase = 0;
							nbElem = theUserCmds.size();
							hMenu = ::GetSubMenu(::GetMenu(_hParent), MENUINDEX_RUN);
							
							::SendMessage(_hParent, WM_USERCMDLIST_MODIFIED, 0, 0);
						}
						else // should never happen
						{
							return FALSE;
						}

						// remove from menu
						::RemoveMenu(hMenu, cmdID++, MF_BYCOMMAND);

						for (size_t i = erasePos ; i < nbElem ; i++)
						{
							char cmdName[64];
							::GetMenuString(hMenu, cmdID, cmdName, sizeof(cmdName), MF_BYCOMMAND);
							::ModifyMenu(hMenu, cmdID, MF_BYCOMMAND, cmdID-1, cmdName);
							cmdID++;
						}
						if (nbElem == 0)
							::RemoveMenu(hMenu, posBase + 1, MF_BYPOSITION);

					}
					return TRUE;
				}
				default :
					if (LOWORD(wParam) == IDD_BABYGRID_ID1)
					{
						if(HIWORD(wParam) == BGN_CELLDBCLICKED) //a cell was clicked in the properties grid
						{
							return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_MODIFY, LOWORD(lParam));
						}
						else if(HIWORD(wParam) == BGN_CELLRCLICKED) //a cell was clicked in the properties grid
						{
							int row = LOWORD(lParam);
							DWORD cmdID = _pAccel->_pAccelArray[row-1].cmd;

							POINT p;
							::GetCursorPos(&p);
							if (!_rightClickMenu.isCreated())
							{
								vector<MenuItemUnit> itemUnitArray;
								itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_MODIFY, "Modify"));
								itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_DELETE, "Delete"));
								_rightClickMenu.create(_hSelf, itemUnitArray);
							}
							bool b = (!((cmdID >= ID_MACRO) && (cmdID < ID_MACRO_LIMIT))) && (!((cmdID >= ID_USER_CMD) && (cmdID < ID_USER_CMD_LIMIT)));
							_rightClickMenu.enableItem(IDM_BABYGRID_DELETE, !b);
							_rightClickMenu.display(p);
							return TRUE;
						}
					}
			}
		}
		default:
			return FALSE;
	}
	return FALSE;
}
