#include "Menu.h"
#include "Default.h"
#include <Resource/DataArray.h>

#include <stdexcept>

using namespace std;
using namespace gge::resource;
using namespace gge::utils;

namespace gaming { namespace menu {

	Menu::Menu() : 
		visible(false), minimized(false),
		HideComplete("hidecomplete", this), ShowComplete("showcomplete", this),
		MinimizeComplete("minimizecomplete", this), RestoreComplete("restorecomplete", this),
		RestoreStarted("restorestarted", this),
		RestoreButton(*this)
	{
		layer.Add(main);
		layer.Add(minimize);
	}

	void Menu::ObtainFrom(gge::resource::DataArray &data) {
		gge::utils::CheckAndDelete(Interfaces.Minimizer);
		gge::utils::CheckAndDelete(Interfaces.Hider);
		gge::utils::CheckAndDelete(Interfaces.Organizer);

		layer.Resize(gge::Main.BoundingBox.GetSize());
		main.Resize(gge::Main.BoundingBox.GetSize());
		minimize.Resize(gge::Main.BoundingBox.GetSize());
		layer.Add(main);
		layer.Add(minimize);

		if(!data.checkLink(1)) {
			throw runtime_error("Organizer cannot be empty");
		} else
			Interfaces.Organizer=Factory::CreateOrganizer(*this, dynamic_cast<gge::resource::DataArray&>(data.getLink(1)));

		if(data.checkLink(2)) {
			Interfaces.Hider=Factory::CreateHider(*this, dynamic_cast<gge::resource::DataArray&>(data.getLink(2)));
		} else
			Interfaces.Hider=new DefaultHider;

		if(data.checkLink(3)) {
			Interfaces.Minimizer=Factory::CreateMinimizer(*this, dynamic_cast<gge::resource::DataArray&>(data.getLink(3)));
		} else
			Interfaces.Minimizer=new NullMinimizer;

		Interfaces.Organizer->Setup(*this);
		Interfaces.Hider->Setup(*this);
		Interfaces.Minimizer->Setup(*this);
		if(Interfaces.Minimizer) {
			if(minimized)
				Interfaces.Minimizer->Minimize(false);
			else
				Interfaces.Minimizer->Restore(false);
		}

		if(!visible && Interfaces.Hider)
			Interfaces.Hider->Hide(false);
	}

	void Menu::UseLayer(gge::LayerBase &layer) {
		layer.Add(this->layer);

		Refresh();
	}

	void Menu::Refresh() { 
		if(Interfaces.Organizer) 
			Interfaces.Organizer->Refresh(); 
		if(Interfaces.Minimizer)
			Interfaces.Minimizer->Refresh();
	}

	void Menu::Minimize(bool animate) {
		if(Interfaces.Minimizer) {
			if(!minimized) {
				Interfaces.Minimizer->Minimize(animate); 
				minimized=true;
			} else
				MinimizeComplete();
		}
	}

	void Menu::Restore(bool animate) {
		if(Interfaces.Minimizer) {
			if(minimized) {
				RestoreStarted();
				Interfaces.Minimizer->Restore(animate); 
				minimized=false;
			} else
				RestoreComplete();
		}
	}

	void Menu::Hide(bool animate) {
		if(Interfaces.Hider) {
			if(visible) {
				Interfaces.Hider->Hide(animate); 
				visible=false;
			} else
				HideComplete();
		}
	}
	
	void Menu::Show(bool animate) {
		if(Interfaces.Hider) {
			if(!visible) {
				Interfaces.Hider->Show(animate); 
				visible=true;
			} else
				ShowComplete();
		}
	}


	Menu::Button &Menu::AddButton(std::string Caption) {
		Menu::Button *btn=new Menu::Button(*this, Caption);
		Buttons.Add(btn);

		Refresh();

		return *btn;
	}

	Menu::Button &Menu::AddButton(std::string Caption, std::function<void()> Handler) {
		Menu::Button *btn=new Menu::Button(*this, Caption);
		btn->ClickEvent.RegisterLambda(Handler);
		Buttons.Add(btn);

		Refresh();

		return *btn;
	}

	IOrganizer *Menu::Factory::CreateOrganizer(Menu &Parent, gge::resource::DataArray &data) {
		IOrganizer *organizer=NULL;

		for(auto creator=Organizers.First();creator.IsValid();creator.Next()) {
			if(creator->ID==data.getString(0))
				organizer=creator->fn();
		}

		if(!organizer)
			organizer=new DefaultOrganizer();

		organizer->Load(data);
		
		return organizer;
	}

	IHider	   *Menu::Factory::CreateHider    (Menu &Parent, gge::resource::DataArray &data) {
		IHider *hider=NULL;

		for(auto creator=Hiders.First();creator.IsValid();creator.Next()) {
			if(creator->ID==data.getString(0))
				hider=creator->fn();
		}

		if(!hider)
			hider=new DefaultHider();

		hider->Load(data);
		
		return hider;
	}

	IMinimizer *Menu::Factory::CreateMinimizer(Menu &Parent, gge::resource::DataArray &data) {
		IMinimizer *minimizer=NULL;

		for(auto creator=Minimizers.First();creator.IsValid();creator.Next()) {
			if(creator->ID==data.getString(0))
				minimizer=creator->fn();
		}

		if(!minimizer)
			minimizer=new DefaultMinimizer();

		minimizer->Load(data);
		
		return minimizer;
	}


} }
