using UnityEngine;
using System.Collections;

public class Engine : MonoBehaviour
{

	Animator animator;
	EngineState currentState = EngineState.IDLE;
	EngineState lastState = EngineState.IDLE;
	private Transform mTransform;
	private int lives = 1;
	public AnimationCurve slideCurve;
	public AnimationCurve rotationCurve;
	public AnimationCurve dyingCurve;
	public TrackGenerator trackGenerator;
	public GameObject cameraTarget;

	public AudioManager audioManager;
	public Sprite deadSprite;

	public GameObject dyingEffect;

	public GameObject scoreText;

	public GameObject tombStone;

	private GameObject tempTombStone;

	public float maxRotation = 25.0f;
	public float dyingTime = 0.0f;
	private float tombStoneTime = 0.0f;

	public float maxSpeed = 15.0f;
	public float minInterval = 1.5f;

	private float leaningTime = 0;

	private float dyingSpeed = 0.0f;
	public int chainedSuccess = 0;

	enum EngineState
	{
		LEANING_LEFT,
		LEANING_RIGHT,
		DYING,
		TOMBSTONE,
		IDLE
	}

	// Use this for initialization
	void Start ()
	{
		animator = GetComponent<Animator> ();
		transform.position = new Vector3 (0, -Camera.main.orthographicSize + 1, -1);
		mTransform = GetComponent<Transform> ();
	}

	void RestartGame()
	{
		Movable.globalSpeed = 0f;
		Destroy(gameObject);
		Application.LoadLevel("main");
	}
	
	// Update is called once per frame
	void Update ()
	{

		if (currentState == EngineState.DYING)
		{
			if (Movable.globalSpeed > 0)
			{
				Movable.globalSpeed = dyingCurve.Evaluate(dyingTime) * dyingSpeed;
				dyingTime += Time.deltaTime * 0.75f;
			}
			else
			{
				currentState = EngineState.TOMBSTONE;
				tempTombStone = Instantiate(tombStone) as GameObject;
				tempTombStone.transform.parent = transform;
				tempTombStone.transform.localPosition = new Vector3(0, 1, 0);
			}
			return;
		}

		if (currentState == EngineState.TOMBSTONE)
		{
			if (tombStoneTime < 1.0f)
			{
				float scaleFactor = Mathf.Lerp(1.0f, 2.5f, tombStoneTime);
				tempTombStone.transform.localScale = new Vector3(scaleFactor, scaleFactor, 1);
				tombStoneTime += Time.deltaTime;
			}
			else
			{
				Invoke("RestartGame", 2.0f);
			}
			return;
		}
		//Debug.Log (Input.GetAxis ("Fire1"));
		if (Input.GetMouseButtonDown (0)) {
			if (Input.mousePosition.x > Screen.width / 2) {
				animator.SetTrigger ("LeanRight");
				lastState = currentState;
				currentState = EngineState.LEANING_RIGHT;
				cameraTarget.transform.Translate(0.5f, 0, 0);
			} else {
				animator.SetTrigger ("LeanLeft");

				lastState = currentState;
				currentState = EngineState.LEANING_LEFT;
				cameraTarget.transform.Translate(-0.5f, 0, 0);
			}
		}

		if (Input.GetMouseButtonUp (0)) {
			animator.SetTrigger ("Idle");
			lastState = currentState;
			currentState = EngineState.IDLE;
			if (lastState == EngineState.LEANING_LEFT)
			{
				cameraTarget.transform.Translate(0.5f, 0, 0);
			}
			else if (lastState == EngineState.LEANING_RIGHT)
			{
				cameraTarget.transform.Translate(-0.5f, 0, 0);
			}
		}

		switch (currentState) {
		case EngineState.LEANING_LEFT:
			{
				mTransform.rotation = Quaternion.Euler(0, Mathf.Lerp(0, maxRotation, leaningTime), 0);
				leaningTime += Time.deltaTime * 4;
				break;
			}
		case EngineState.LEANING_RIGHT:
			{
				mTransform.rotation = Quaternion.Euler(0, Mathf.Lerp(0, -maxRotation, leaningTime), 0);
				leaningTime += Time.deltaTime * 4;
				break;
			}
		case EngineState.IDLE:
			{
				float to = (lastState == EngineState.LEANING_LEFT ? maxRotation : -maxRotation);
				mTransform.rotation = Quaternion.Euler(0, Mathf.Lerp(0, to, leaningTime), 0);
				leaningTime -= Time.deltaTime * 4;
				break;
			}
		}

		leaningTime = Mathf.Clamp (leaningTime, 0, 1);
	}

