#include "Crawler.h"
#include "MenuComponent.h"
#include "DEFINES.h"
#include "safemap.h"
#include "Item.h"
#include "MenuItemButton.h"
#include "ScrollableWindowComponent.h"

bool Menu::MOUSE_NAVIGATION=true;
std::vector<Menu*>Menu::stack;
std::map<MenuType,Menu*>Menu::menus;
std::string Menu::themeSelection="BlueDefault";
safeunorderedmap<std::string,Theme>Menu::themes;
safemap<ITCategory,std::vector<MenuComponent*>>Menu::inventoryListeners;
const vf2d Menu::CENTERED = {-456,-456};
std::vector<MenuComponent*>Menu::unhandledComponents;
//////////////////////////////////////////////////////////////////////////////////////////////////
///__/////////////////////////////////////////////////////////////////////////////////////////////
//|  |////////////////////////////////////////////////////////////////////////////////////////////
//|  |/////WARNING! If you are adding something here you likely are adding another container with MenuComponent pointers in it right now.
//|  |/////Because we are handling raw pointers, you must also add this container to the list of iterating search removal containers that occur in the
//|  |/////DESTRUCTOR of MenuComponents!!!!! (Go to MenuComponent::~MenuComponent()) THIS IS NOT A DRILL! 
//|__|////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
///__/////////////////////////////////////////////////////////////////////////////////////////////
//|__/////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
MenuType Menu::lastMenuTypeCreated;
std::string Menu::lastRegisteredComponent;
bool Menu::cover;

INCLUDE_GFX
extern vi2d WINDOW_SIZE;

typedef Attribute A;

Menu::Menu(vf2d pos,vf2d size)
	:pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){
	r.Create(size.x,size.y);
	overlay.Create(WINDOW_SIZE.x,WINDOW_SIZE.y);
}

Menu::~Menu(){
	for(auto key:components){
		delete key.second;
	}
}

void Menu::InitializeMenus(){
	stack.reserve(32);
	InitializeTestMenu();
	InitializeTestSubMenu();
	InitializeInventoryWindow();
	InitializeClassSelectionWindow();
	InitializeClassInfoWindow();
	InitializeMainMenuWindow();
	InitializeOverworldMapLevelWindow();

	for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){
		if(menus.count(type)==0){
			ERR("WARNING! Menu Type "<<type<<" does not exist!")
		}
		//Lock up everything once it's done.
		menus[type]->buttons.SetInitialized();
		menus[type]->keyboardButtons.SetInitialized();
		for(auto&key:menus[type]->components){
			MenuComponent*component=key.second;
			component->AfterCreate();
		}
	}

	if(Menu::unhandledComponents.size()>0){
		std::cout<<"WARNING! There are "<<Menu::unhandledComponents.size()<<" components that were not added to any Menu! These have been leaked and should not be happening!"<<std::endl;
		std::cout<<"See below for a report of unhandled components:"<<std::endl;
		int count=0;
		for(MenuComponent*component:Menu::unhandledComponents){
			std::cout<<"\tComponent "<<(count+1)<<": "<<std::endl;
			std::cout<<"\t-Parent Menu:"<<component->parentMenu<<" Label: "<<component->label<<std::endl;
			std::cout<<"\t\tCreated Inside of Menu: "<<component->memoryLeakInfo.first<<" // Last Component: "<<component->memoryLeakInfo.second<<std::endl;
			count++;
		}
		ERR("")
	}
}

Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
	menus[type]=NEW Menu(pos,size);
	lastMenuTypeCreated=type;
	return menus.at(type);
}

void Menu::AddComponent(std::string key,MenuComponent*button){
	if(button->selectable){
		buttons.Unlock();
		if(buttons.count(button->rect.pos.y)){
			buttons.at(button->rect.pos.y).push_back(button);
		}else{
			buttons[button->rect.pos.y].push_back(button);
		}
		if(button->selectableViaKeyboard){
			keyboardButtons.Unlock();
			if(keyboardButtons.count(button->rect.pos.y)){
				keyboardButtons.at(button->rect.pos.y).push_back(button);
			}else{
				keyboardButtons[button->rect.pos.y].push_back(button);
			}
		}
		
		//We must lock the values before calling sort. Sort seems to try and create new accesses.
		buttons.SetInitialized();
		keyboardButtons.SetInitialized();

		//We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards.
		std::sort(buttons[button->rect.pos.y].begin(),buttons[button->rect.pos.y].end(),[](MenuComponent*c1,MenuComponent*c2){
			return c1->GetPos().x<c2->GetPos().x;
		});
		if(keyboardButtons.count(button->rect.pos.y)){ //Keyboard buttons may not necessarily contain this key...Let's be sure.
			std::sort(keyboardButtons[button->rect.pos.y].begin(),keyboardButtons[button->rect.pos.y].end(),[](MenuComponent*c1,MenuComponent*c2){
				return c1->GetPos().x<c2->GetPos().x;
			});
		}
	}else{
		displayComponents.push_back(button);
	}
	if(components.count(key)){
		ERR("WARNING! Key "<<key<<" for this sub-menu already exists! Key names must be unique!")
	}
	button->name=key;
	components.Unlock(); //It's possible we can add a component later on, so we will make sure we remove the lock first.
	components[key]=button;
	components.SetInitialized();
	lastRegisteredComponent=key;
	std::erase_if(Menu::unhandledComponents,[&](MenuComponent*b1){return b1==button;});
}

