﻿using UnityEngine;
using System.Collections;

public class FormationController : MonoBehaviour {
	// adjust/set in inspector!
	public GameObject enemyPrefab;
	public float reverseBuffer = -2.12f;
	public float reverseSquelch = 1.12f;
	public float spawnDelay = 0.8f;
	public GameObject resetButton;

	private float baseAcceleration, direction, maxSpeed, padding, spawnTime, speed, xMax, xMin;
	private bool afterMatch, decelerate, gameStarted, passGo, respawn, right, shoot;
	private ArrayList enemies;
	private int finalWave;
	private GameManager gameManager;

	public void EnemyAdd (GameObject enemy) { enemies.Add (enemy); }

	void OnDrawGizmos () { Gizmos.DrawWireCube(transform.position, new Vector3 (8,8,1)); }
	float SetXClamps (float position) { return Mathf.Clamp(position, xMin, xMax); }

	void Start () {
		gameManager = GameObject.FindObjectOfType<GameManager>();
			if (!gameManager) Debug.LogError ("GAME_MANAGER_FAIL_Start");

		baseAcceleration = 0.10f;
		decelerate = true;
		enemies = new ArrayList();
		finalWave = 42;
		maxSpeed = 9f;
		padding = 3.6f;
		right = true;
		speed = baseAcceleration;
		SetMinMaxX();
	}

	void Update () {
		// set position
		transform.position += new Vector3 (speed * Time.deltaTime, 0f, 0f);

		// test and flip TODO fix this
		if (transform.position.x >= xMax) { right = !right; speed = -0.33f; decelerate = false; }
		else if (transform.position.x <= xMin) { right = !right; speed = 0.35f; decelerate = false; }

		// accelerator
		if (right && speed < maxSpeed) speed += baseAcceleration;
		else if (!right && speed > -maxSpeed) speed -= baseAcceleration;

		if (speed == maxSpeed) decelerate = true;

	//	passGo = right;
		// decelerator
		if (decelerate) { // TODO finish deceleration 
			if (transform.position.x < xMin - reverseBuffer || transform.position.x > xMax + reverseBuffer)  {
				Debug.Log ("squelch");
				speed = speed / reverseSquelch;
			} //else if (transform.position.x <= xMin || transform.position.x >= xMax ) { right = !right; decelerate = false; }
		}
	}

	public void TriggerRespawn () {
		respawn = true;
		gameStarted = true;
		Invoke ("Respawn", spawnDelay);
	}

	void FixedUpdate () {
		// TODO come up with a *good* win condition, furthermore let levelmanager control wins and losses
		if (gameManager.GetScore() > 50000f) {
			Despawner();
			gameManager.WinBattle();
		}

		// win after X waves?
		if (gameManager.GetWaveNumber() == finalWave && FormationIsEmpty()) {
			Despawner();
			gameManager.WinBattle();
		}

		// formation spawn control
		afterMatch = resetButton.activeSelf;
		if (FormationIsFull()) { respawn = false; gameManager.HideWave(); }
		if (FormationIsEmpty() && !respawn && !afterMatch) { TriggerRespawn(); }
		if (gameManager.GetEnemies() == 0 && !respawn && gameStarted && !afterMatch) { TriggerRespawn(); }
	}

	bool FormationIsEmpty () {
		foreach(Transform childPositionGameObject in transform) {
			if (childPositionGameObject.childCount > 0) return false;
		} return true;
	}

	Transform NextFreePosition () {
		foreach(Transform childPosition in transform) {
			if (childPosition.childCount == 0) return childPosition;
		} return null;
	}

	void Respawn () {
		gameManager.ShowWave();
		Transform freePos = NextFreePosition();
		if (freePos) FillPosition(freePos);
		if (NextFreePosition()) Invoke("Respawn", spawnDelay);
		else if (FormationIsFull() && gameManager.GetWaveNumber() < finalWave) gameManager.IncrementWaveNumber();
	}

	bool FormationIsFull () {
		foreach(Transform childPosition in transform) {
			if (childPosition.childCount == 0) return false;
		} return true;
	}

	void FillPosition (Transform pos) {
		GameObject enemy = Instantiate(enemyPrefab, pos.transform.position, Quaternion.identity) as GameObject;
		EnemyAdd(enemy);
		enemy.transform.parent = pos;
		gameManager.EnemyUp();
	}

	public void Despawner () {
		foreach (GameObject enemy in enemies) {
			Destroy (enemy, 0.001f);
		}
		gameManager.ZeroEnemies();
	}

	void SetMinMaxX () {
		float distance = transform.position.z - Camera.main.transform.position.z;
		Vector3 leftBoundary = Camera.main.ViewportToWorldPoint(new Vector3(0,0,distance));
		Vector3 rightBoundary = Camera.main.ViewportToWorldPoint(new Vector3(1,0,distance));
		xMax = rightBoundary.x - padding;
		xMin = leftBoundary.x + padding;
	}
}
