#include "FileMenu.h"

#include <string.h>
#include "WimpLib:exception.h"
#include "WimpLib:File.h"
#include "WimpLib:mem.h"
#include "WimpLib:Menu.h"

HMenu FileMenu_Build(const char* title, const char* path, FileMenu_Accept FAccept, bool bRecurse)
{
	int     entry = 0;
	int     pathlen = strlen(path) + 1;
	char*   volatile pnewfile = NULL;
	char*   pbuffer;
	HMenu   volatile menu = NULL;
	HMenu   submenu = NULL;
	bool    bAdd;
	int     index;

	try
	{
		pnewfile = throw_mem_alloc(MAXPATH);
		pbuffer = pnewfile + pathlen;

		menu = throw_New_Menu_Empty(title);

		strcpy(pnewfile, path);
		pbuffer[-1] = '.';

		while(entry != -1)
		{
			entry = Dir_ReadEntry(path, entry, pbuffer);

			if (pbuffer[0])
			{
				if (bRecurse
				&&  (File_GetFileType(pnewfile) >= 0x01000))
					submenu = FileMenu_Build(pbuffer, pnewfile, FAccept, true);
				else
					submenu = NULL;

				bAdd = FAccept(pnewfile);

				if (bAdd || submenu)
				{
					index = throw_Menu_InsertItem(menu, pbuffer, -1);
					if (!bAdd)
						Menu_ItemSetProperty(menu, index, EMenu_Item_FgColor, 0x5);
					if (submenu)
						Menu_ItemSetSubMenu(menu, index, submenu);
				}
			}
		}

		if (!Menu_CountItems(menu))
		{
			Delete_Menu(menu, true);
			menu = NULL;
		}
	}
	catch
	{
		if (menu)
		{
			Delete_Menu(menu, true);
			menu = NULL;
		}
	}
	catch_end

	mem_free(pnewfile);

	return menu;
}

bool FileMenu_IsValidText(HMenu menu, const char* pname, int* hit)
{
	const char* psubname = pname;
	char* pnext;
	int i = 0;
	int index;

	while (psubname)
	{
		pnext = strchr(psubname, '.');
		if (pnext)
			pnext[0] = 0;

		index = Menu_FindItem(menu, psubname);
		if (index == -1)
		{
			if (hit) hit[0] = -1;
			return false;
		}

		if (hit) hit[i] = index;

		if (pnext)
		{
			menu = Menu_ItemGetSubMenu(menu, index);
			if (!menu)
			{
				if (hit) hit[0] = -1;
				return false;
			}
			i++;
			pnext[0] = '.';
			psubname = pnext + 1;
		}
		else
			psubname = NULL;
	}

	hit[i+1] = -1;

	if (Menu_ItemGetProperty(menu, hit[i], EMenu_Item_FgColor) == 0x7)
		return true;

	hit[0] = -1;
	return false;
}

bool FileMenu_IsValidHit(HMenu menu, const int* hit)
{
	int i = 0;

	if (hit[0] < 0) return false;

	while (hit[i + 1] >= 0)
	{
		menu = Menu_ItemGetSubMenu(menu, hit[i]);
		i++;
	}

	if (Menu_ItemGetProperty(menu, hit[i], EMenu_Item_FgColor) == 0x7)
		return true;
	else
		return false;
}

const char* FileMenu_Decode(HMenu menu, const int* hit)
{
	static char string[MAXPATH];
	char* pstr = string;
	int i;

	// First scan in submenu of current menu
	for (i = 0; hit[i] >= 0; i++)
	{
		strcpy(pstr, Menu_ItemGetText(menu, hit[i]));
		pstr += strlen(pstr);
		*pstr = '.';
		pstr++;
		menu = Menu_ItemGetSubMenu(menu, hit[i]);
	}
	if (hit[0] < 0)
		pstr[0] = 0;
	else
		pstr[-1] = 0; // erase last dot

	return string;
}

void FileMenu_NextHit(HMenu mainmenu, int* hit)
{
	HMenu menu;
	HMenu menus[10];
	int i = 0;
	bool bLast = true;

	menu = mainmenu;

	// First scan in submenu of current menu
	for ( i = 0; hit[i] >= 0; i++)
	{
		if (hit[i] < (Menu_CountItems(menu) - 1))
			bLast = false;
		menus[i] = menu;
		menu = Menu_ItemGetSubMenu(menu, hit[i]);
	}

	// Is very last possible item?
	if (bLast && !menu)
		return;

	menus[i] = menu;
	// hit[i] is -1
	// i >= 0
	// menu is submenu of last selected item (if any)

	while (true)
	{
		// If last item as a submenu, we will found the next value in it.
		while (menu)
		{
			// Is first item valid?
			hit[i] = 0;
			hit[i+1] = -1;
			if (Menu_ItemGetProperty(menu, 0, EMenu_Item_FgColor) == 0x7)
				return;
			// No, then it must have a submenu
			menu = Menu_ItemGetSubMenu(menu, 0);
			i++;
		}

		// No submenu, look at next item in last menu
		i--;
		menu = menus[i];
		if (hit[i] < (Menu_CountItems(menu) - 1))
		{
			// Look at next item
			hit[i]++;
			hit[i+1] = -1;
			// Is item a valid one?
			if (Menu_ItemGetProperty(menu, hit[i], EMenu_Item_FgColor) == 0x7)
				return;
			// No, then it must have a submenu
			menu = Menu_ItemGetSubMenu(menu, hit[i]);
			i++;
		}
		else
		{
			// No next entry on this level, invalidate submenu
			hit[i] = -1;
			menu = NULL;
		}
		// We now fall back on entry case of main loop
	}
}

void FileMenu_PreviousHit(HMenu mainmenu, int* hit)
{
	HMenu menu;
	HMenu menus[10];
	int i = 0;

	menu = mainmenu;

	// First scan in submenu of current menu
	for ( i = 0; hit[i] >= 0; i++)
	{
		menus[i] = menu;
		menu = Menu_ItemGetSubMenu(menu, hit[i]);
	}

	i--;

	while (i >= 0)
	{
		menu = menus[i];
		// previous item
		hit[i]--;
		// If previous item as a submenu, we will found the previous value in it.
		if (hit[i] >= 0)
		{
			// find last item of last submenu
			menu = Menu_ItemGetSubMenu(menu, hit[i]);
			while (menu)
			{
				i++;
				// Is first item valid?
				hit[i] = Menu_CountItems(menu) - 1;
				hit[i+1] = -1;
				menu = Menu_ItemGetSubMenu(menu, hit[i]);
			}
			return;
		}

		// No previous item move back to parent menu
		i--;
	}

	// Gone before first, goto first
	hit[0] = -1;
	FileMenu_NextHit(mainmenu, hit);

	return;
}
