using UnityEngine;
using System;
using Me.StefS.Utility;

namespace Me.StefS.UnityUtility.UI{
	public class HudController : MonoBehaviour {
		#region Serialized Fields
		[SerializeField]
		private Camera mainCamera;

		[SerializeField]
		private int hudDesignedAspectX;

		[SerializeField]
		private int hudDesignedAspectY;

		[SerializeField]
		private GameObject centeredReferenceGameObject;
		#endregion

		#region other private fields
		private GameObject[] anchorMap;
		private Vector3[] anchorToIntendedPositionMap;
		#endregion

		#region properties
		public Camera MainCamera {
			get {
				return mainCamera;
			}
		}
		#endregion

		#region Public API
		public void Initialize ()
		{
			this.SetAnchors ();
		}
		#endregion

		#region private helper methods
		private void SetAnchors(){
			this.anchorMap = new GameObject[Enum.GetValues (typeof(Anchor)).Length];
			this.anchorToIntendedPositionMap = new Vector3[this.anchorMap.Length];
			float zDistance = this.mainCamera.transform.position.VectorTo(
				this.centeredReferenceGameObject.transform.position).magnitude;
			for (int anchorIndex = 0; anchorIndex < this.anchorMap.Length; anchorIndex++) {
				GameObject anchorGameObject = new GameObject (((Anchor)anchorIndex).ToString());
				anchorGameObject.transform.parent = this.transform;
				Vector3 anchorPosition;
				Vector3 anchorIntendedPosition;
				float designedWidth = (this.mainCamera.pixelHeight * hudDesignedAspectX) / hudDesignedAspectY;
				float centerWidth = this.mainCamera.pixelWidth / 2f;
				switch ((Anchor)anchorIndex) {
				case  Anchor.Center:
				case Anchor.None:
					anchorPosition = new Vector3 (
						centerWidth,
						this.mainCamera.pixelHeight / 2f,
						zDistance);
					anchorIntendedPosition = anchorPosition;
					break;
				case Anchor.Left:
					anchorPosition = new Vector3 (
						centerWidth - (designedWidth /2f),
						this.mainCamera.pixelHeight / 2f,
						zDistance);
					anchorIntendedPosition = new Vector3 (
						0,
						this.mainCamera.pixelHeight / 2f,
						zDistance);
					break;
				case Anchor.Right:
					anchorPosition = new Vector3 (
						centerWidth + (designedWidth /2f),
						this.mainCamera.pixelHeight / 2f,
						zDistance);
					anchorIntendedPosition  = new Vector3 (
						this.mainCamera.pixelWidth,
						this.mainCamera.pixelHeight / 2f,
						zDistance);
					break;
				default:
					throw new InvalidOperationException ("all cases should have been set");
					break;
				}

				anchorGameObject.transform.position = this.mainCamera.ScreenToWorldPoint(anchorPosition);
				this.anchorMap[anchorIndex] = anchorGameObject;
				this.anchorToIntendedPositionMap [anchorIndex] = this.mainCamera.ScreenToWorldPoint(anchorIntendedPosition);
			}

			HudElement[] children = this.GetComponentsInChildren<HudElement> (true);
			for (int hudChildIndex = 0; hudChildIndex < children.Length; hudChildIndex++) {
				HudElement element = children [hudChildIndex];
				if (element.gameObject.transform.parent != this.transform) {
					throw new InvalidProgramException ("Only first level children of the hud should be hud elements");
				}

				element.gameObject.transform.parent = this.anchorMap [(int)element.Anchor].transform;
			}

			for (int anchorIndex = 0; anchorIndex < this.anchorMap.Length; anchorIndex++) {
				this.anchorMap [anchorIndex].transform.position = this.anchorToIntendedPositionMap [anchorIndex];
			}
		}
		#endregion
	}
}