void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
	if(game->GetMouse(Mouse::LEFT).bReleased||game->GetKey(SPACE).bReleased||game->GetKey(ENTER).bReleased){
		MenuSelect(game);
	}
}

void Menu::HoverMenuSelect(Crawler*game){
	if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return;
	if(buttons[selection.y][selection.x]->draggable){
		if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
			CheckClickAndPerformMenuSelect(game);
		}else{
			draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem();
			buttonHoldTime=0;
		}
	}else{
		CheckClickAndPerformMenuSelect(game);
	}
}

void Menu::MenuSelect(Crawler*game){
	if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return;
	bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x]});
 	if(buttonStillValid){
		if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
			if(stack.size()<32){
				stack.push_back(menus[buttons[selection.y][selection.x]->menuDest]);//Navigate to the next menu.
			}else{
				ERR("WARNING! Exceeded menu stack size limit!")
			}
		}
	}
}

void Menu::Update(Crawler*game){
	if(draggingComponent==nullptr){
		HoverMenuSelect(game);
	}

	if(!UsingMouseNavigation()&&geom2d::line<float>(lastActiveMousePos,game->GetMousePos()).length()>="ThemeGlobal.MouseActivationDistance"_F||UsingMouseNavigation()){
		SetMouseNavigation(true);
	}

	for(auto&key:buttons){
		for(auto&button:key.second){
			if(!button->disabled){
				button->hovered=false;
			}
		}
	}

	bool itemHovered=false;

	if(!UsingMouseNavigation()){
		if(selection!=vi2d{-1,-1}){
			buttons[selection.y][selection.x]->hovered=true;
			itemHovered=true;
		}
	}else{
		selection={-1,-1};
		for(auto&key:buttons){
			int index=0;
			for(auto&button:key.second){
				if(!button->disabled){
					if(button->GetHoverState(game)){
						button->hovered=true;
						itemHovered=true;
						selection.y=key.first;
						selection.x=index;
					}
				}
				index++;
			}
		}
	}

	if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&(((!UsingMouseNavigation()&&(game->GetKey(ENTER).bHeld)||game->GetKey(SPACE).bHeld))||game->GetMouse(Mouse::LEFT).bHeld)){
		buttonHoldTime+=game->GetElapsedTime();
	}else{
		buttonHoldTime=0;
	}

	if(draggingComponent!=nullptr){
		MenuComponent*selectedComponent=nullptr;
		if(selection!=vi2d{-1,-1}){
			selectedComponent=buttons[selection.y][selection.x];
		}


		auto ClearDraggingComponent=[&](){
			delete draggingComponent; //We know we allocated a new instance of this, so we will now free it.
			draggingComponent=nullptr;
		};

		if(!UsingMouseNavigation()){
			if(game->GetKey(ENTER).bReleased||game->GetKey(SPACE).bReleased){
				if(selectedComponent==nullptr){//Dropping over an empty area.
					ClearDraggingComponent();
				}else
				if(selectedComponent->DropDraggableItem(draggingComponent)){
					ClearDraggingComponent();
				}
			}
		}else{
			if(game->GetMouse(Mouse::LEFT).bReleased){
				if(selectedComponent==nullptr){//Dropping over an empty area.
					ClearDraggingComponent();
				}else
				if(selectedComponent->DropDraggableItem(draggingComponent)){
					ClearDraggingComponent();
				}
			}
		}
	}

	KeyboardButtonNavigation(game,pos);
	for(auto&key:buttons){
		for(auto&button:key.second){
			if(button->renderInMain){
				button->_Update(game);
			}
		}
	}
	for(auto&component:displayComponents){
		if(component->renderInMain){
			component->_Update(game);
		}
	}
};

