#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_5
#define UNITY_FEATURE_UGUI
#endif

using System.Collections.Generic;
using UnityEngine.Serialization;
#if UNITY_FEATURE_UGUI
using UnityEngine;
using UnityEngine.UI;

//-----------------------------------------------------------------------------
// Copyright 2015-2016 RenderHeads Ltd.  All rights reserverd.
//-----------------------------------------------------------------------------

namespace RenderHeads.Media.AVProVideo
{
	[AddComponentMenu("AVPro Video/Display uGUI")]
	public class DisplayUGUI : UnityEngine.UI.MaskableGraphic
	{
		[SerializeField]
		public MediaPlayer _mediaPlayer;

		[SerializeField]
		public Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);

		[SerializeField]
		public bool _setNativeSize = false;

		[SerializeField]
		public bool _keepAspectRatio = true;

		[SerializeField]
		public bool _noDefaultDisplay = true;

		[SerializeField]
		public Texture _defaultTexture;

		private Texture _currentTexture;

		private int _lastWidth;
		private int _lastHeight;

//		protected DisplayUGUI()
//		{ }

		/// <summary>
		/// Returns the texture used to draw this Graphic.
		/// </summary>
		public override Texture mainTexture
		{
			get
			{
				Texture result = Texture2D.whiteTexture;
				if (HasValidTexture())
				{
					result = _mediaPlayer.TextureProducer.GetTexture();
				}
				else
				{
					if (_noDefaultDisplay)
					{
						result = null;
					}
					else if (_defaultTexture != null)
					{
						result = _defaultTexture;
					}
				}
				return result;
			}
		}

		public bool HasValidTexture()
		{
			return (_mediaPlayer != null && _mediaPlayer.TextureProducer != null && _mediaPlayer.TextureProducer.GetTexture() != null);
		}

		void Update()
		{
			if (mainTexture == null)
			{
				// When the texture becomes null we need to mark the material as dirty otherwise the editor can crash
				if (mainTexture != _currentTexture)
				{
					_currentTexture = mainTexture;
					SetMaterialDirty();
				}
				return;
			}

			_currentTexture = mainTexture;

			if (_setNativeSize)
			{
				SetNativeSize();
			}
			if (HasValidTexture())
			{
				if (mainTexture.width != _lastWidth || mainTexture.height != _lastHeight)
				{
					_lastWidth = mainTexture.width;
					_lastHeight = mainTexture.height;
					SetVerticesDirty();
				}
			}

			SetMaterialDirty();
		}

		/// <summary>
		/// Texture to be used.
		/// </summary>
		public MediaPlayer CurrentMediaPlayer
		{
			get
			{
				return _mediaPlayer;
			}
			set
			{
				if (_mediaPlayer == value)
				{
					return;
				}

				_mediaPlayer = value;
				//SetVerticesDirty();
				SetMaterialDirty();
			}
		}

		/// <summary>
		/// UV rectangle used by the texture.
		/// </summary>
		public Rect uvRect
		{
			get
			{
				return m_UVRect;
			}
			set
			{
				if (m_UVRect == value)
				{
					return;
				}
				m_UVRect = value;
				SetVerticesDirty();
			}
		}

		/// <summary>
		/// Adjust the scale of the Graphic to make it pixel-perfect.
		/// </summary>

		[ContextMenu("Set Native Size")]
		public override void SetNativeSize()
		{
			Texture tex = mainTexture;
			if (tex != null)
			{
				int w = Mathf.RoundToInt(tex.width * uvRect.width);
				int h = Mathf.RoundToInt(tex.height * uvRect.height);
				rectTransform.anchorMax = rectTransform.anchorMin;
				rectTransform.sizeDelta = new Vector2(w, h);
			}
		}

