using UnityEngine;
using System.Collections;

[AddComponentMenu("Quad UI/Quad UI (Main)")]
/**
	This is a Singleton class. Only one QuadUI object may be instantiated at any given time, otherwise an exception is thrown.
	This class is sealed and cannot be extended.
	
	This is your top-level UI manager. All interactive events are dispatched from here. This class also has some helper Gizmos for laying out your UI in the Scene View.
	
	QuadUI is platform-independent as it takes advantage of Unity's platform-dependent compilation to filter out unnecessary user interaction events on platforms.
	For example: A touch interface has no "Mouse Over" event, so anything like that will not be compiled when working within a Mobile build setting such as iOS or Android.
*/
public sealed class QuadUI : MonoBehaviour 
{
	
	/**		
		The screen resolution of your deployment platform. This is used to draw out your wireframe canvas in the Scene View.
		
		Note: This enum is Build-Setting dependent, and therefore different values will be available for different build settings.
		
		For iPhone:
		
			Custom = 0, iPhonePortrait = 1, iPhoneLandscape = 2, iPadPortrait = 3, iPadLandscape = 4, iPhone4Portrait = 5, iPhone4Landscape = 6
		
		For Android:
		
			Custom = 0, HTCLegendTall = 1, HTCLegendWide = 2, NexusOneTall = 3, NexusOneWide = 4, MotorolaDroidTall = 5, MotorolaDroidWide = 6, TegraTabletTall = 7, TegraTabletWide = 8
		
	*/
	public enum Resolution
	{
		Custom = 0
		
		#if UNITY_IPHONE
		,iPhonePortrait = 1,
		iPhoneLandscape = 2,
		iPadPortrait = 3,
		iPadLandscape = 4,
		iPhone4Portrait = 5,
		iPhone4Landscape = 6
		#endif
		
		#if UNITY_ANDROID
		,HTCLegendTall = 1,
		HTCLegendWide = 2,
		NexusOneTall = 3,
		NexusOneWide = 4,
		MotorolaDroidTall = 5,
		MotorolaDroidWide = 6,
		TegraTabletTall = 7,
		TegraTabletWide = 8
		#endif
	}
	
	static QuadUI _instance;
	
	/**
		Time.timeScale independent deltaTime. TimescaleIndependentAnimation uses this variable to power its animations.
	*/
	public static float deltaTime;
	
	/**
		If this is false, this class will not perform any automatic raycasts on input events and your UI will effectively be disabled.
	*/
	public bool allowUserInput = true;
	
	/**
		This is the orthographic camera that will fill your screen space. All raycasting is done from here with the Camera's layerBitMask taken into account to filter out non-UI colliders.
	*/
	public Camera cam;
	
	/**
		This should match the resolution your are building the UI for.
	*/
	public QuadUI.Resolution resolution;
	
	float _currTime = 0;
	float _timeAtLastFrame = 0;
	
	int layerBitMask = 1;
	InteractiveElement2D _currentElement;
	
	/**
		If QuadUI.resolution is set to Custom, define the dimensions here.
	*/
	public Vector2 screenDimensions = new Vector2(1024,768);
	
	void Awake()
	{
		if(_instance && _instance != this)
		{
			throw new System.Exception("Singleton Error: More than one [QuadUI] object instantiated at the same time. Please insure only one is instantiated at any given time. If you are moving from scene to scene, make sure you call QuadUI.OnLevelEnd() before you change scenes.");
		}
		else
		{
			_instance = this;
			layerBitMask = cam.cullingMask;
		}
	}
	
	void Update ()
	{
		CalculateDeltaTime();
		
		if(!allowUserInput) return;
		
		#if UNITY_EDITOR
			//we get mouse input no matter what
			MouseInputUpdate();
			
			#if UNITY_IPHONE || UNITY_ANDROID //Mobile Build Settings, but in Editor
				TouchInputUpdate();
			#endif
		
		#else //Not Editor
			
			#if UNITY_IPHONE || UNITY_ANDROID
				TouchInputUpdate();
			#else
				MouseInputUpdate();
			#endif
		
		#endif
	}
	
	void MouseInputUpdate()
	{
		RaycastHit hit;
		Ray ray;
		
		ray = (Ray) cam.ScreenPointToRay(Input.mousePosition);
		
		if(Physics.Raycast(ray, out hit, cam.farClipPlane, layerBitMask))
		{
			_currentElement = (InteractiveElement2D) hit.collider.GetComponent(typeof(InteractiveElement2D));
			
			if(Input.GetMouseButtonDown(0))
			{
				//Mouse Down
				if(_currentElement) _currentElement.OnDown((Vector2)Input.mousePosition);
			}
			else if(Input.GetMouseButtonUp(0))
			{
				//Mouse Up
				if(_currentElement) _currentElement.OnUp((Vector2)Input.mousePosition);
			}
			else
			{
				//Mouse Over
				if(_currentElement) _currentElement.OnOver((Vector2)Input.mousePosition);
			}
		}
		else
		{
			//We are over nothing, did we just leave something?
			if(_currentElement)
			{
				_currentElement.OnOut();
				_currentElement = null;
			}
		}
	}
	