void Menu::Draw(Crawler*game){
	if(GetCurrentTheme().IsScaled()){
		DrawScaledWindowBackground(game,pos);
	}else{
		DrawTiledWindowBackground(game,pos);
	}

	game->SetDrawTarget(r.Sprite());
	Pixel::Mode prevMode=game->GetPixelMode();
	game->SetPixelMode(Pixel::MASK);
	game->Clear(BLANK);
	for(auto&component:displayComponents){
		if(component->renderInMain){
			component->_Draw(game);
		}
	}
	for(auto&key:buttons){
		for(auto&button:key.second){
			if(button->renderInMain){
				button->_Draw(game);
			}
		}
	}
	game->SetPixelMode(prevMode);
	game->SetDrawTarget(nullptr);
	r.Decal()->Update();
	game->DrawDecal(pos,r.Decal());
	for(auto&component:displayComponents){
		if(component->renderInMain){
			component->_DrawDecal(game,this==Menu::stack.back());
		}
	}
	for(auto&key:buttons){
		for(auto&button:key.second){
			if(button->renderInMain){
				button->_DrawDecal(game,this==Menu::stack.back());
			}
		}
	}

	if(GetCurrentTheme().IsScaled()){
		DrawScaledWindowBorder(game,pos);
	}else{
		DrawTiledWindowBorder(game,pos);
	}

	if(draggingComponent!=nullptr){
		game->SetDrawTarget(overlay.Sprite());
		Pixel::Mode prevMode=game->GetPixelMode();
		game->SetPixelMode(Pixel::MASK);
		game->Clear(BLANK);
		vf2d offsetPos=draggingComponent->rect.pos;
		if(!UsingMouseNavigation()){
			MenuComponent*selectedComponent=buttons[selection.y][selection.x];
			vf2d drawOffset{};
			if(selectedComponent->parentComponent!=nullptr){
				drawOffset+=selectedComponent->parentComponent->V(A::SCROLL_OFFSET);
			}
			draggingComponent->Draw(game,drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4});
		}else{
			draggingComponent->Draw(game,-offsetPos+game->GetMousePos());
		}
		game->SetPixelMode(prevMode);
		game->SetDrawTarget(nullptr);
		overlay.Decal()->Update();
		game->DrawDecal({0,0},overlay.Decal(),{1,1},this==Menu::stack.back()?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
		if(!UsingMouseNavigation()){
			MenuComponent*selectedComponent=buttons[selection.y][selection.x];
			vf2d drawOffset{};
			if(selectedComponent->parentComponent!=nullptr){
				drawOffset+=selectedComponent->parentComponent->V(A::SCROLL_OFFSET);
			}
			draggingComponent->DrawDecal(game,drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4},this==Menu::stack.back());
		}else{
			draggingComponent->DrawDecal(game,-offsetPos+game->GetMousePos(),this==Menu::stack.back());
		}
	}
};

void Menu::OpenMenu(MenuType menu,bool cover){
	Menu::cover=cover;
	stack.clear();
	stack.push_back(menus[menu]);
}

