#pragma once
#include <sstream>

#include <Widgets/Panel.h>
#include <Widgets/Label.h>
#include <Widgets/Organizers/LinearOrganizer.h>

#include "../Mechanics/PlayerGame.h"
#include "../Mechanics/Townsfolk.h"
#include "../Mechanics/Human.h"
#include "../Mechanics/Soldier.h"
#include "../Mechanics/Artisan.h"
#include "../Mechanics/TownBuilding.h"
#include "ArtisanChooser.h"
#include "CraftingList.h"
#include <Widgets/Button.h>
#include "../Mechanics/Inventory.h"
#include "Inventory.h"
#include <Widgets/Progressbar.h>
#include <iomanip>
#include "../Mechanics/Den.h"

//for vs
#undef interface

namespace interface {

	class Infopanel : public gge::widgets::Panel {
	public:
		Infopanel() : selected(NULL), userminimized(false), minimized(true) {
			setshowvscroll(false);

			SetOrganizer(organizer);

			SetContainer(gge::widgets::TopLevel);
			Resize(300, 165);
			SetX((gge::widgets::TopLevel.GetWidth()-GetWidth())*3/4);

			Padding=gge::utils::Margins(6,8,5,10);

			name.SetBlueprint(gge::widgets::WR.Labels.Subheading);


			hireSoldier.Text="Recruit";
			hireArtisan.Text="Hire artisan";
			destroyTB.Text="Destroy";
			craft.Text="Craft";
			openInventory.Text="Inventory";

			hp.AnimationDuration=250;
			stamina.AnimationDuration=250;
			craftprog.AnimationDuration=250;


			auto nl=organizer.nextline;
			

			organizer.Spacing=0;

			organizer
				<<name<<nl
				<<type<<nl
				<<info<<nl
			;

			hireSoldier.ClickEvent.RegisterLambda([&]{
				if(dynamic_cast<mechanics::Townsfolk*>(selected)) {
					mechanics::Townsfolk *tf=dynamic_cast<mechanics::Townsfolk*>(selected);
					auto s=tf->BecomeASoldier();
					display(s);
					selectObject(s);
				}
			});

			hireArtisan.ClickEvent.RegisterLambda([&]{
				artisanChooser.Show();
			});

			destroyTB.ClickEvent.RegisterLambda([&]{
				if(dynamic_cast<mechanics::TownBuilding*>(selected)) {
					mechanics::TownBuilding *tb=dynamic_cast<mechanics::TownBuilding*>(selected);
					tb->destroy();
					display(NULL);
					selectObject(NULL);
				}
			});

			artisanChooser.accepted.RegisterLambda([&](std::string ID) {
				if(dynamic_cast<mechanics::Townsfolk*>(selected)) {
					mechanics::Townsfolk *tf=dynamic_cast<mechanics::Townsfolk*>(selected);
					auto a=tf->BecomeAnArtisan(ID);
					display(a);
					selectObject(a);
				}
				artisanChooser.Hide();
			});

			craft.ClickEvent.RegisterLambda([&]{
				if(dynamic_cast<mechanics::Artisan*>(selected)) {
					mechanics::Artisan *a=dynamic_cast<mechanics::Artisan*>(selected);
					craftingList.Show(*a);
				}
			});

			craftingList.accepted.RegisterLambda([&](std::string ID) {
				if(dynamic_cast<mechanics::Artisan*>(selected)) {
					mechanics::Artisan *a=dynamic_cast<mechanics::Artisan*>(selected);
					if(!mechanics::PlayerGame::current().CheckCraft(ID, true)) {
						a->setAnimation(North, "No", false);
						return;
					}

					a->beginCrafting(ID);
					display(selected);
				}
			});

			openInventory.ClickEvent.RegisterLambda([&]{
				if(dynamic_cast<mechanics::Soldier*>(selected)) {
					mechanics::Soldier *s=dynamic_cast<mechanics::Soldier*>(selected);
					inventory.Show(s);
				}
			});


			minimize();
		}

