#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include "filemenu.h"
#include "system.h"
#include "filemenuitem.h"

using namespace std;

namespace hm
{

	FileMenu::FileMenu(string title,Surface *surface) :
	Menu(title,surface)
	{
		this->title = title;
		this->surface = surface;
		setSelected(0);
		setWindowSize(320,240);
		icon = NULL;
		scroll = 0;
		actionHandler = NULL;
		background = NULL;
		confirm = false;
		ignoreUnknown = false;

		directoryIcon = new Image("skin/folder.png");
		fileIcon = new Image("skin/file.png");

	}

	void FileMenu::draw()
	{
		int x = this->x;
		int y = this->y;

		Surface *surface = getSurface();

		surface->clearClipRect();

		// draw background
		if (background!=NULL)
			surface->drawImage(background,0,0);

		// center the window to the surface
		if ((x==-1) && (y==-1))
		{
			x = (surface->getWidth() - width) / 2;
			y = (surface->getHeight() - height) / 2;
		}

		// draw the main window
		surface->drawWindow(x,y,width,height,title);

		// draw current directory (will scroll to the right on overflow)
		int ypos = y + windowPadding + surface->getHeaderHeight();
		surface->drawRect(x+windowPadding,ypos,width-windowPadding*2,surface->getFont()->getHeight(),0xFFFFFF);
		
		surface->setClipRect(x+windowPadding,ypos,width-windowPadding*2,surface->getFont()->getHeight());
		int stringSize = surface->getFont()->getStringWidth(getValue());
		int valx = x+windowPadding;
		if (stringSize>(width-windowPadding*2)) valx -= stringSize - (width-windowPadding*2);
		surface->drawText(getValue(),valx,ypos);
		surface->clearClipRect();

		ypos += surface->getFont()->getHeight()+windowPadding;

		// draw the item list
		int listW = width - windowPadding*2;
		int listH = y + height - ypos - windowPadding*2 - surface->getFont()->getHeight();
		int listX = x + windowPadding;
		int listY = ypos;
		drawList(listX,listY,listW,listH);

		ypos += listH+windowPadding;

		// format file size
		string fileSizeText;
		if (selected<children.size())
		{
			FileMenuItem *selectedItem = (FileMenuItem*)children.at(selected);
			unsigned long long size = selectedItem->getFileDescription().size;

			ostringstream val;
			unsigned long long start = 1000 * 1000 * 1000;
			while (start>0)
			{
				int sect = (size/start);

				if (sect>1000)
					val << "." << setfill('0') << setw(3) << (sect % 1000);
				else if (sect>0)
					val << ((size/start) % 1000);

				start /= 1000;
			}

			fileSizeText = val.str();

		}
		else
		{
			fileSizeText = "no files";
		}

		// draw filesize
		//surface->drawRect(x+windowPadding,ypos,width-windowPadding*2,surface->getFont()->getHeight(),0xFFFFFF);
		surface->drawText(fileSizeText,x+windowPadding,ypos);
		ypos += surface->getFont()->getHeight()+windowPadding;

		surface->flip();
	}

	FileMenu::~FileMenu()
	{

		delete(directoryIcon);
		delete(fileIcon);

	}
	
	void FileMenu::addFileExtension(string extension,Image *icon)
	{
		FileExtension e;
		e.extension = extension;
		e.icon = icon;
		fileExensions.push_back(e);
	}

	void FileMenu::setSelected(int sel)
	{
		
		// make sure that the child that was previously selected doesn't have a name
		if (selected<children.size()) children.at(selected)->setName("");

		// make sure that the new selected child does
		if (sel<children.size()) children.at(sel)->setName(name+".file");

		selected = sel;

	}

	void FileMenu::openDirectory(string dirname)
	{

		setValue(dirname);

		// remove all active files
		for (unsigned int i=0; i<children.size(); i++)
		{
			Menu *m = children.at(i);
			delete(m);
		}
		children.clear();

		// enumerate directory
		FileList list = msystem.enumerateDirectory(dirname);
		for (unsigned int i=0; i<list.size(); i++)
		{
			FileMenuItem *m;

			FileDescription file = list.at(i);

			if (file.name != ".")
			{
				m = new FileMenuItem(file.name,getSurface());
				m->setValue(dirname + "/" + file.name);
				m->setFileDescription(file);
				m->setConfirm(confirm,confirmText);
				m->setActionHandler(actionHandler);
			}
			else
			{
				m = NULL;
			}

			// determine icon
			if (m)
			{
				if (file.isdir)
				{
					m->setIcon(directoryIcon);
					appendChild(m);
				}
				else
				{
					bool found=false;
					// look for a known extension
					for (unsigned int j=0; j<fileExensions.size(); j++)
					{
						FileExtension ext = fileExensions.at(j);
						if ( file.name.find(ext.extension)==file.name.size()-ext.extension.size() )
						{
							m->setIcon(ext.icon);
							found = true;
						}
					}
					// none found? just use the 'plain' file icon
					if (!found)
						m->setIcon(fileIcon);

					if (found||!ignoreUnknown)
						appendChild(m);
				}
			}
		}

	}

	int FileMenu::enter()
	{
		int res = 0;

		// fire enter event
		if (actionHandler!=NULL)
			actionHandler->enter(this);

		background = getSurface()->toImage();

		openDirectory(getValue());

		draw();
		scroll = 0;

		running=true;
		while (running)
		{
			Event e = msystem.pollEvent();
			if (e.type==EVENT_QUIT) running = false;

			if (e.type==EVENT_KEYUP)
			{
				if (e.key==KEY_REJECT)
					running=false;

				if (e.key==KEY_ACCEPT)
				{
					if (children.size()>(unsigned int)selected)
					{
						FileMenuItem *item = (FileMenuItem *)children.at(selected);

						if (item->getFileDescription().isdir)
						{
							if (item->getTitle()=="..")
							{
								string path = item->getValue();
								// remove everything after the last /, twice :)
								path = path.substr(0,path.rfind("/",path.rfind("/")-1));
								openDirectory(path);
							}
							else
							{
								openDirectory(item->getValue());
							}
						}
						else
						{
							res = item->enter();
							if (res)
								break;
						}

						setSelected(0);
						draw();
					}
					draw();
				}
			}

			if (e.type==EVENT_KEYDOWN)
			{
				int maxent = children.size()-1;

				if ((e.key==KEY_DOWN)&&((unsigned int)selected<maxent))
					setSelected(selected+1);

				if ((e.key==KEY_UP)&&(selected>0))
					setSelected(selected-1);

				if (e.key==KEY_PGDOWN)
				{
					if ((((unsigned int)selected)+6<maxent))
						setSelected(selected+6);
					else
						setSelected(maxent);
				}

				if (e.key==KEY_PGUP)
				{
					if (((unsigned int)selected) > 5)
						setSelected(selected-6);
					else
						setSelected(0);
				}

				draw();
			}

		}

		delete(background);
		background = NULL;

		return res;
	}

	void FileMenu::setConfirm(bool conf,string text)
	{
		confirm = conf;
		confirmText = text;
	}

	void FileMenu::setIgnoreUnknownTypes(bool ignore)
	{
		ignoreUnknown = ignore;
	}



};

