/*
 *   mru.c
 *
 *   This file is part of Emu28
 *
 *   Copyright (C) 2007 Christoph Gießelink
 *
 */
#include "pch.h"
#include "resource.h"
#include "Emu28.h"

static TCHAR  szOriginal[MAX_PATH] = _T("");

static LPTSTR *ppszFiles = NULL;			// pointer to MRU table
static UINT   nEntry = 0;					// no. of MRU entries

static BOOL GetMenuPosForId(HMENU hMenu, UINT nItem, HMENU *phMruMenu, UINT *pnMruPos)
{
	HMENU hSubMenu;
	UINT  i,nID,nMaxID;

	nMaxID = GetMenuItemCount(hMenu);
	for (i = 0; i < nMaxID; ++i)
	{
		nID = GetMenuItemID(hMenu,i);		// get ID

		if (nID == 0) continue;				// separator or invalid command

		if (nID == (UINT)-1)				// possibly a popup menu
		{
			hSubMenu = GetSubMenu(hMenu,i);	// try to get handle to popup menu
			if (hSubMenu != NULL)			// it's a popup menu
			{
				// recursive search
				if (GetMenuPosForId(hSubMenu,nItem,phMruMenu,pnMruPos))
					return TRUE;
			}
			continue;
		}

		if (nID == nItem)					// found ID
		{
			*phMruMenu = hMenu;				// remember menu and position
			*pnMruPos = i;
			return TRUE;
		}
	}
	return FALSE;
}

BOOL MruInit(UINT nNum)
{
	HMENU hMenu = GetMenu(hWnd);			// main menu
	if (hMenu == NULL) return FALSE;		// failed, no menu bar

	_ASSERT(ppszFiles == NULL);				// MRU already initialized

	// no. of files in MRU list
	nEntry = ReadSettingsInt(_T("MRU"),_T("FileCount"),nNum);

	if (nEntry > 0)							// allocate MRU table
	{
		// create MRU table
		if ((ppszFiles = (LPTSTR *) malloc(nEntry * sizeof(*ppszFiles))) == NULL)
			return FALSE;

		// fill each entry
		for (nNum = 0; nNum < nEntry; ++nNum)
			ppszFiles[nNum] = NULL;

		MruReadList();						// read actual MRU list
	}
	return TRUE;
}

VOID MruCleanup(VOID)
{
	UINT i;

	MruWriteList();							// write actual MRU list

	if (ppszFiles != NULL)					// table defined
	{
		for (i = 0; i < nEntry; ++i)		// cleanup each entry
		{
			if (ppszFiles[i] != NULL)		// valid entry
				free(ppszFiles[i]);			// cleanup entry
		}

		free(ppszFiles);					// free table
		ppszFiles = NULL;
	}
	return;
}

VOID MruAdd(LPCTSTR lpszEntry)
{
	TCHAR  szFilename[MAX_PATH];
	LPTSTR lpFilePart;
	UINT i;

	if (ppszFiles != NULL)					// MRU initialized
	{
		_ASSERT(nEntry > 0);				// must have entries

		// get full path name
		GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);

		// look if entry is already in table
		for (i = 0; i < nEntry; ++i)
		{
			// already in table -> quit
			if (   ppszFiles[i] != NULL		// valid entry
				&& lstrcmpi(ppszFiles[i],szFilename) == 0)
			{
				MruMoveTop(i);				// move to top and update menu
				return;
			}
		}

		i = nEntry - 1;						// last index
		if (ppszFiles[i] != NULL)			// valid entry
			free(ppszFiles[i]);				// free oldest entry

		for (; i > 0; --i)					// move old entries 1 line down
		{
			ppszFiles[i] = ppszFiles[i-1];
		}

		// add new entry to top
		ppszFiles[0] = DuplicateString(szFilename);
	}
	return;
}

VOID MruRemove(UINT nIndex)
{
	// MRU initialized and index inside valid range
	if (ppszFiles != NULL && nIndex < nEntry)
	{
		free(ppszFiles[nIndex]);			// free entry

		for (; nIndex < nEntry - 1; ++nIndex) // move below entries 1 line up
		{
			ppszFiles[nIndex] = ppszFiles[nIndex+1];
		}

		ppszFiles[nIndex] = NULL;			// clear last line
	}
	return;
}

VOID MruMoveTop(UINT nIndex)
{
	// MRU initialized and index inside valid range
	if (ppszFiles != NULL && nIndex < nEntry)
	{
		LPTSTR lpszEntry = ppszFiles[nIndex];// remember selected entry

		for (; nIndex > 0; --nIndex)		// move above entries 1 line down
		{
			ppszFiles[nIndex] = ppszFiles[nIndex-1];
		}

		ppszFiles[0] = lpszEntry;			// insert entry on top
	}
	return;
}

UINT MruEntries(VOID)
{
	return nEntry;
}

UINT MruID(LPCTSTR lpszEntry)
{
	TCHAR  szFilename[MAX_PATH];
	LPTSTR lpFilePart;
	UINT i;

	if (ppszFiles != NULL)					// MRU initialized
	{
		_ASSERT(nEntry > 0);				// must have entries

		// get full path name
		GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);

		// look if entry is already in table
		for (i = 0; i < nEntry; ++i)
		{
			if (   ppszFiles[i] != NULL		// valid entry
				&& lstrcmpi(ppszFiles[i],szFilename) == 0)
			{
				return i;					// return ID
			}
		}
	}
	return (UINT) -1;						// not found
}

VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize)
{
	*szFilename = 0;						// not found

	// MRU initialized and index inside valid range
	if (ppszFiles != NULL && nIndex < nEntry)
	{
		_ASSERT(ppszFiles[nIndex] != NULL);	// valid entry
		lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize);
	}
	return;
}

VOID MruUpdateMenu(HMENU hMenu)
{
	TCHAR szCurPath[MAX_PATH];
	BOOL  bEmpty;
	UINT  i;

	if (hMenu != NULL)						// have menu
	{
		HMENU hMruMenu;						// menu handle for MRU list
		UINT  nMruPos;						// insert position for MRU list

		_ASSERT(IsMenu(hMenu));				// validate menu handle

		// search for menu position of ID_FILE_MRU_FILE1
		if (GetMenuPosForId(hMenu,ID_FILE_MRU_FILE1,&hMruMenu,&nMruPos))
		{
			if (*szOriginal == 0)			// get orginal value of first MRU entry
			{
				VERIFY(GetMenuString(hMruMenu,nMruPos,szOriginal,ARRAYSIZEOF(szOriginal),MF_BYPOSITION));
			}

			if (nEntry == 0)				// kill MRU menu entry
			{
				// delete MRU menu
				DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);

				// delete the following separator
				_ASSERT((GetMenuState(hMruMenu,nMruPos,MF_BYPOSITION) & MF_SEPARATOR) != 0);
				DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);
			}

			if (ppszFiles != NULL)			// MRU initialized
			{
				_ASSERT(nEntry > 0);		// must have entries

				// delete all menu entries
				for (i = 0; DeleteMenu(hMenu,ID_FILE_MRU_FILE1+i,MF_BYCOMMAND) != FALSE; ++i) { }

				// check if MRU list is empty
				for (bEmpty = TRUE, i = 0; bEmpty && i < nEntry; ++i)
				{
					bEmpty = (ppszFiles[i] == NULL);
				}

				if (bEmpty)					// MRU list is empty
				{
					// fill with orginal string
					VERIFY(InsertMenu(hMruMenu,nMruPos,MF_STRING|MF_BYPOSITION|MF_GRAYED,ID_FILE_MRU_FILE1,szOriginal));
					return;
				}

				// current directory
				GetCurrentDirectory(ARRAYSIZEOF(szCurPath),szCurPath);

				for (i = 0; i < nEntry; ++i) // add menu entries
				{
					if (ppszFiles[i] != NULL) // valid entry
					{
						TCHAR  szMenuname[2*MAX_PATH+3];
						TCHAR  szFilename[MAX_PATH];
						LPTSTR lpFilePart,lpszPtr;

						// check if file path and current path is identical
						if (GetFullPathName(ppszFiles[i],ARRAYSIZEOF(szFilename),szFilename,&lpFilePart))
						{
							TCHAR szCutname[MAX_PATH];

							*(lpFilePart-1) = 0; // devide path and name

							// name is current directory -> use only name
							if (lstrcmpi(szCurPath,szFilename) == 0)
							{
								// short name view
							}
							else
							{
								// full name view
								lpFilePart = ppszFiles[i];
							}

							// cut filename to fit into menu
							GetCutPathName(lpFilePart,szCutname,ARRAYSIZEOF(szCutname),36);
							lpFilePart = szCutname;

							// adding accelerator key
							lpszPtr = szMenuname;
							*lpszPtr++ = _T('&');
							*lpszPtr++ = _T('0') + ((i + 1) % 10);
							*lpszPtr++ = _T(' ');

							// copy file to view buffer and expand & to &&
							while (*lpFilePart != 0)
							{
								if (*lpFilePart == _T('&'))
								{
									*lpszPtr++ = *lpFilePart;
								}
								*lpszPtr++ = *lpFilePart++;
							}
							*lpszPtr = 0;

							VERIFY(InsertMenu(hMruMenu,nMruPos+i,
										MF_STRING|MF_BYPOSITION,ID_FILE_MRU_FILE1+i,
										szMenuname));
						}
					}
				}
			}
		}
	}
	return;
}

VOID MruWriteList(VOID)
{
	TCHAR szItemname[32];
	UINT  i;

	if (nEntry > 0)
	{
		// no. of files in MRU list
		WriteSettingsInt(_T("MRU"),_T("FileCount"),nEntry);

		for (i = 0; i < nEntry; ++i)		// add menu entries
		{
			_ASSERT(ppszFiles != NULL);		// MRU not initialized
			wsprintf(szItemname,_T("File%d"),i+1);
			if (ppszFiles[i] != NULL)		// valid entry
			{
				WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
			}
			else
			{
				DelSettingsKey(_T("MRU"),szItemname);
			}
		}
	}
	return;
}

VOID MruReadList(VOID)
{
	TCHAR szFilename[MAX_PATH];
	TCHAR szItemname[32];
	UINT  i;

	for (i = 0; i < nEntry; ++i)			// add menu entries
	{
		_ASSERT(ppszFiles != NULL);			// MRU not initialized

		wsprintf(szItemname,_T("File%d"),i+1);
		ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));

		if (ppszFiles[i] != NULL)			// valid entry
		{
			free(ppszFiles[i]);				// free entry
			ppszFiles[i] = NULL;			// clear last line
		}

		if (*szFilename)					// read a valid entry
		{
			ppszFiles[i] = DuplicateString(szFilename);
		}
	}
	return;
}