		virtual bool KeyboardHandler(gge::input::keyboard::Event::Type event, gge::input::keyboard::Key Key) {
			if(gge::widgets::Panel::KeyboardHandler(event, Key))
				return true;
			
			if(event == gge::input::keyboard::Event::Down) {
				if(selected != NULL) {
					if(Key==gge::input::keyboard::KeyCodes::Escape) {
						minimize();
						return true;
					}
					else if(Key == gge::input::keyboard::KeyCodes::F1) {
						if(minimized) {
							userminimized=false;
							display(selected);
						}
						else {
							userminimized=true;
							minimize();
						}
					}
				}
			}

			return false;
		}

		virtual bool MouseHandler(gge::input::mouse::Event::Type event, gge::utils::Point location, int amount) {
			if(event==gge::input::mouse::Event::Left_Click) {
				if(minimized) {
					userminimized=false;
					display(selected);
				}
				else {
					userminimized=true;
					minimize();
				}
			}

			return !gge::input::mouse::Event::isScroll(event);
		}

		void update() {
			if(!mechanics::PlayerGame::isInGame()) return;

			display(selected);

			if(inventory.IsVisible())
				inventory.update();
		}

		void display(mechanics::Object *object) {
			selected=object;

			hireSoldierl.Detach();
			hireSoldier.Detach();
			hireArtisanl.Detach();
			hireArtisan.Detach();
			destroyTB.Detach();
			hp.Detach();
			hpl.Detach();
			craftprog.Detach();
			craftitem.Detach();
			stamina.Detach();
			staminal.Detach();
			craft.Detach();
			craftl.Detach();
			openInventory.Detach();
			name="";
			type="";
			info.Text="";
			name.Icon=NULL;

			if(!selected) {
				minimize();
			}
			else {
				if(!userminimized) {
					restore();
				}

				if(dynamic_cast<mechanics::Townsfolk*>(selected)) {
					mechanics::Townsfolk *tf=dynamic_cast<mechanics::Townsfolk*>(selected);
					name = "  "+tf->title();
					name.Icon=gge::widgets::WR.Icons("citizen");

					std::stringstream ss;
					ss<<(tf->gender()==Gender::male ? "Male" : "Female")<<", ";
					ss<<"HP: "<<(int)tf->HP()<<"/"<<(int)tf->maximumHP()<<std::endl;
					ss<<tf->stat();
					info.Text=ss.str();

					organizer<<hireSoldier<<hireSoldierl<<organizer.nextline;
					organizer<<hireArtisan<<hireArtisanl<<organizer.nextline;;

					hireSoldier.Enable();
					hireArtisan.Enable();
					ss.str("");
					ss<<"  Recruiting costs "<<assets::constants::gold::soldierGoldCost<<" gold.";
					hireSoldierl.Text=ss.str();
					ss.str("");
					ss<<"  Hiring costs "<<assets::constants::gold::artisanGoldCost<<" gold.";
					hireArtisanl.Text=ss.str();

					if(mechanics::PlayerGame::current().soldierHousing()<=mechanics::PlayerGame::current().getUnitCount()) {
						hireArtisan.Disable();
						hireSoldier.Disable();
						hireSoldierl.Text="  Cannot house more units.";
						hireArtisanl.Text="  Cannot house more units.";
						organizer.Reorganize();
						return;
					}
					if(tf->gender()!=Gender::male) {
						hireSoldier.Disable();
						hireSoldierl.Text="  Only males can be recruited.";
						organizer.Reorganize();
					}
					if(mechanics::PlayerGame::current().gold()<assets::constants::gold::soldierGoldCost) {
						hireSoldier.Disable();
					}
					if(mechanics::PlayerGame::current().gold()<assets::constants::gold::artisanGoldCost) {
						hireArtisan.Disable();
					}
				}
				else if(dynamic_cast<mechanics::Soldier*>(selected)) {
					mechanics::Soldier *s=dynamic_cast<mechanics::Soldier*>(selected);
					name = "  "+s->title();
					name.Icon=gge::widgets::WR.Icons("soldier");


					std::stringstream ss;
					ss<<"Level: "<<s->level()<<" ("<<(int)s->xp()<<"/"<<(int)s->nextLevelXP()<<"), ";
					if(s->inventory().mainHand)
						ss<<"Dam: "<<(int)s->inventory().mainHand->attackDamage()<<" ("<<std::fixed<<std::setprecision(1)<<s->inventory().mainHand->cooldown()/1000.f<<"s)";
					else
						ss<<"No weapon";
					ss<<std::endl;
					ss<<s->stat();
					info.Text=ss.str();

					ss.str("");
					ss<<"HP: "<<(int)s->HP()<<"/"<<(int)s->maximumHP()<<"  ";
					hp.Max=s->maximumHP();
					hp.Value=s->HP();
					hpl.Text=ss.str();

					ss.str("");
					ss<<"Sta: "<<(int)s->stamina()<<"/"<<(int)s->maximumStamina()<<"  ";
					stamina.Max=s->maximumStamina();
					stamina.Value=s->stamina();
					staminal.Text=ss.str();

					organizer<<hpl<<hp<<organizer.nextline;
					organizer<<staminal<<stamina<<organizer.nextline;
					organizer<<openInventory<<organizer.nextline;
				}
				else if(dynamic_cast<mechanics::Artisan*>(selected)) {
					mechanics::Artisan *a=dynamic_cast<mechanics::Artisan*>(selected);
					name.Icon=gge::widgets::WR.Icons("artisan");
					name = "  "+a->title();

					std::stringstream ss;
					ss<<(a->gender()==Gender::male ? "Male" : "Female")<<", ";
					ss<<"Level: "<<a->level()<<" ("<<(int)a->xp()<<"/"<<(int)a->nextLevelXP()<<"), ";
					ss<<"HP: "<<(int)a->HP()<<"/"<<(int)a->maximumHP()<<std::endl;
					ss<<a->stat();
					info.Text=ss.str();



					if(a->crafting()) {
						ss.str("");
						ss<<"  finishing in "<<std::fixed<<std::setprecision(1)<<(a->totalCraftTime()-a->craftProgress())/1000.f<<" secs";

						craftl.Text=ss.str();
						craft.Disable();

						craftitem.Text="Crafting: "+a->crafting()->ID+"  ";
						craftprog.Max=a->totalCraftTime();
						craftprog.Value=a->craftProgress();

						organizer<<craftitem<<craftprog<<organizer.nextline;
					}
					else {
						craftl.Text="";
						craft.Enable();
					}

					organizer<<craft<<craftl<<organizer.nextline;
				}
				else if(dynamic_cast<mechanics::TownBuilding*>(selected)) {
					mechanics::TownBuilding *tb=dynamic_cast<mechanics::TownBuilding*>(selected);
					name="  "+tb->provider().ID;
					name.Icon=gge::widgets::WR.Icons("building");

					type="Town building";
					std::stringstream ss;
					ss<<"Capacity: "<<tb->capacity();
					info.Text=ss.str();

					ss.str("");
					ss<<"HP: "<<(int)tb->HP()<<"/"<<(int)tb->maximumHP()<<"  ";
					hpl.Text=ss.str();
					hp.Max=tb->maximumHP();
					hp.Value=tb->HP();

					organizer<<hpl<<hp<<organizer.nextline;

					organizer<<destroyTB<<organizer.nextline;

					destroyTB.SetEnabled(tb->provider().ID!="Town center");
				}
				else if(dynamic_cast<mechanics::MilitaryBuilding*>(selected)) {
					mechanics::MilitaryBuilding *mb=dynamic_cast<mechanics::MilitaryBuilding*>(selected);

					std::stringstream sst;
					std::stringstream ss;

					name="  "+mb->provider().ID;
					name.Icon=gge::widgets::WR.Icons("building");

					sst<<"Military building - ";
					switch(mb->type()) {
					case assets::MilitaryBuilding::Housing:
						sst<<"housing";

						ss<<"Capacity: "<<dynamic_cast<mechanics::HousingBuilding*>(mb)->capacity();

						break;
					case assets::MilitaryBuilding::Storage:
						sst<<"storage";

						mechanics::StorageBuilding *st;
						st=dynamic_cast<mechanics::StorageBuilding*>(mb);

						ss<<"Type: ";

						switch(st->storageType()) {
						case assets::Item::Armor:
							ss<<"Armor";
							break;
						case assets::Item::Melee:
							ss<<"Melee";
							break;
						case assets::Item::Thrust:
							ss<<"Polearm";
							break;
						case assets::Item::Ranged:
							ss<<"Bow";
							break;
						case assets::Item::Cast:
							ss<<"Wand";
							break;
						}
						ss<<std::endl;

						ss<<"Stored: "<<st->stored()<<"/"<<st->capacity();

						break;
					case assets::MilitaryBuilding::Tools:
						sst<<"tools";
						break;
					case assets::MilitaryBuilding::MeleeTraining:
						sst<<"training - melee";

						ss<<"Max level: "<<mb->provider().maxLvl;

						break;
					case assets::MilitaryBuilding::RangedTraining:
						sst<<"training - ranged";

						ss<<"Max level: "<<mb->provider().maxLvl;

						break;
					}
					type=sst.str();
					info.Text=ss.str();

					ss.str("");
					ss<<"HP: "<<(int)mb->HP()<<"/"<<(int)mb->maximumHP()<<"  ";
					hpl.Text=ss.str();
					hp.Max=mb->maximumHP();
					hp.Value=mb->HP();

					organizer<<hpl<<hp<<organizer.nextline;


					//destroyMB.Show();

					//destroyMB.SetEnabled(tb->provider().ID!="Town center");
				}
				else if(dynamic_cast<mechanics::Wildling*>(selected)) {
					auto w=dynamic_cast<mechanics::Wildling*>(selected);

					name.Text="  "+w->provider().ID;
					name.Icon=gge::widgets::WR.Icons("wildling");

					type.Text="Wildling";

					hpl.Text="HP: ";
					hp.Max=w->maximumHP();
					hp.Value=w->HP();

					organizer<<hpl<<hp<<organizer.nextline;
				}
				else if(dynamic_cast<mechanics::Den*>(selected)) {
					auto d=dynamic_cast<mechanics::Den*>(selected);

					name.Text="  "+d->provider().ID;
					name.Icon=gge::widgets::WR.Icons("den");

					type.Text="Den";

					hpl.Text="HP: ";
					hp.Max=d->maximumHP();
					hp.Value=d->HP();

					organizer<<hpl<<hp<<organizer.nextline;
				}
				else {
					minimize();
					name="";
					type="";
				}


			}

			Focus();
			Reorganize();
		}

		void minimize() {
			SetY(gge::widgets::TopLevel.GetHeight()-30);
			minimized=true;
		}

		void restore() {
			SetY(gge::widgets::TopLevel.GetHeight()-GetHeight()+10);
			minimized=false;
		}

		~Infopanel() {
			RemoveOrganizer();
		}


	protected:
		gge::widgets::LinearOrganizer organizer;
		gge::widgets::Label name, type, info;

		gge::widgets::Button hireSoldier, hireArtisan;
		gge::widgets::Label hireSoldierl, hireArtisanl;
		gge::widgets::Button destroyTB;
		gge::widgets::Button openInventory;

		gge::widgets::Label hpl,staminal;
		gge::widgets::Progressbar<float> hp, stamina;

		mechanics::Object *selected;

		gge::widgets::Button craft;
		gge::widgets::Label craftl;

		gge::widgets::Progressbar<int> craftprog;
		gge::widgets::Label craftitem;


		Inventory inventory;

		ArtisanChooser artisanChooser;

		CraftingList craftingList;

		bool userminimized;
		bool minimized;
	};

}