	IEnumerator Slide (AnimationCurve curve, int direction)
	{
		float t = 0;
		Vector3 position = mTransform.position;
		while (t <= 1) {
			mTransform.position = position + new Vector3 (curve.Evaluate (t) * direction, 0, 0);
			t += Time.deltaTime * (Movable.globalSpeed / 2);
			yield return null;
		}

		mTransform.position = position + new Vector3 (curve.Evaluate (1) * direction, 0, 0);
		AnimationEnd(direction);
	}

	IEnumerator Rotate (AnimationCurve curve, int direction)
	{
		float t = 0;
		Vector3 rotation = mTransform.localRotation.eulerAngles;
		while (t <= 1) {
			mTransform.localRotation = Quaternion.Euler (rotation + new Vector3 (0, 0, curve.Evaluate (t) * direction * 90));
			t += Time.deltaTime * (Movable.globalSpeed / 2);
			yield return null;
		}

		mTransform.localRotation = Quaternion.Euler (rotation + new Vector3 (0, 0, curve.Evaluate (1) * direction * 90));
	}

	void AnimationEnd(int direction)
	{
		cameraTarget.transform.Translate(1.0f * direction, 0, 0);
	}

	void Die()
	{
		audioManager.PlayCrash();
		dyingEffect.SetActive(true);
		currentState = EngineState.DYING;
		dyingSpeed = Movable.globalSpeed;
		GetComponent<SpriteRenderer> ().sprite = deadSprite;
		foreach (Transform t in transform) {
			if (t.gameObject.name.StartsWith("engineSide"))
			{
				t.gameObject.SetActive(false);
			}
		}
		Camera.main.GetComponent<CameraMovement> ().Shake (0.5f, 0.6f);
	}
	
	void OnTriggerEnter2D (Collider2D other)
	{
		if (other.name == "DeadEnd") {
			Die();
		} else if (other.name.StartsWith ("Obstacle")) {
			//loose 1 life!!!!
			scoreText.GetComponent<ScoreManager>().UpdateLives(--lives);

			if (lives <= 0)
			{
				Die();
				return;
			}
			else
			{
				audioManager.PlaySqueak();
			}
			//shake the camera
			Camera.main.GetComponent<CameraMovement> ().Shake (0.3f, 0.3f);
			chainedSuccess = 0;
		} 
		else if (other.name == "Wagon")
		{
			chainedSuccess = 0;
			scoreText.GetComponent<ScoreManager>().UpdateLives(++lives);
			other.transform.parent = null;
			other.gameObject.SetActive(false);
		}
		else
		{
			chainedSuccess++;

			if (Movable.globalSpeed < maxSpeed)
			{
				Movable.globalSpeed += 0.1f;
			}

			if ((chainedSuccess % 4) == 1)
			{
				if (TrackGenerator.initialInterval > minInterval)
				{
					TrackGenerator.initialInterval -= 0.08f;
				}
			}

			scoreText.GetComponent<ScoreManager>().IncrementScore();

			switch (currentState)
			{
				case EngineState.LEANING_LEFT:
					//transform.Translate(-1, 0, 0, Space.World);
					StartCoroutine(Slide(slideCurve, -1));
					StartCoroutine(Rotate(rotationCurve, 1));
					trackGenerator.TrainMoved(-1);
					break;
				case EngineState.LEANING_RIGHT:
					//transform.Translate(1, 0, 0, Space.World);
					StartCoroutine(Slide(slideCurve, 1));
					StartCoroutine(Rotate(rotationCurve, -1));
					trackGenerator.TrainMoved(1);
					break;
				case EngineState.IDLE:
					trackGenerator.TrainMoved(0);
					break;
			}
		}
	}
}
