// Splash Screen class
// This is a Core Component class that causes a screen blanking logo to appear on demand.
// It's a little more complex than that. It can also perform a series of triggered actions.
//
// This should probably be loaded up with static functions, and potentially implemented as a static class.
// Arguably, the core should integrate the splash screen into itself, but we can leave that for another time.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent (typeof(GUITexture))]
public class SplashScreen : MonoBehaviour 
{
	public enum EffectType
	{
		/*				// I haven't had time to write all of these functions yet.
		NoEffect,
		FadeOnly,
		ColorOnly,
		*/
		ColorFade
	}
	
	public enum DismissTrigger
	{
		AnyKey,
		DoneLoading,
		AnyKeyDoneLoading,
		DoneFadeIn,
		/*				// Likewise, haven't had time to write these either, though, they are pretty simple.
		OneSecond,
		TwoSeconds,
		FiveSeconds,
		TenSeconds,
		*/
		Always,
		Never
	}
	
	//private EffectType effectType = EffectType.ColorFade;
	
	// These have all been left public because I was using the inspector to modify them.
	// When we have time, we'll hazard encapsulating some of these.
	[SerializeField]
	private Rect splashRect;
	private static SplashScreen Instance;
	public static SplashScreen GetInstance(){ return Instance; }
	
	private Color targetColor;
	[SerializeField]
	private float colorRate = 0.1f;
	private bool fading = false;
	private bool opaque = false;
	
	private int fadeDirection = 0;
	
	[SerializeField]
	private GameObject background = null;
	private float percentage = 0.8f;
	
	private List<System.Action> summonActions	= new List<System.Action>();
	private List<System.Action> dismissActions 	= new List<System.Action>();
	private DismissTrigger dismissTrigger = DismissTrigger.Never;
	
	// This is a function that returns true when a trigger has tripped.
	private delegate bool TriggerFunction();
	// A dictionary containing links between trigger enums and trigger functions.
	static private Dictionary<DismissTrigger,TriggerFunction> triggerDictionary = new Dictionary<DismissTrigger, TriggerFunction>()
	{
		{DismissTrigger.AnyKey,				AnyKey},
    	{DismissTrigger.DoneLoading,		DoneLoading},
    	{DismissTrigger.AnyKeyDoneLoading, 	AnyKeyDoneLoading},
		{DismissTrigger.Always, 			Always},
		{DismissTrigger.Never, 				Never},
		{DismissTrigger.DoneFadeIn, 		DoneFadeIn}
	};
	
	void Awake ()
	{
		Instance = this;
	}
	
	void Start () 
	{
		Core.Attach(this);
		enabled = false;
		GetComponent<GUITexture>().color = Color.clear;
		opaque = true;
	}
	
	void Update () 
	{
		if (triggerDictionary[dismissTrigger]())
		{	// If the dismiss trigger goes off, we'll reset the dismiss trigger and fade out.
			dismissTrigger = DismissTrigger.Never;
			FadeOut();
		}
		
		if (fading)
		{	// If we're fading, perform the fading animation.
			ChangeColor();
			if (fadeDirection == -1)
			{	// Fade out
				if (GetComponent<GUITexture>().color.a == 0)
				{
					// We'll turn off the monobehaviour to stop updating.
					fading = false;
					enabled = false;
					fadeDirection = 0;
					
					foreach (System.Action runNow in dismissActions)
					{
						runNow();
					}
					dismissActions.Clear();
				}
			}
			else if (fadeDirection == 1)
			{	// Fade in
				if (GetComponent<GUITexture>().color.a >= 0.5f)
				{
					fading = false;
					fadeDirection = 0;
					
					foreach (System.Action runNow in summonActions)
					{
						runNow();
					}
					summonActions.Clear();
				}
			}
		}
		
		ResizeTexture(); // Called frequently to account for screen size changes. Not efficient, but who cares? This is a splash screen.
	}
	