void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
	vi2d prevSelection=selection;
	if(game->GetKey(RIGHT).bPressed){
		if(selection==vi2d{-1,-1})return;
		SetMouseNavigation(false);
		selection.x=(size_t(selection.x)+1)%keyboardButtons[selection.y].size();
	}
	if(game->GetKey(LEFT).bPressed){
		if(selection==vi2d{-1,-1})return;
		selection.x--;
		SetMouseNavigation(false);
		if(selection.x<0)selection.x+=keyboardButtons[selection.y].size();
	}
	if(game->GetKey(DOWN).bPressed||game->GetKey(UP).bPressed){
		if(game->GetKey(DOWN).bPressed){
			SetMouseNavigation(false);
			bool found=false;
			bool selectedItem=false;
			if(selection==vi2d{-1,-1}){
				//Highlight first item.
				for(auto&key:keyboardButtons){
					selection.y=key.first;
					break;
				}
			}else{
				for(auto&key:keyboardButtons){
					if(found){ //Once we discover the previous element, the next element becomes our next selection.
						int previousButtonX=keyboardButtons[selection.y][selection.x]->rect.pos.x;
						selection.y=key.first;
						int index=0;
						for(auto&button:key.second){ //Try to match a button in the same column as this button first.
							if(previousButtonX==button->rect.pos.x){
								selection.x=index;
								break;
							}
							index++;
						}
						selectedItem=true;
						break;
					}
					if(key.first==selection.y
						//It's entirely possible this button was selected from the button selection list and may be out-of-bounds here.
						&&selection.x>=0&&selection.x<keyboardButtons[selection.y].size()){
						found=true;
					}
				}
				if(!selectedItem){ //This means we need to loop around instead and pick the first one.
					for(auto&key:keyboardButtons){
						selection.y=key.first;
						break;
					}
				}
			}
		}
		if(game->GetKey(UP).bPressed){
			SetMouseNavigation(false);
			if(selection==vi2d{-1,-1}){
				//Highlight last item.
				for(auto&key:keyboardButtons){
					selection.y=key.first;
				}
			}else{
				int prevInd=-1;
				for(auto&key:keyboardButtons){
					if(key.first==selection.y&&
						//It's entirely possible this button was selected from the button selection list and may be out-of-bounds here.
						selection.x>=0&&selection.x<keyboardButtons[selection.y].size()){
						break;
					}
					prevInd=key.first;
				}
				if(prevInd!=-1){
					int previousButtonX=keyboardButtons[selection.y][selection.x]->rect.pos.x;
					selection.y=prevInd;
					int index=0;
					for(auto&button:keyboardButtons[prevInd]){ //Try to match a button in the same column as this button first.
						if(previousButtonX==button->rect.pos.x){
							selection.x=index;
							break;
						}
						index++;
					}
				}else{ //Since we didn't find it, it means we're at the top of the list or the list is empty. Go to the last element and use that one.
					int lastInd=-1;
					for(auto&key:keyboardButtons){
						lastInd=key.first;
					}
					selection.y=lastInd;
				}
			}
		}
		//In both cases, we should clamp the X index to make sure it's still valid.
		if(selection.y!=-1){
			selection.x=std::clamp(selection.x,0,int(keyboardButtons[selection.y].size())-1);
		}else{
			selection.x=-1;
		}
	}
	if(game->GetMouse(0).bPressed||game->GetKey(ENTER).bPressed||game->GetKey(SPACE).bPressed){
		SetMouseNavigation(game->GetMouse(0).bPressed); //If a click occurs we use mouse controls.
		if(!UsingMouseNavigation()){
			buttonHoldTime=0;
			//Key presses automatically highlight the first button if it's not highlighted.
			if(selection==vi2d{-1,-1}&&buttons.size()>0){
				//Find the first possible button entry in the map...
				int firstInd=-1;
				for(auto&key:buttons){
					if(buttons[key.first].size()>0){
						firstInd=key.first;
						break;
					}
				}
				if(firstInd!=-1){ //This means we found a valid menu item. If we didn't find one don't highlight any menu item...
					selection={0,firstInd};
				}
			}
		}else{//Mouse click.
			selection={-1,-1};
			for(auto&key:buttons){
				int index=0;
				for(auto&button:key.second){
					if(!button->disabled){
						if(geom2d::overlaps(geom2d::rect<float>{button->rect.pos+menuPos,button->rect.size},game->GetMousePos())){
							selection={index,key.first};
							break;
						}
					}
					index++;
				}
			}
			buttonHoldTime=0;
		}
	}
	if(prevSelection!=selection){
		if(selection!=vi2d{-1,-1}&&buttons[selection.y][selection.x]->disabled){
			bool handled=false;
			if(!UsingMouseNavigation()){
				//Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead.
				//If we return false, then we handled it ourselves, no need to go back to the previous selection.
				if(HandleOutsideDisabledButtonSelection(buttons[selection.y][selection.x])){
					handled=true;
				}
			}
			if(!handled){
				// If the new selection of a button on this frame is disabled for some reason and we didn't handle it, we need to go back to what we had selected before.
				selection=prevSelection; 
			}
		}
	}
}

void Menu::DrawScaledWindowBorder(Crawler*game,vf2d menuPos){
	vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};

	//Upper-Left
	game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{patchSize.x*0,patchSize.y*0},patchSize,GetRenderColor());
	//Upper-Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{patchSize.x*2,patchSize.y*0},patchSize,GetRenderColor());
	//Bottom-Left
	game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{patchSize.x*0,patchSize.y*2},patchSize,GetRenderColor());
	//Bottom-Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{patchSize.x*2,patchSize.y*2},patchSize,GetRenderColor());
	//Top
	game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{patchSize.x*1,patchSize.y*0},patchSize,GetRenderColor());
	//Left
	game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{patchSize.x*0,patchSize.y*1},patchSize,GetRenderColor());
	//Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{patchSize.x*2,patchSize.y*1},patchSize,GetRenderColor());
	//Bottom
	game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{patchSize.x*1,patchSize.y*2},patchSize,GetRenderColor());
}

