#pragma once

#include "Menu.h"
#include <Utils/Collection.h>
#include <Engine/GGEMain.h>
#include <Widgets/WidgetRegistry.h>
#include <Widgets/Organizers/ListOrganizer.h>
#include <Widgets/Base/VirtualPanel.h>
#include <Widgets/InlinePanel.h>
#include <Widgets/WidgetRegistry.h>

namespace gaming { namespace menu {

	//Creates a virtual panel, and a linear organizer
	//and places buttons inside the panel, always places on 0,0
	//unless someone modifies its location property
	class DefaultOrganizer : public IOrganizer {
		friend class Menu::Factory;
		friend class Menu;
	public:

		virtual void Setup(Menu &menu) {
			vp.LandOn(menu.MainLayer());
			parent=&menu;
			clearevents();

			Refresh();
		}

		virtual void Refresh() {
			clearevents();

			if(!parent) return;

			int k=0;
			for(auto button=parent->Buttons.First();button.IsValid();button.Next()) {
				gge::widgets::Button *rep=NULL;

				if(button->Visible) {
					if(Buttons.GetCount()>k) {
						Buttons[k].Text=button->Text;
						ip<<Buttons[k];
						Buttons[k].Icon=button->Icon;
						Buttons[k].ClickEvent.LinkTo(button->ClickEvent);
					} else {
						gge::widgets::Button &btn=*new gge::widgets::Button();
						if(gge::widgets::WR.Buttons.Decorative)
							btn.SetBlueprint(gge::widgets::WR.Buttons.Decorative);
						btn.Text=button->Text;
						btn.Icon=button->Icon;
						btn.AllowFocus=false;
						btn.ClickEvent.LinkTo(button->ClickEvent);
						ip<<btn;
						Buttons.Add(btn);
					}

					if(button->Disabled)
						Buttons[k].Disable();
					else
						Buttons[k].Enable();

					k++;
				}


			}
		}

		virtual void Load(gge::resource::DataArray &data) {
			if(data.getInt(1)!=1)
				throw std::runtime_error("Default menu version is not suitable.");
			ip.Move(data.getPoint(2));
			ip.Resize(data.getSize(3));
		}

		virtual ~DefaultOrganizer() {
			Buttons.Destroy();
			gge::widgets::WR.LoadedEvent.Unregister(this, &DefaultOrganizer::wr_loaded);
		}

		static IOrganizer *Create() { return new DefaultOrganizer(); }

	protected:
		void clearevents() {
			for(auto button=Buttons.First();button.IsValid();button.Next()) {
				button->ClickEvent.Clear();
			}
		}

		gge::utils::Collection<gge::widgets::Button> Buttons;
		gge::widgets::ListOrganizer	organizer;

		gge::widgets::VirtualPanel vp;
		gge::widgets::InlinePanel ip;

		Menu *parent;

		void wr_loaded() {
			if(!gge::widgets::WR.Buttons.Decorative) return;
			for(auto button=Buttons.First();button.IsValid();button.Next()) {
				button->SetBlueprint(gge::widgets::WR.Buttons.Decorative);
			}
		}

		DefaultOrganizer() : parent(NULL) {
			ip.SetOrganizer(organizer);
			vp.AddWidget(ip);
			ip.Padding=0;
			gge::widgets::WR.LoadedEvent.Register(this, &DefaultOrganizer::wr_loaded);
		}
	};

	//Hides the menu without any animation or effects
	//just hides the contents of the main frame
	class DefaultHider : public IHider {
		friend class Menu::Factory;
		friend class Menu;
	public:

		virtual void Setup(Menu &menu) {
			parent=&menu;
		}
		virtual void Hide(bool)	{
			parent->MainLayer().IsVisible=false;
			parent->HideComplete();
		};

		virtual void Show(bool)	{
			parent->MainLayer().IsVisible=true;
			parent->ShowComplete();
		};

		virtual void Load(gge::resource::DataArray &data) {}

		static IHider *Create() { return new DefaultHider(); }

	protected:

		DefaultHider() : parent(NULL) { }

		Menu *parent;

	};

	//Null minimizer
	class NullMinimizer : public IMinimizer {
		friend class Menu::Factory;
		friend class Menu;
	public:
		virtual void Setup(Menu& menu) {
			parent=&menu;
		}

		virtual void Minimize(bool animate)	{
			parent->Hide(animate);
		}

		virtual void Restore(bool animate)	{
			parent->Show(animate);
		}

		virtual void Load(gge::resource::DataArray &data) {}

		static IMinimizer *Create() { return new NullMinimizer(); }

	protected:
		Menu *parent;

		NullMinimizer() {}
	};



	//Default minimizer
	class DefaultMinimizer : public IMinimizer {
		friend class Menu::Factory;
		friend class Menu;
	public:
		virtual void Setup(Menu& menu) {
			if(parent)
				btn.ClickEvent.Clear();

			parent=&menu;
			btn.ClickEvent.LinkTo(parent->RestoreButton.ClickEvent);
			btn.ClickEvent.Register(this, &DefaultMinimizer::restore_click);

			vp.Show();
			vp.LandOn(menu.MinimizeLayer());
		}

		virtual void Minimize(bool)	{
			if(!parent) return;

			parent->MainLayer().IsVisible=false;
			parent->MinimizeComplete();
		};

		virtual void Refresh() {
			if(!parent) return;

			btn.Text=parent->RestoreButton.Text;
			btn.Icon=parent->RestoreButton.Icon;
			btn.SetEnabled(!parent->RestoreButton.Disabled);
			parent->MinimizeLayer().IsVisible=parent->RestoreButton.Visible;
		}

		virtual void Restore (bool)	{
			if(!parent) return;

			parent->MainLayer().IsVisible=true;
			parent->RestoreComplete();
		};

		virtual void Load(gge::resource::DataArray &data) {
			if(data.getInt(1)!=1)
				throw std::runtime_error("Default minimizer version is not suitable.");
			btn.Move(data.getPoint(2));
		}


		~DefaultMinimizer() {
			gge::widgets::WR.LoadedEvent.Register(this, &DefaultMinimizer::wr_loaded);
		}

		static IMinimizer *Create() { return new DefaultMinimizer(); }
	protected:
		void restore_click() {
			parent->Restore();
		}

		gge::widgets::VirtualPanel		vp;
		gge::widgets::Button			btn;

		Menu *parent;

		void wr_loaded() {
			if(!gge::widgets::WR.Buttons.Decorative) return;

			btn.SetBlueprint(gge::widgets::WR.Buttons.Decorative);
		}


		DefaultMinimizer()
		{
			btn.SetContainer(vp);
			btn.ClickEvent.Register(this, &DefaultMinimizer::restore_click);

			if(gge::widgets::WR.Buttons.Decorative) 
				btn.SetBlueprint(gge::widgets::WR.Buttons.Decorative);;


			gge::widgets::WR.LoadedEvent.Register(this, &DefaultMinimizer::wr_loaded);
		}
	};

} }