namespace BP
{
	namespace UI
	{
		const int WINDOWSTATE_OPEN = 0;
		const int WINDOWSTATE_CLOSED = 1;
		const int WINDOWSTATE_OPENING = 2;
		const int WINDOWSTATE_CLOSING = 3;

		class Window
		{
			int id;
			int state = WINDOWSTATE_CLOSED;
			float stateChangeTime = 0;
			Element@ selectedItem;
			array<Element@> items;
			//window should have depth
			//------------------------------------------------------------------------------------------------------------------------
			Window(int id)
			{
				this.id = id;
			}
			//------------------------------------------------------------------------------------------------------------------------
			Element@ AddButton(int id, int x, int y, int width, int height, float depth, int normalTexID, int selectTexID, array<int> navElementIDs)
			{
				Element@ element = AddItem(id, x, y, width, height, depth, normalTexID, selectTexID, navElementIDs);
				element.isButton = true;
				return @element;
			}
			//------------------------------------------------------------------------------------------------------------------------
			Element@ AddImage(int id, int x, int y, int width, int height, float depth, int normalTexID, int selectTexID, array<int> navElementIDs)
			{
				Element@ element = AddItem(id, x, y, width, height, depth, normalTexID, selectTexID, navElementIDs);
				element.isButton = false;
				return @element;
			}
			//------------------------------------------------------------------------------------------------------------------------
			private Element@ AddItem(int id, int x, int y, int width, int height, float depth, int normalTexID, int selectTexID, array<int> navElementIDs)
			{
				//depth pos offset
				float posScale = UI_DEPTH / (UI_DEPTH + depth);
				float posOffset = (1.0f - posScale) * 0.5f;
				
				//pos based on ui size
				float xRatio = ((x / UI_PIXEL_WIDTH) * posScale) + posOffset;
				float yRatio = ((y / UI_PIXEL_HEIGHT) * posScale) + posOffset;
				
				//size based on ui size
				float widthRatio = (width / UI_PIXEL_WIDTH);// * BP::UI::elementScale.x;
				float heightRatio = (widthRatio * (float(height) / width));// * BP::UI::elementScale.z;
				Rect bounds(xRatio, yRatio, widthRatio, heightRatio);
				
				Element item(id, width, height, bounds, depth, array<int> = {normalTexID, selectTexID, selectTexID, normalTexID}, navElementIDs);
				@item.actor = BP::Spawn::Actor(kActor_UIElement, Math::vecZero);
				item.actor.Scale() = (kVec3(widthRatio, 1.0f, heightRatio) * UI_ELEMENT_BASESIZE) * BP::UI::elementScale;
				item.isButton = true;
				item.SetToNormal();
				items.insertLast(@item);
				return @item;
			}
			//------------------------------------------------------------------------------------------------------------------------
			//position and size is in pixels (from top left)
			
			//elementWidth (In pixels) / ui width (In pixels)
			//elementWidthRatio = 64 / 960
			//UI_ELEMENT_BASESIZE * elementWidthRatio = element Scale/width
				
			//UI_BASE_WIDTH_RATIO
			
