using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TrackGenerator : MonoBehaviour
{
	private List<int> gridPosition = new List<int> ();
	private List<int> stopPosition = new List<int> ();

	private int trainGridPos = 0;
	public int tilesUntilObstacle = 2;
	private int _tilesUntilObstacle;

	public static float initialInterval = 2.5f;
	private float splitTrackInterval = 2.0f;
	public float startingInterval = 5.0f;
	private GameObject lastLine = null;
	private int numTracks = 0;

	public PoolManager verticalTrackPool;
	public PoolManager twoSplitTrackPool;
	public PoolManager threeSplitTrackPool;
	public PoolManager endTrackPool;
	private PoolManager[] trackPoolTypes;

	public GameObject wagon;

	public GameObject [] Obstacles;
	public PoolManager obstaclePool;

	public PoolManager vTrackPool;
	public Engine engine;

	public GameObject groundObject;
	public Sprite groundSprite;

	private List<GameObject> currentGround;
	private List<GameObject> lastGround;

	int safeOne = 0;

	// Use this for initialization
	void Start ()
	{
		if (GameObject.Find ("Fader") != null) {
			GameObject.Find ("Fader").GetComponent<Fader> ().FadeId ();
		}

		Screen.sleepTimeout = SleepTimeout.NeverSleep;

		gridPosition.Add (0);

		Movable.globalSpeed = 5f;
		TrackGenerator.initialInterval = 2.5f;

		trackPoolTypes = new PoolManager[3];
		trackPoolTypes [0] = verticalTrackPool;
		trackPoolTypes [1] = twoSplitTrackPool;
		trackPoolTypes [2] = threeSplitTrackPool;


		GenerateStartingLines ();
		currentGround = new List<GameObject>();
		lastGround = new List<GameObject>();
		GenerateStartingGrounds(2, ref currentGround);
		GenerateStartingGrounds(10, ref lastGround);
	}

	void GenerateStartingLines ()
	{
		float curPos = -Camera.main.orthographicSize;
		float maxPos = -curPos;
		while (curPos <= maxPos + 1) {
			GenerateNewLine ();
			curPos += 1.0f;
		}
	}

	void GenerateStartingGrounds(float height, ref List<GameObject> tempGroundList)
	{
		float groundWidth = groundSprite.bounds.max.x - groundSprite.bounds.min.x;
		float startPosition = -Camera.main.orthographicSize - 2 + Camera.main.transform.position.x;
		float endPosition = Camera.main.orthographicSize + 2 + Camera.main.transform.position.x;
		while (startPosition <= endPosition)
		{
			GameObject tempGround = Instantiate(groundObject) as GameObject;
			tempGround.transform.localPosition = new Vector3(startPosition, height, 0);
			tempGroundList.Add(tempGround);
			startPosition += groundWidth;
		}
	}

	void RecycleGrounds(float height)
	{
		List<GameObject> tempGroundList = new List<GameObject>();
		float groundWidth = groundSprite.bounds.max.x - groundSprite.bounds.min.x;
		float startPosition = -Camera.main.orthographicSize - 2 + Camera.main.transform.position.x;
		float endPosition = Camera.main.orthographicSize + 2 + Camera.main.transform.position.x;

		int i = 0;
		while (startPosition <= endPosition)
		{
			GameObject tempGround = currentGround[i++];
			tempGround.transform.localPosition = new Vector3(startPosition, height, 0);
			tempGroundList.Add(tempGround);
			startPosition += groundWidth;
		}
		currentGround = lastGround;
		lastGround = tempGroundList;
	}

	void GenerateNewLine ()
	{
		PoolManager trackToGenerate = verticalTrackPool;
		bool generateSplit = false;

		if (splitTrackInterval <= 0) {
			splitTrackInterval = initialInterval;
			numTracks = Random.Range (1, 3);
			trackToGenerate = trackPoolTypes [numTracks];
			generateSplit = true;
			_tilesUntilObstacle = tilesUntilObstacle;
		}

		GameObject tempLine = new GameObject ("Track Line", typeof(Movable));
		tempLine.GetComponent<Movable> ().lastLine = lastLine;
		tempLine.GetComponent<Movable> ().trackGenerator = this;
		tempLine.GetComponent<Movable> ().offset = new Vector3 (0, (generateSplit ? 2 : 1), 0);

		if (!generateSplit) {
			_tilesUntilObstacle--;
			if(_tilesUntilObstacle == 0)
			{
				safeOne = gridPosition[Random.Range(0, gridPosition.Count)];
				
				foreach(int pos in gridPosition)
				{
					if(safeOne != pos)
					{
						//generate obstacle;
						GameObject tempObstacle = obstaclePool.GetObject();
						tempObstacle.transform.parent = tempLine.transform;
						tempObstacle.transform.localPosition = new Vector3 (pos, 0, 0);
					}
				}
			}

			if(_tilesUntilObstacle == -3)
			{
				if(engine.chainedSuccess > 3)
				{
					wagon.SetActive(true);
					wagon.transform.parent = tempLine.transform;
					wagon.transform.localPosition = new Vector3 (safeOne, 1, 0);
					engine.chainedSuccess = 0;
				}
			}
		}

		foreach (int pos in stopPosition) {
			GameObject temp = endTrackPool.GetObject ();
			temp.transform.parent = tempLine.transform;
			temp.transform.localPosition = new Vector3 (pos, 0, 0);
		}

		stopPosition.Clear ();

		foreach (int pos in gridPosition) {
			GameObject temp = trackToGenerate.GetObject ();
			temp.transform.parent = tempLine.transform;
			temp.transform.localPosition = new Vector3 (pos, (generateSplit ? -0.5f : 0), 0);
		}

		lastLine = tempLine;

		if (numTracks == 1) {
			gridPosition.Remove(trainGridPos);

			if(!gridPosition.Contains(trainGridPos + 1))
				gridPosition.Add(trainGridPos + 1);
			
			if(!gridPosition.Contains(trainGridPos - 1))
				gridPosition.Add(trainGridPos - 1);
		}

		if (numTracks == 2) {
			if(!gridPosition.Contains(trainGridPos))
				gridPosition.Add(trainGridPos);

			if(!gridPosition.Contains(trainGridPos + 1))
				gridPosition.Add(trainGridPos + 1);

			if(!gridPosition.Contains(trainGridPos - 1))
				gridPosition.Add(trainGridPos - 1);
		}

		numTracks = 0;
	}

	public void TrainMoved(int dir)
	{
		trainGridPos += dir;

		foreach (int pos in gridPosition) {
			if(pos != trainGridPos)
				if(!stopPosition.Contains(trainGridPos))
					stopPosition.Add(pos);
		}

		gridPosition.Clear();
		gridPosition.Add (trainGridPos);


	}

	public void LineDestroyed ()
	{
		GenerateNewLine ();
	}
	
	// Update is called once per frame
	void Update ()
	{

		if (startingInterval >= 0)
		{
			startingInterval -= Time.deltaTime;
		}

		if (startingInterval <= 0)
		{
			splitTrackInterval -= Time.deltaTime;
		}
		if (currentGround != null)
		{
			float currentHeight = currentGround[0].transform.position.y;
			if (currentHeight < -Camera.main.orthographicSize - 3)
			{
				float groundHeight = groundSprite.bounds.max.y - groundSprite.bounds.min.y;
				RecycleGrounds(currentHeight + 2 * groundHeight);
			}
		}
	}
}
