using System;
using System.Globalization;
using System.Linq;
using Mox.Shared.Math;
using Mox.Shared.Renderer;
using Mox.Shared.UI;

namespace Mox.Shared.Serializer
{
	public abstract class Serializer
	{
		public abstract bool IsLoading { get; }

		public abstract bool Serialize(ref int _value, string _sName, int _defaultValue);

		public abstract bool Serialize(ref string _value, string _sName, string _defaultValue);

		public abstract bool Serialize(ref bool _value, string _sName, bool _defaultValue);

		public bool SerializeEnum<T>(ref T _enum, string _sName, T _defaultValue)
		{
			if (IsLoading)
			{
				string sEnum = null;
				if (Serialize(ref sEnum, _sName, _defaultValue?.ToString()))
				{
					_enum = (T) Enum.Parse(typeof(T), sEnum);

					return true;
				}
			}
			else
			{
				string sEnum = _enum.ToString();
				if (!_enum.Equals(_defaultValue) && Serialize(ref sEnum, _sName, _defaultValue?.ToString()))
				{
					return true;
				}
			}

			return false;
		}

		public bool Serialize(ref Color _color, string _sName, Color _defaultValue)
		{
			if (IsLoading)
			{
				string sColor = null;
				if (Serialize(ref sColor, _sName, _defaultValue?.ToString()))
				{
					var tokens = sColor.Split(',').Select(c => float.Parse(c.Trim())).ToArray();
					_color = new Color(tokens[0], tokens[1], tokens[2], tokens[3]);

					return true;
				}
			}
			else if (_color != null)
			{
				string sColor = _color.ToString();
				if (!_color.Equals(_defaultValue) && Serialize(ref sColor, _sName, _defaultValue?.ToString()))
				{
					return true;
				}
			}

			return false;
		}
		
		public bool Serialize(ref Rect _rect, string _sName, Rect _defaultValue)
		{
			if (IsLoading)
			{
				string sRect = null;
				if (Serialize(ref sRect, _sName, _defaultValue?.ToString()))
				{
					var tokens = sRect.Split(',').Select(c => int.Parse(c.Trim())).ToArray();
					_rect = new Rect(tokens[0], tokens[1], tokens[2], tokens[3]);

					return true;
				}
			}
			else if (_rect != null)
			{
				string sRect = _rect.ToString();
				if (!_rect.Equals(_defaultValue) && Serialize(ref sRect, _sName, _defaultValue?.ToString()))
				{
					return true;
				}
			}

			return false;
		}
		
		public bool Serialize(ref SubImage _subImage, string _sName)
		{
			if (IsLoading)
			{
				string sSubImage = null;
				if (Serialize(ref sSubImage, _sName, null))
				{
					_subImage = RendererBase.Instance.Atlas.SubImages[sSubImage];

					return true;
				}
			}
			else
			{
				var subImage = _subImage;
				var sSubImage = RendererBase.Instance.Atlas.SubImages.FirstOrDefault(kvp => kvp.Value == subImage).Key;
				if (_subImage != null && Serialize(ref sSubImage, _sName, null))
				{
					return true;
				}
			}

			return false;
		}

		public bool Serialize(ref Measure _measure, string _sName, Measure _defaultValue)
		{
			if (IsLoading)
			{
				string sMeasure = null;
				if (Serialize(ref sMeasure, _sName, _defaultValue?.ToString()))
				{
					var iUnit = -1;
					for (int i = 0; i < sMeasure.Length; ++i)
					{
						if (sMeasure[i] == '%' || sMeasure[i] == '*' || sMeasure[i] == 'p')
						{
							iUnit = i;
							break;
						}
					}

					var sValue = sMeasure.Substring(0, iUnit);
					var sUnit = sMeasure.Substring(iUnit);
					if (string.IsNullOrEmpty(sValue))
					{
						sValue = "1";
					}

					var eUnit = 
						sUnit == "%" ? EUnit.Percent :
						sUnit == "*" ? EUnit.Star :
						sUnit == "px" ? EUnit.Pixel : 
						throw new Exception();

					_measure = new Measure(double.Parse(sValue), eUnit);

					return true;
				}
			}
			else if (_measure != null)
			{
				string sMeasure = _measure.ToString();

				if (!_measure.Equals(_defaultValue) && Serialize(ref sMeasure, _sName, _defaultValue?.ToString()))
				{
					return true;
				}
			}

			return false;
		}

		public abstract bool StartChild(string[] _aValidTags, out string _sName);
		public abstract bool StartChild(string _sName);
		public abstract void EndChild();
	}

    public abstract class Serializable
    {
	    public abstract void Serialize(Serializer _serializer);
    }
}