	void TouchInputUpdate()
	{
		RaycastHit hit;
		Ray ray;
		
		foreach(Touch touch in Input.touches)
		{
			//cast a ray from out touch point on the screen into our world
			ray = (Ray) cam.ScreenPointToRay(touch.position);
			
			//check if the ray hit anything on our layer	
			if(Physics.Raycast(ray,out hit,cam.farClipPlane,layerBitMask))
			{
				switch(touch.phase)
				{
					case TouchPhase.Began:
					hit.collider.gameObject.SendMessage("OnDown",touch.position,SendMessageOptions.DontRequireReceiver);
					break;
					
					case TouchPhase.Stationary:
					hit.collider.gameObject.SendMessage("OnStationary",touch.position,SendMessageOptions.DontRequireReceiver);
					break;
					
					case TouchPhase.Moved:
					hit.collider.gameObject.SendMessage("OnMove",touch.position,SendMessageOptions.DontRequireReceiver);
					break;
					
					case TouchPhase.Ended:
					hit.collider.gameObject.SendMessage("OnUp",touch.position,SendMessageOptions.DontRequireReceiver);
					break;
					
					case TouchPhase.Canceled:
					//do nothing
					break;
				}
			}
		}
	}
	
	void CalculateDeltaTime()
	{
		_currTime = Time.realtimeSinceStartup;
		deltaTime = _currTime - _timeAtLastFrame;
		_timeAtLastFrame = _currTime;
	}
	
	/**
		Static Read only. Returns the Instantiation of this Singleton.
	*/
	public static QuadUI Instance
	{
		get
		{
			return _instance;
		}
	}
	
	/**
		Static communication to the Singleton instance's allowUserInput variable. Use this to toggle the activation of your UI. For more info see QuadUI.allowUserInput.
	*/
	public static bool Interactive
	{
		get
		{
			return _instance.allowUserInput;
		}
		set
		{
			_instance.allowUserInput = value;
		}
	}
	
	/**
		It is imperative to call this method before moving to another Level, especially if the next level contains another instantiation of QuadUI.
	*/
	public static void OnLevelEnd()
	{
		_instance = null;
	}
	
	void OnDrawGizmos()
	{
		if(!cam) return;
		
		int screenWidth = 480;
		int screenHeight = 320;
		
		#if UNITY_IPHONE
			switch(resolution)
			{
				case QuadUI.Resolution.iPhonePortrait:
					screenWidth = 320;
					screenHeight = 480;
				break;
				case QuadUI.Resolution.iPhoneLandscape:
					screenWidth = 480;
					screenHeight = 320;
				break;
				case QuadUI.Resolution.iPadPortrait:
					screenWidth = 768;
					screenHeight = 1024;
				break;
				case QuadUI.Resolution.iPadLandscape:
					screenWidth = 1024;
					screenHeight = 768;
				break;
				case QuadUI.Resolution.iPhone4Portrait:
					screenWidth = 640;
					screenHeight = 920;
				break;
				case QuadUI.Resolution.iPhone4Landscape:
					screenWidth = 920;
					screenHeight = 640;
				break;
				case QuadUI.Resolution.Custom:
					screenWidth = (int) screenDimensions.x;
					screenHeight = (int) screenDimensions.y;
				break;
			}
		#endif
		
		#if UNITY_ANDROID
			switch(resolution)
			{
				case QuadUI.Resolution.HTCLegendTall:
					screenWidth = 320;
					screenHeight = 480;
				break;
				case QuadUI.Resolution.HTCLegendWide:
					screenWidth = 480;
					screenHeight = 320;
				break;
				case QuadUI.Resolution.NexusOneTall:
					screenWidth = 480;
					screenHeight = 800;
				break;
				case QuadUI.Resolution.NexusOneWide:
					screenWidth = 800;
					screenHeight = 480;
				break;
				case QuadUI.Resolution.MotorolaDroidTall:
					screenWidth = 480;
					screenHeight = 854;
				break;
				case QuadUI.Resolution.MotorolaDroidWide:
					screenWidth =854;
					screenHeight = 480;
				break;
				case QuadUI.Resolution.TegraTabletTall:
					screenWidth = 600;
					screenHeight = 1024;
				break;
				case QuadUI.Resolution.TegraTabletWide:
					screenWidth = 1024;
					screenHeight = 600;
				break;
				case QuadUI.Resolution.Custom:
					screenWidth = (int) screenDimensions.x;
					screenHeight = (int) screenDimensions.y;
				break;
			}
		#endif
			
		#if !UNITY_ANDROID && !UNITY_IPHONE
			screenWidth = (int) screenDimensions.x;
			screenHeight = (int) screenDimensions.y;
		#endif

		Vector3 bb = new Vector3(screenWidth,screenHeight,cam.farClipPlane);
		Vector3 loc = cam.transform.position;
		Gizmos.color = new Color(.1F,.1F,.1F,1);
		Gizmos.DrawWireCube(new Vector3(loc.x,loc.y,loc.z+(.5F*cam.farClipPlane)),bb);
	}
}