			Element AddItem(int id, int x, int y, int width, int height, float depth, array<int> stateTextureIDs, array<int> navElementIDs)
			{
				//depth pos offset
				float posScale = UI_DEPTH / (UI_DEPTH + depth);
				float posOffset = (1.0f - posScale) * 0.5f;
				
				//pos based on ui size
				float xRatio = ((x / UI_PIXEL_WIDTH) * posScale) + posOffset;
				float yRatio = ((y / UI_PIXEL_HEIGHT) * posScale) + posOffset;
				
				//size based on ui size
				float widthRatio = (width / UI_PIXEL_WIDTH);// * BP::UI::elementScale.x;
				float heightRatio = (widthRatio * (float(height) / width));// * BP::UI::elementScale.z;
				Rect bounds(xRatio, yRatio, widthRatio, heightRatio);
				
				Element item(id, width, height, bounds, depth, stateTextureIDs, navElementIDs);
				@item.actor = BP::Spawn::Actor(kActor_UIElement, Math::vecZero);
				item.actor.Scale() = (kVec3(widthRatio, 1.0f, heightRatio) * UI_ELEMENT_BASESIZE) * BP::UI::elementScale;
				item.SetToNormal();
				// item.actor.Scale() = (kVec3(UI_ELEMENT_BASESIZE, UI_ELEMENT_BASESIZE, UI_ELEMENT_BASESIZE) + scale) * BP::UI::elementScale;
				//set callbacks
				// @item.onNormal = @onNormal;

				// float widthRatio = (width / UI_PIXEL_WIDTH);
				// float heightRatio = widthRatio * (float(height) / width);
				// Rect bounds(xRatio, yRatio, widthRatio, heightRatio);
				// item.actor.Scale() = (kVec3(widthRatio, 1.0f, heightRatio) * UI_ELEMENT_BASESIZE) * BP::UI::elementScale;


				
				items.insertLast(@item);
				
				return item;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void Destroy()
			{
				int itemsLength = int(items.length());
				for (int i = 0; i < itemsLength; i++)
				{
					Element @item = items[i];
					if (@item != null)
					{
						item.Destroy();
					}
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void Open()
			{
				if (IsClosed())
				{
					state = WINDOWSTATE_OPENING;
					SetSelectedItem(items[0]); //should be set to starting item
					stateChangeTime = 0.0f;
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void Close()
			{
				if (IsOpen())
				{
					state = WINDOWSTATE_CLOSING;
					stateChangeTime = 0.0f;
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool IsOpen()
			{
				return state == WINDOWSTATE_OPEN;
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool IsClosed()
			{
				return state == WINDOWSTATE_CLOSED;
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool IsOpening()
			{
				return state == WINDOWSTATE_OPENING;
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool IsClosing()
			{
				return state == WINDOWSTATE_CLOSING;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void NavigateSelect(int direction)
			{
				if (@selectedItem != null)
				{
					int elementID = selectedItem.GetNavElementID(direction);
					int itemsLength = int(items.length());
					for (int i = 0; i < itemsLength; i++)
					{
						Element @item = items[i];
						if (item.id == elementID)
						{
							SetSelectedItem(@item);
							break;
						}
					}
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void SetSelectedItem(Element@ item)
			{
				if (@selectedItem != null)
				{
					selectedItem.SetToNormal();
				}
				@selectedItem = @item;
				selectedItem.OnSelect();
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnTick()
			{
				//update closing/opening
				if (IsOpening())
				{
					stateChangeTime -= GAME_DELTA_TIME;
					if (stateChangeTime <= 0)
					{
						state = WINDOWSTATE_OPEN;
					}
				}
				else if (IsClosing())
				{
					stateChangeTime -= GAME_DELTA_TIME;
					if (stateChangeTime <= 0)
					{
						state = WINDOWSTATE_CLOSED;
					}
				}
				
				int itemsLength = int(items.length());
				for (int i = 0; i < itemsLength; i++)
				{
					items[i].OnTick();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnTickActive()
			{
				//input
				if (IsOpen())
				{
					//update mouse over item
					if (BP::UI::mouseMoved)
					{
						int itemsLength = int(items.length());
						for (int i = 0; i < itemsLength; i++)
						{
							Element @item = items[i];
							
							// if (item.id == 1)
							// {
								// DebugLog("Mouse: " + BP::UI::mousePosition.ToString() + " Over = " + item.IsOver(BP::UI::mousePosition) + " Bounds = " + item.bounds.ToString());
							// }
							
							if (item.isButton && item.IsOver(BP::UI::mousePosition))
							{
								if (@selectedItem != @item)
								{
									SetSelectedItem(@item);
								}
								break;
							}
						}
					}

					if (BP::Input::ForwardDown())
					{
						NavigateSelect(ELEMENT_DIR_UP);
					}
					else if (BP::Input::BackwardDown())
					{
						NavigateSelect(ELEMENT_DIR_DOWN);
					}
					else if (BP::Input::StrafeRightDown())
					{
						NavigateSelect(ELEMENT_DIR_RIGHT);
					}
					else if (BP::Input::StrafeLeftDown())
					{
						NavigateSelect(ELEMENT_DIR_LEFT);
					}
					else if (BP::Input::AttackDown() || BP::Input::AltFireDown() || BP::Input::JumpDown())
					{
						if (@selectedItem != null)
						{
							selectedItem.OnActive();
						}
					}
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
		};
	}
}