		/// <summary>
		/// Update all renderer data.
		/// </summary>
// OnFillVBO deprecated by 5.2
// OnPopulateMesh(Mesh mesh) deprecated by 5.2 patch 1
#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2_0
/*		protected override void OnPopulateMesh(Mesh mesh)
		{			
			List<UIVertex> verts = new List<UIVertex>();
			_OnFillVBO( verts );

			var quad = new UIVertex[4];
			for (int i = 0; i < vbo.Count; i += 4)
			{
				vbo.CopyTo(i, quad, 0, 4);
				vh.AddUIVertexQuad(quad);
			}
			vh.FillMesh( toFill );
		}*/

#if !UNITY_5_2_1
		protected override void OnPopulateMesh(VertexHelper vh)
		{
			vh.Clear();
			
			List<UIVertex> aVerts = new List<UIVertex>();
			_OnFillVBO( aVerts );

			List<int> aIndicies = new List<int>( new int[]{ 0, 1, 2, 2, 3, 0 } );
			vh.AddUIVertexStream( aVerts, aIndicies );
		}
#endif
		[System.Obsolete("This method is not called from Unity 5.2 and above")]
#endif
		protected override void OnFillVBO(List<UIVertex> vbo)
		{
			_OnFillVBO(vbo);
		}

		private void _OnFillVBO(List<UIVertex> vbo)
		{
			bool flipY = false;
			if (HasValidTexture())
			{
				flipY = _mediaPlayer.TextureProducer.RequiresVerticalFlip();
			}

			Vector4 v = GetDrawingDimensions(_keepAspectRatio);

			vbo.Clear();

			var vert = UIVertex.simpleVert;

			vert.position = new Vector2(v.x, v.y);
			vert.uv0 = new Vector2(m_UVRect.xMin, m_UVRect.yMin);
			if (flipY)
			{
				vert.uv0 = new Vector2(m_UVRect.xMin, 1.0f - m_UVRect.yMin);
			}
			vert.color = color;
			vbo.Add(vert);

			vert.position = new Vector2(v.x, v.w);
			vert.uv0 = new Vector2(m_UVRect.xMin, m_UVRect.yMax);
			if (flipY)
			{
				vert.uv0 = new Vector2(m_UVRect.xMin, 1.0f - m_UVRect.yMax);
			}
			vert.color = color;
			vbo.Add(vert);

			vert.position = new Vector2(v.z, v.w);
			vert.uv0 = new Vector2(m_UVRect.xMax, m_UVRect.yMax);
			if (flipY)
			{
				vert.uv0 = new Vector2(m_UVRect.xMax, 1.0f - m_UVRect.yMax);
			}
			vert.color = color;
			vbo.Add(vert);

			vert.position = new Vector2(v.z, v.y);
			vert.uv0 = new Vector2(m_UVRect.xMax, m_UVRect.yMin);
			if (flipY)
			{
				vert.uv0 = new Vector2(m_UVRect.xMax, 1.0f - m_UVRect.yMin);
			}
			vert.color = color;
			vbo.Add(vert);
		}

		//Added this method from Image.cs to do the keep aspect ratio
		private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
		{
			Vector4 returnSize = Vector4.zero;

			if( mainTexture )
			{
				var padding = Vector4.zero;
				var textureSize = new Vector2(mainTexture.width, mainTexture.height);
				
				Rect r = GetPixelAdjustedRect();
//				Debug.Log(string.Format("r:{2}, textureSize:{0}, padding:{1}", textureSize, padding, r));
				
				int spriteW = Mathf.RoundToInt( textureSize.x );
				int spriteH = Mathf.RoundToInt( textureSize.y );
				
				var size = new Vector4( padding.x / spriteW,
										padding.y / spriteH,
										(spriteW - padding.z) / spriteW,
										(spriteH - padding.w) / spriteH );

				if (shouldPreserveAspect && textureSize.sqrMagnitude > 0.0f)
				{
					var spriteRatio = textureSize.x / textureSize.y;
					var rectRatio = r.width / r.height;
					
					if (spriteRatio > rectRatio)
					{
						var oldHeight = r.height;
						r.height = r.width * (1.0f / spriteRatio);
						r.y += (oldHeight - r.height) * rectTransform.pivot.y;
					}
					else
					{
						var oldWidth = r.width;
						r.width = r.height * spriteRatio;
						r.x += (oldWidth - r.width) * rectTransform.pivot.x;
					}
				}
				
				returnSize = new Vector4( r.x + r.width * size.x,
										  r.y + r.height * size.y,
										  r.x + r.width * size.z,
										  r.y + r.height * size.w  );
				
			}

			return returnSize;
		}	
	}
}

#endif