using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Cryville.Common.Unity.UI {
	/// <summary>
	/// A <see cref="ILayoutElement" /> that takes the length of one axis to compute the preferred length of the other axis with respect to a aspect ratio.
	/// </summary>
	[AddComponentMenu("Layout/Aspect Ratio Layout Element")]
	[ExecuteAlways]
	public class AspectRatioLayoutElement : UIBehaviour, ILayoutElement {
		[SerializeField]
		[Tooltip("The aspect ratio. Width divided by height.")]
		private float m_aspectRatio = 1;
		/// <summary>
		/// The aspect ratio. Width divided by height.
		/// </summary>
		public float AspectRatio {
			get { return m_aspectRatio; }
			set { SetProperty(ref m_aspectRatio, value); }
		}

		[SerializeField]
		[Tooltip("Whether to compute the length of the y axis.")]
		private bool m_isVertical = false;
		/// <summary>
		/// Whether to compute the length of the y axis.
		/// </summary>
		public bool IsVertical {
			get { return m_isVertical; }
			set { SetProperty(ref m_isVertical, value); }
		}

		private void SetProperty<T>(ref T prop, T value) {
			if (Equals(prop, value)) return;
			prop = value;
			SetDirty();
		}

		/// <inheritdoc />
		public float minWidth {
			get {
				return m_isVertical ? -1 : (transform as RectTransform).rect.height * m_aspectRatio;
			}
		}
		/// <inheritdoc />
		public float preferredWidth { get { return minWidth; } }
		/// <inheritdoc />
		public float flexibleWidth { get { return -1; } }

		/// <inheritdoc />
		public float minHeight {
			get {
				return m_isVertical ? (transform as RectTransform).rect.width / m_aspectRatio : -1;
			}
		}
		/// <inheritdoc />
		public float preferredHeight { get { return minHeight; } }
		/// <inheritdoc />
		public float flexibleHeight { get { return -1; } }

		/// <inheritdoc />
		public int layoutPriority { get { return 1; } }

		/// <inheritdoc />
		public void CalculateLayoutInputHorizontal() { }

		/// <inheritdoc />
		public void CalculateLayoutInputVertical() { }

		protected override void OnEnable() {
			base.OnEnable();
			SetDirty();
		}
		protected override void OnBeforeTransformParentChanged() {
			base.OnBeforeTransformParentChanged();
			SetDirty();
		}
		protected override void OnTransformParentChanged() {
			base.OnTransformParentChanged();
			SetDirty();
		}
		protected override void OnDidApplyAnimationProperties() {
			base.OnDidApplyAnimationProperties();
			SetDirty();
		}
#if UNITY_EDITOR
		protected override void OnValidate() {
			base.OnValidate();
			SetDirty();
		}
#endif
		protected override void OnDisable() {
			SetDirty();
			base.OnDisable();
		}
		protected override void OnRectTransformDimensionsChange() {
			base.OnRectTransformDimensionsChange();
			SetDirty();
		}
		bool _delayedSetDirty;
		private void SetDirty() {
			if (!IsActive()) return;
			if (CanvasUpdateRegistry.IsRebuildingLayout()) _delayedSetDirty = true;
			else LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
		}
		void Update() {
			if (!_delayedSetDirty) return;
			_delayedSetDirty = false;
			LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
		}
	}
}
