using Mox.Shared.Renderer;

namespace Mox.Shared.UI
{
	public struct SButtonEventData
	{
		public SButtonEventData(int _iX, int _iY, int _iIndex = -1, string _sTag = null)
		{
			X = _iX;
			Y = _iY;
			Index = _iIndex;
			Tag = _sTag;
		}

		public int X;
		public int Y;
		public int Index;
		public string Tag;
	}

	public class Button : Image
	{
		public override void Render()
		{
			if ((States & ControlStates.Disabled) != 0)
			{
				RenderImage(BackgroundDisabled ?? Background);
			}
			else if ((States & ControlStates.Pressed) != 0)
			{
				RenderImage(BackgroundPressed ?? Background);
			}
			else if ((States & ControlStates.Highlighted) != 0)
			{
				RenderImage(BackgroundHover ?? Background);
			}
			else
			{
				RenderImage(Background);
			}
		}

		internal override bool HandleEvent(SEventProperties _eventProperties)
		{
			bool bStopPropagation = false;

			switch (_eventProperties.EventType)
			{
			case EEventType.MouseButtonDown:
				{
					SMouseEventData mouseEvent = (SMouseEventData) _eventProperties.Data;
					Root.Instance.MouseCaptureControl = this;
					Root.Instance.FireEvent(this, (States & ControlStates.Disabled) == 0 ? EEventType.ButtonPressed : EEventType.ButtonDisabledPressed, EEventPropagation.Bubble, mouseEvent);

					base.HandleEvent(_eventProperties);

					bStopPropagation = true;

					m_iReceivedMouseDownIndex = mouseEvent.Index;
					m_bReceivedMouseDown = true;
					m_iReceivedDrag = false;
				}

				break;
			case EEventType.MouseButtonUp:
				{
					SMouseEventData mouseEvent = (SMouseEventData) _eventProperties.Data;

					if (m_bReceivedMouseDown && mouseEvent.Index == m_iReceivedMouseDownIndex)
					{
						if (!m_iReceivedDrag || Root.Instance.MainControl.HitTest(mouseEvent.X, mouseEvent.Y) == this)
						{
							FireClickEvent((SMouseEventData) _eventProperties.Data);
							bStopPropagation = true;
						}
					}

					bStopPropagation |= base.HandleEvent(_eventProperties);

					if (Root.Instance.MouseCaptureControl == this)
						Root.Instance.MouseCaptureControl = null;
				}

				break;
			case EEventType.BeginDrag:
			case EEventType.Dragged:
				{
					SMouseEventData mouseEvent = (SMouseEventData) _eventProperties.Data;

					if (m_bReceivedMouseDown && mouseEvent.Index == m_iReceivedMouseDownIndex)
					{
						m_iReceivedDrag = true;
						Root.Instance.FireEvent(this, EEventType.ButtonDragged, EEventPropagation.Bubble, mouseEvent);
					}

					bStopPropagation |= base.HandleEvent(_eventProperties);
				}

				break;
			default:
				bStopPropagation |= base.HandleEvent(_eventProperties);

				break;
			}

			return bStopPropagation;
		}

		private void FireClickEvent(SMouseEventData _mouseEvent)
		{
			if ((States & ControlStates.Disabled) == 0)
			{
				OnClick(_mouseEvent);
			}
			else
			{
				OnDisabledClick(_mouseEvent);
			}
		}

		protected virtual void OnClick(SMouseEventData _mouseEvent)
		{
			Root.Instance.FireEvent(this, EEventType.ButtonClicked, EEventPropagation.Bubble, new SButtonEventData(_mouseEvent.X, _mouseEvent.Y, _mouseEvent.Index, Tag));
		}

		protected virtual void OnDisabledClick(SMouseEventData _mouseEvent)
		{
			Root.Instance.FireEvent(this, EEventType.ButtonDisabledClicked, EEventPropagation.Bubble, new SButtonEventData(_mouseEvent.X, _mouseEvent.Y, _mouseEvent.Index, Tag));
		}

		internal override void OnLostCapture()
		{
			base.OnLostCapture();

			if (!m_bReceivedMouseDown)
			{
				return;
			}

			m_bReceivedMouseDown = false;
			m_iReceivedMouseDownIndex = -1;

			Root.Instance.FireEvent(this, (States & ControlStates.Disabled) == 0 ? EEventType.ButtonReleased : EEventType.ButtonDisabledReleased, EEventPropagation.Bubble, null);
		}

		public override void Serialize(Serializer.Serializer _serializer)
		{
			_serializer.Serialize(ref m_BackgroundHover, nameof(BackgroundHover));
			_serializer.Serialize(ref m_BackgroundPressed, nameof(BackgroundPressed));
			_serializer.Serialize(ref m_BackgroundDisabled, nameof(BackgroundDisabled));
			_serializer.Serialize(ref m_sSoundClicked, nameof(SoundClicked), string.Empty);

			base.Serialize(_serializer);
		}

		public override bool HandleSound(SEventProperties _eventProperties, out string _sSound)
		{
			if (_eventProperties.EventType == EEventType.ButtonClicked && !string.IsNullOrEmpty(m_sSoundClicked))
			{
				_sSound = m_sSoundClicked;
				return true;
			}

			return base.HandleSound(_eventProperties, out _sSound);
		}

		public string SoundClicked { get => m_sSoundClicked; set => m_sSoundClicked = value; }
		public SubImage BackgroundHover { get => m_BackgroundHover; set => m_BackgroundHover = value; }
		public SubImage BackgroundPressed { get => m_BackgroundPressed; set => m_BackgroundPressed = value; }
		public SubImage BackgroundDisabled { get => m_BackgroundDisabled; set => m_BackgroundDisabled = value; }

		private int m_iReceivedMouseDownIndex;
		private bool m_bReceivedMouseDown;
		private bool m_iReceivedDrag;

		private string m_sSoundClicked = string.Empty;
		private SubImage m_BackgroundHover;
		private SubImage m_BackgroundPressed;
		private SubImage m_BackgroundDisabled;
	}
}