	private void ResizeTexture()
	{
		//This accounts for different fix aspect ratios. The texture is meant to stay square.
		int dimension = Mathf.Min(Screen.width, Screen.height);
		
		int size = Mathf.CeilToInt(dimension * percentage);
		int inset = Mathf.CeilToInt(-size * 0.5f);
		
		splashRect = new Rect(inset, inset, size, size);
		
		GetComponent<GUITexture>().pixelInset = splashRect;
		
		transform.position = new Vector3(0.5f,0.5f,0);
		GetComponent<GUITexture>().pixelInset = splashRect;
	}
	
	private void ChangeColor()
	{
		// !!! Return to this
		
		Color newColor = new Color();
		Color color = GetComponent<GUITexture>().color;
		Color backgroundColor = background.GetComponent<GUITexture>().color;
		

		if (fadeDirection == -1)
		{
			newColor.r = Mathf.Max(targetColor.r, color.r + (fadeDirection * Time.deltaTime * colorRate));
			newColor.g = Mathf.Max(targetColor.g, color.g + (fadeDirection * Time.deltaTime * colorRate));
			newColor.b = Mathf.Max(targetColor.b, color.b + (fadeDirection * Time.deltaTime * colorRate));
			newColor.a = Mathf.Max(targetColor.a, color.a + (fadeDirection * Time.deltaTime * colorRate));
		}
		else if (fadeDirection == 1)
		{
			newColor.r = Mathf.Min(targetColor.r, color.r + (fadeDirection * Time.deltaTime * colorRate));
			newColor.g = Mathf.Min(targetColor.g, color.g + (fadeDirection * Time.deltaTime * colorRate));
			newColor.b = Mathf.Min(targetColor.b, color.b + (fadeDirection * Time.deltaTime * colorRate));
			newColor.a = Mathf.Min(targetColor.a, color.a + (fadeDirection * Time.deltaTime * colorRate));
		}
		
		GetComponent<GUITexture>().color = newColor;
		
		if (opaque)
		{
			backgroundColor.a = 0.5f;
		}
		else
		{
			backgroundColor.a = newColor.a;
		}
		
		GetComponent<GUITexture>().color = newColor;
		background.GetComponent<GUITexture>().color = backgroundColor;
	}
	
	static public void AddDismissAction(System.Action action)
	{
		if (action != null)
		{
			Instance.dismissActions.Add(action);
		}
	}
	
	static public void SetDismissTrigger(SplashScreen.DismissTrigger trigger)
	{
		Instance.dismissTrigger = trigger;
	}
	
	static public void AddSummonAction(System.Action action)
	{
		if (action != null)
		{
			Instance.summonActions.Add(action);
		}
	}
	
	static public void Summon()
	{
		FadeIn ();
	}
	
	static public void Dismiss()
	{
		FadeOut ();
	}
	
	static private void FadeIn()
	{
		Instance.targetColor = new Color(0.5f, 0.5f, 0.5f, 0.5f); // !!!
		Instance.fading = true;
		Instance.enabled = true;
		Instance.fadeDirection = 1;
	}
	
	static private void FadeOut()
	{
		Instance.fading = true;
		Instance.targetColor.a = 0.0f;
		Instance.fadeDirection = -1;
		Instance.opaque = false;
	}
	
	#region Dismissal Trigger Functions
	// We are functions sent here for your convenience.
	public static void DefaultAction()
	{
		return;
	}
	
	static private bool AnyKey()
	{
		return Input.anyKeyDown;
	}
	
	static private bool DoneLoading()
	{
		return (!Core.isLoading && !LoadingScreen.isLoading);
	}
	
	static private bool AnyKeyDoneLoading()
	{
		return (Input.anyKeyDown && !Core.isLoading && !LoadingScreen.isLoading);
	}
	
	static bool Timed()
	{
		return Input.anyKeyDown;
	}
	
	static private bool Always()
	{
		return true;
	}
	
	static private bool Never()
	{
		return false;
	}
	static private bool DoneFadeIn()
	{
		return (Instance.GetComponent<GUITexture>().color.a >= Instance.targetColor.a);
	}
	#endregion
}
