namespace BP
{
	namespace UI
	{
		//UI Elements (x, y, z(depth add), normal texture id):
		//normal/selected/active/disabled
		
		funcdef void ElementStateChangeCallBack();

		const int ELEMENT_STATE_NORMAL = 0;
		const int ELEMENT_STATE_SELECTED = 1;
		const int ELEMENT_STATE_ACTIVE = 2;
		const int ELEMENT_STATE_DISABLED = 3;
		const int ELEMENT_STATES = 4;
		
		const int ELEMENT_DIR_UP = 0;
		const int ELEMENT_DIR_RIGHT = 1;
		const int ELEMENT_DIR_DOWN = 2;
		const int ELEMENT_DIR_LEFT = 3;
		const int ELEMENT_NAV_DIRECTIONS = 4;
		
		class Element
		{
			int id;
			kActor @actor;
			kVec3 position;
			Rect bounds;
			float depth;
			int state = ELEMENT_STATE_NORMAL;
			ElementStateChangeCallBack @onNormal;
			ElementStateChangeCallBack @onSelect;
			ElementStateChangeCallBack @onActive;
			ElementStateChangeCallBack @onDisable;
			array<int> stateTextureIDs(ELEMENT_STATES);
			array<int> navElementIDs(ELEMENT_NAV_DIRECTIONS);
			int pixelWidth; //not needed
			int pixelHeight; //not needed
			bool isButton;
			bool isActivated;
			bool isDisabled;
			//------------------------------------------------------------------------------------------------------------------------
			Element()
			{
				
			}
			//------------------------------------------------------------------------------------------------------------------------
			Element(int id, int pixelWidth, int pixelHeight, Rect& in bounds, float depth, array<int> stateTextureIDs, array<int> navElementIDs)
			{
				this.id = id;
				this.pixelWidth = pixelWidth;
				this.pixelHeight = pixelHeight;
				this.bounds = bounds;
				position = bounds.Center();
				this.depth = BP::UI::UI_DEPTH + depth;
				
				int stateTextureIDsLength = int(stateTextureIDs.length());
				for (int i = 0; i < ELEMENT_STATES; i++)
				{
					if (i >= stateTextureIDsLength)
					{
						break;
					}
					this.stateTextureIDs[i] = stateTextureIDs[i];
				}
				
				int navElementIDsLength = int(navElementIDs.length());
				for (int i = 0; i < ELEMENT_NAV_DIRECTIONS; i++)
				{
					if (i >= navElementIDsLength)
					{
						break;
					}
					this.navElementIDs[i] = navElementIDs[i];
				}
				
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnTick()
			{
				//90 fov = 0.0f;
				//100 fov = 0.95
				//110 fov = 1.9; ?
				
				
				//90 / 110 = 0.81818181818181818181818181818182
				//0.81818181818181818181818181818182 * 4.4f = 3.6
				//3.6/2
				
				// float mouseDepth = 4.4f + 0.8f;
				
				
				
				// float pixelWidth = 64;
				// float pixelHeight = 64;
				
				// float widthRatio = (pixelWidth / UI_PIXEL_WIDTH);
				// float heightRatio = widthRatio * (float(pixelHeight) / pixelWidth);
				
				// //BP::Game::GetFOV();
				
				// //90 is normal fov, bigger fov shrinks it
				
				// bounds.SetSize(widthRatio, heightRatio);
				actor.Scale() = (kVec3(bounds.width, 1.0f, bounds.height) * UI_ELEMENT_BASESIZE) * BP::UI::elementScale;

				float xySize = depth * BP::UI::elementXYScale;
				
				actor.Origin() = (BP::UI::playerPos + BP::UI::playerForwardDir * (depth * BP::UI::heightRatio)) +
									((BP::UI::playerRightDir * (xySize * 2.0f)) * position.x - (BP::UI::playerRightDir * xySize));
				actor.Origin().z += ((xySize * 2.0f) * BP::UI::heightRatio) * (1.0f - position.z) - (xySize * BP::UI::heightRatio);
				actor.Yaw() = BP::UI::uiYaw;
				//Set Position
			}
			//------------------------------------------------------------------------------------------------------------------------
			void Destroy()
			{
				if (BP::Actor::Exists(@actor))
				{
					actor.Remove();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			int GetNavElementID(int direction)
			{
				return navElementIDs[direction];
			}
			//------------------------------------------------------------------------------------------------------------------------
			void SetTexture(int textureID)
			{
				DebugAssert(@actor != null, "[BP::UI::Element::SetTexture] actor is null");
				DebugAssert(actor.RenderMeshComponent() !is null, "[BP::UI::Element::SetTexture] actor does not have a RenderMeshComponent");
				actor.RenderMeshComponent().AltTexture() = textureID;
			}
			//------------------------------------------------------------------------------------------------------------------------
			// Is Position over this element
			//------------------------------------------------------------------------------------------------------------------------
			bool IsOver(const kVec3 &in p)
			{
				// float xySize = depth * BP::UI::elementXYScale;
				
				// float sizeX = actor.Scale().x * (xySize * 2.0f);
				// if (p.x >= actor.Origin().x - sizeX && p.x <= actor.Origin().x + sizeX)
				// {
					// return true;
				// }				
				// return false;
				
				//Rect tBounds = bounds;
				//tBounds.SetSize(tBounds.width * BP::UI::elementScale.x, tBounds.height * BP::UI::elementScale.z);
				// tBounds.width *= BP::UI::elementScale.x;
				// tBounds.height *= BP::UI::elementScale.z;
				return bounds.ContainsPoint(p);
			}
			//------------------------------------------------------------------------------------------------------------------------
			void SetToNormal()
			{
				if (isDisabled)
				{
					OnDisable();
				}
				else if (isActivated)
				{
					OnActive();
				}
				else
				{
					OnNormal();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnNormal()
			{
				SetTexture(stateTextureIDs[ELEMENT_STATE_NORMAL]);
				if (@onNormal != null)
				{
					onNormal();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnSelect()
			{
				SetTexture(stateTextureIDs[ELEMENT_STATE_SELECTED]);
				if (@onSelect != null)
				{
					onSelect();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnActive()
			{
				SetTexture(stateTextureIDs[ELEMENT_STATE_ACTIVE]);
				isActivated = true;
				if (@onActive != null)
				{
					onActive();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnDeactive()
			{
				isActivated = false;
				SetTexture(stateTextureIDs[ELEMENT_STATE_NORMAL]);
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnDisable()
			{
				SetTexture(stateTextureIDs[ELEMENT_STATE_DISABLED]);
				if (@onDisable != null)
				{
					onDisable();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
		};
	}
}