void Menu::DrawTiledWindowBorder(Crawler*game,vf2d menuPos){
	vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};

	//Upper-Left
	game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{0,0},patchSize,GetRenderColor());
	//Upper-Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{0,0},patchSize,GetRenderColor());
	//Bottom-Left
	game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{0,0},patchSize,GetRenderColor());
	//Bottom-Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{0,0},patchSize,GetRenderColor());
	//Top
	game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{0,0},vf2d{size.x,patchSize.y},GetRenderColor());
	//Left
	game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{0,0},vf2d{patchSize.x,size.y},GetRenderColor());
	//Right
	game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{0,0},vf2d{patchSize.x,size.y},GetRenderColor());
	//Bottom
	game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{0,0},vf2d{size.x,patchSize.y},GetRenderColor());
}

void Menu::DrawScaledWindowBackground(Crawler*game,vf2d menuPos){
	vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};

	//Center
	if(GetCurrentTheme().HasBackground()){
		Decal*back=GetCurrentTheme().GetBackground();
		game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size(),GetRenderColor());
	}else{
		game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize,GetRenderColor());
	}
}

void Menu::DrawTiledWindowBackground(Crawler*game,vf2d menuPos){
	vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};

	//Center
	if(GetCurrentTheme().HasBackground()){
		Decal*back=GetCurrentTheme().GetBackground();
		game->DrawPartialDecal(menuPos,size,back,{0,0},size,GetRenderColor());
	}else{
		game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{0,0},patchSize,GetRenderColor());
	}
}

Renderable&Menu::GetPatchPart(int x,int y){
	return GFX[themeSelection+"_"+std::to_string(x)+std::to_string(y)+".png"];
}

Theme&Menu::GetCurrentTheme(){
	return themes[themeSelection];
}

Pixel Menu::GetRenderColor(){
	bool focused=Menu::stack.back()==this;
	Pixel col=WHITE;
	if(!focused){
		col=WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F;
	}
	return col;
}

bool Menu::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){
	if(disabledButton->parentComponent!=nullptr){
		return disabledButton->parentComponent->HandleOutsideDisabledButtonSelection(disabledButton);
	}else{
		return false;
	}
}


bool Menu::UsingMouseNavigation(){
	return MOUSE_NAVIGATION;
};
void Menu::SetMouseNavigation(bool mouseNavigation){
	if(MOUSE_NAVIGATION&&!mouseNavigation){
		//When mouse navigation was enabled and now needs to be disabled, we store the mouse position.
		INCLUDE_game
		lastActiveMousePos=game->GetMousePos();
	}
	MOUSE_NAVIGATION=mouseNavigation;
};

void Menu::InventorySlotsUpdated(ITCategory cat){
	//Update the inventory with a new inventory slot, since there's one additional item to interact with now.
	std::vector<std::string>&inv=Inventory::get(cat);
	for(MenuComponent*component:inventoryListeners.at(cat)){
		component->OnInventorySlotsUpdate(cat);
	}
}

void Menu::AddInventoryListener(MenuComponent*component,ITCategory category){
	if(inventoryListeners.count(category)){
		std::vector<MenuComponent*>&listenerList=inventoryListeners.at(category);
		if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){
			ERR("WARNING! Component "<<component->name<<" has already been added to the "<<category<<" listener list! There should not be any duplicates!!")
		}
		listenerList.push_back(component);
	}else{
		ERR("WARNING! Inventory category "<<category<<" does not exist!")
	}
}

vf2d Menu::center(){
	return size/2;
}

void Menu::CloseMenu(){
	if(stack.size()>0){
		stack.pop_back();
	}else{
		ERR("WARNING! Trying to close out no menu?? Why are we doing this?")
	}
}

std::pair<MenuType,std::string>Menu::GetMemoryLeakReportInfo(){
	return {lastMenuTypeCreated,lastRegisteredComponent};
}

void Menu::CloseAllMenus(){
	if(stack.size()>0){
		stack.clear();
	}else{
		ERR("WARNING! Trying to close out no menu?? Why are we doing this?")
	}
}

bool Menu::IsMenuOpen(){
	return stack.size()>0;
}

void Menu::CleanupAllMenus(){
	for(auto key:Menu::menus){
		Menu*menu=key.second;
		for(auto componentKey:menu->components){
			MenuComponent*component=componentKey.second;
			component->Cleanup();
			delete component;
		}
		menu->components.Reset();
		menu->Cleanup();
		delete menu;
	}
	Menu::menus.clear();
}

void Menu::Cleanup(){}