using UnityEngine;
using System.Collections;

public struct InputData{
	public float forward;
	public float left;
	public float right;
	public float torqueLeft;
	public float torqueRight;
	public InputData(float _forward, float _left, float _right, float _torqueLeft, float _torqueRight){
		this.forward = _forward;
		this.left = _left;
		this.right = _right;
		this.torqueLeft = _torqueLeft;
		this.torqueRight = _torqueRight;
	}
};

public class Canoo1 : MonoBehaviour {
	public GameObject leftPaddle;
	public GameObject rightPaddle;
	public GameObject player1;
	public GameObject player2;
	public GameObject player3;
	public GameObject player4;
	private SpriteAnimation LPaddleScript;
	private SpriteAnimation RPaddleScript;
	public int moneyOnBoard = 0;
	public int canooNumber = 1;
	public int[] playersOnBoard = new int[2];
	
	public float forward = 0.0f;
	public float left = 0.0f;
	public float right = 0.0f;
	public static float forwardMultiplier = -2f;
	public static float velocityMultiplier = 30.0f;
	public float turningMultiplier = 2.0f;
	public float torqueConstant = 1.0f;
	public float torqueLeft = 0.0f;
	public float torqueRight = 0.0f;
	public bool isLeftPlayer = true;
	public GameObject canoo;
	private Canoo1_delayed delayed;
	public InputData[] history = new InputData[50]; // Frames to remember
	private int frame = 0;
	private bool started = false;
	private Transform initialTransform;
	private float maxRotation = 20.0f;
	public Quaternion rotationStart;
	public Quaternion rotationLeft;
	public Quaternion rotationRight;
	public bool shouldRotateRight = false;
	public bool shouldRotateLeft = false;
	public bool rotateBackFromLeft = false;
	public bool rotateBackFromRight = false;
	public float currentRotation;
	public float rotationTimeFactor = 2.0f;
	public float timeSinceLeft = 1.0f;
	public float timeSinceRight = 1.0f;
	public bool isLeftMashing = false;
	public bool isRightMashing = false;
	public float mashingLimit = 0.5f;
	public float mashingTimeout = 1.0f;
	public float speedBoostWindow = 0.2f;
	public float speedBoostTimeout = 5.0f;
	public float timeSinceSpeedBoost = 5.0f;
	public bool isFighting = false;
	public int fightPressedPlayer1 = 0;
	public int fightPressedPlayer2 = 0;
	
	// Use this for initialization
	void Start () {
		//initialTransform = gameObject.transform;
		delayed = canoo.GetComponent("Canoo1_delayed") as Canoo1_delayed;
		LPaddleScript = leftPaddle.GetComponent("SpriteAnimation") as SpriteAnimation;
		RPaddleScript = rightPaddle.GetComponent("SpriteAnimation") as SpriteAnimation;
		rotationStart = gameObject.transform.rotation;
		rotationLeft = rotationStart * Quaternion.Euler(new Vector3(0, 0, -maxRotation));
		rotationRight = rotationStart * Quaternion.Euler(new Vector3(0, 0, maxRotation));
		
	}
	
	// Update is called once per frame
	void Update () {
		forward = 0.0f;
		left = 0.0f;
		right = 0.0f;
		torqueLeft = 0.0f;
		torqueRight = 0.0f;
		//rotationTarget = 0.0f;
		timeSinceLeft += Time.deltaTime;
		timeSinceRight += Time.deltaTime;
		timeSinceSpeedBoost += Time.deltaTime;
		
		// Test for fighting
		if (! isFighting){
			updateFightStatus();
		}
		else {
			if (isFightPressed(0)){
				fightPressedPlayer1 += 1;
				if (fightPressedPlayer1 > 20){
					fightWonBy(0);
				}
			}
			if (isFightPressed(1)){
				fightPressedPlayer2 += 1;
				if (fightPressedPlayer2 > 20){
					fightWonBy(1);
				}
			}
			
		}
		// Test for mashing baddies
		if (timeSinceLeft > mashingLimit){
			isLeftMashing = false;
		}
		if (timeSinceRight > mashingLimit){
			isRightMashing = false;
		}
		if (!(isLeftMashing	|| isRightMashing )){
			if (((timeSinceLeft < speedBoostWindow && isRightPressed()) ||
			    (timeSinceRight < speedBoostWindow && isLeftPressed()) ||
			     isLeftPressed() && isRightPressed()) &&
			    timeSinceSpeedBoost > speedBoostTimeout){
				
				gameObject.rigidbody.AddForce(new Vector3(0, - 4.0f * velocityMultiplier * forwardMultiplier, 0));
				timeSinceSpeedBoost = 0.0f;
				rotateBackFromLeft = shouldRotateLeft;
				shouldRotateLeft = false;
				rotateBackFromRight = shouldRotateRight;
				shouldRotateRight = false;
				return;
			}
		}
		if (isLeftPressed()){
			handleLeftButton();
		}
		if (isRightPressed()){
			handleRightButton();
		}
		if (left > 0) {
			if (!shouldRotateLeft){
				shouldRotateRight = false;
				shouldRotateLeft = true;
				rotateBackFromLeft = false;
				rotateBackFromRight = false;
			}
		}
		if (right > 0) {
			if (!shouldRotateRight){
				shouldRotateLeft = false;
				shouldRotateRight = true;
				rotateBackFromLeft = false;
				rotateBackFromRight = false;
			}
		}
		currentRotation = Quaternion.Angle( transform.rotation, rotationStart);
		if (shouldRotateRight) {
			//Quaternion change = Quaternion.Euler(0, 0, maxRotation*Time.deltaTime*rotationTimeFactor);
			transform.rotation = Quaternion.Slerp(transform.rotation, rotationRight, Time.deltaTime*rotationTimeFactor*2);
			if (Mathf.Abs(currentRotation)	> maxRotation - 2.0f ){
				shouldRotateRight = false;
				rotateBackFromRight = true;
				rotateBackFromLeft = false;
			}
		} else if (shouldRotateLeft) {
			//Quaternion change = Quaternion.Euler(0, 0, -maxRotation*Time.deltaTime*rotationTimeFactor);
			transform.rotation = Quaternion.Slerp(transform.rotation, rotationLeft, Time.deltaTime*rotationTimeFactor*2);
			if (Mathf.Abs(currentRotation)	> maxRotation - 2.0f ){
				shouldRotateLeft = false;
				rotateBackFromLeft = true;
				rotateBackFromRight = false;
			}
		} else { // Should rotate back
			if (Mathf.Abs(currentRotation)	> 1.0f){
				//Quaternion change;
//				if (rotateBackFromLeft){
//					//change = Quaternion.Euler(0, 0, maxRotation*Time.deltaTime*rotationTimeFactor);
					transform.rotation = Quaternion.Slerp(transform.rotation, rotationStart, Time.deltaTime*rotationTimeFactor*2);
//				} else if (rotateBackFromRight) {
					//change = Quaternion.Euler(0, 0, -maxRotation*Time.deltaTime*rotationTimeFactor);
//					transform.rotation = Quaternion.Slerp(transform.rotation, rotationStart, Time.deltaTime*rotationTimeFactor*2);
//				}
			} else {
				rotateBackFromLeft = false;
				rotateBackFromRight = false;
			}
		}
		
		gameObject.rigidbody.AddRelativeForce(new Vector3((left + -right) * turningMultiplier, -Mathf.Abs(forward) * forwardMultiplier, 0));

		history[frame] = new InputData(forward, left, right, torqueLeft, torqueRight);
		
		frame++;
		if(frame > 49){
			frame = 0;
			if(!started){
				started = true;
				delayed.init();
			}
		}
	}
	
	public InputData getHistory(int index){
		return history[index];
	}
	
	public void handleLeftButton(){
		if (isLeftMashing) {
			isLeftMashing = (timeSinceLeft < mashingTimeout);
		} else {
			isLeftMashing = (timeSinceLeft < mashingLimit);
		}
		LPaddleScript.Play();	 
		left = velocityMultiplier * Mathf.Min(1.0f, timeSinceLeft * timeSinceLeft);
		forward = velocityMultiplier * Mathf.Min(1.0f, timeSinceLeft * timeSinceLeft);
		timeSinceLeft = 0.0f;
	}
	
	public void handleRightButton(){
		if (isRightMashing) {
			isRightMashing = (timeSinceRight < mashingTimeout);
		} else {
			isRightMashing = (timeSinceRight < mashingLimit);
		}
		RPaddleScript.Play();	 
		right = velocityMultiplier * Mathf.Min(1.0f, timeSinceRight * timeSinceRight);
		forward = velocityMultiplier * Mathf.Min(1.0f, timeSinceRight * timeSinceRight);
		timeSinceRight = 0.0f;
	}
	
	public bool isLeftPressed(){
//		if (isLeftPlayer) {
//			return Input.GetKeyUp(KeyCode.A);
//			
//		} else {
//						
//			return Input.GetKeyUp(KeyCode.LeftArrow);
//		}
		switch(playersOnBoard[1]){
			case 1:
				return Input.GetKeyUp(KeyCode.Q);
			break;
			case 2:
				return Input.GetKeyUp(KeyCode.V);
			break;
			case 3:
				return Input.GetKeyUp(KeyCode.I);
			break;
			case 4:
				return Input.GetKeyUp(KeyCode.DownArrow);
			break;
			default:
				return false;
			break;
		}
	}
	
	public bool isRightPressed(){
//		if (isLeftPlayer) {
//			return Input.GetKeyUp(KeyCode.D);
//			
//		} else {
//						
//			return Input.GetKeyUp(KeyCode.RightArrow);
//		}
		switch(playersOnBoard[0]){
			case 1:
				return Input.GetKeyUp(KeyCode.Q);
			break;
			case 2:
				return Input.GetKeyUp(KeyCode.V);
			break;
			case 3:
				return Input.GetKeyUp(KeyCode.I);
			break;
			case 4:
				return Input.GetKeyUp(KeyCode.DownArrow);
			break;
			default:
				return false;
			break;
		}
	}
	
	void OnTriggerEnter(Collider col){
		if(col.gameObject.tag == "gold"){
			Gold goldScript;
			goldScript = col.gameObject.GetComponent("Gold") as Gold;
			moneyOnBoard += goldScript.value;
			goldScript.Reset();
        	Debug.Log("Boat now has " + moneyOnBoard + " gold!");
		} else if(col.gameObject.tag == "checkpoint"){
			Debug.Log("Checkpoint hit");
			cashTransfer();
		}
	}
	
	void OnCollisionEnter(Collision col)
    {
		if(col.gameObject.tag == "player"){
			Debug.Log("I hit a player!");
			Player playerScript;
			playerScript = col.gameObject.GetComponent("Player") as Player;
			if(playerScript.state == (int)playerState.SWIMMING){
				playerScript.collider.enabled = false;
				pushPopPlayersAboard(playerScript.playerNumber);
				Debug.Log("He's number " + playerScript.playerNumber);
				playerScript.currentCanoo = canooNumber;
				playerScript.state = (int)playerState.IDLE;
			}
		}
		
    }
	
	void cashTransfer(){ // This function should be called at every checkpoint. It distributes the money from the canoo the players onboard.
		Player playerScript1, playerScript2, playerScript3, playerScript4;
		playerScript1 = player1.GetComponent("Player") as Player;
		playerScript2 = player2.GetComponent("Player") as Player;
		playerScript3 = player3.GetComponent("Player") as Player;
		playerScript4 = player4.GetComponent("Player") as Player;
		if(playersOnBoard[0] == 0 && playersOnBoard[1] == 0) // Empty Canoo - value reset, and that's it.!
			moneyOnBoard = 0;
		else if(playersOnBoard[0] != 0 && playersOnBoard[1] == 0){ // Front seat is taken
			switch(playersOnBoard[0]){
				case 1:
					playerScript1.money += moneyOnBoard;
				break;
				case 2:
					playerScript2.money += moneyOnBoard;
				break;
				case 3:
					playerScript3.money += moneyOnBoard;
				break;
				case 4:
					playerScript4.money += moneyOnBoard;
				break;
			}
		}
		else if(playersOnBoard[0] == 0 && playersOnBoard[1] != 0){ // Back seat is taken
			switch(playersOnBoard[1]){
				case 1:
					playerScript1.money += moneyOnBoard;
				break;
				case 2:
					playerScript2.money += moneyOnBoard;
				break;
				case 3:
					playerScript3.money += moneyOnBoard;
				break;
				case 4:
					playerScript4.money += moneyOnBoard;
				break;
			}
		}
		else {// Both seats are taken
			switch(playersOnBoard[0]){
				case 1:
					playerScript1.money += moneyOnBoard / 2;
				break;
				case 2:
					playerScript2.money += moneyOnBoard / 2;
				break;
				case 3:
					playerScript3.money += moneyOnBoard / 2;
				break;
				case 4:
					playerScript4.money += moneyOnBoard / 2;
				break;
			}
			switch(playersOnBoard[1]){
				case 1:
					playerScript1.money += moneyOnBoard / 2;
				break;
				case 2:
					playerScript2.money += moneyOnBoard / 2;
				break;
				case 3:
					playerScript3.money += moneyOnBoard / 2;
				break;
				case 4:
					playerScript4.money += moneyOnBoard / 2;
				break;
			}
		}
		moneyOnBoard = 0;
	}
		
				
	
	void pushPopPlayersAboard(int newPlayerIndex){
		if((playersOnBoard[0] != 0 && playersOnBoard[1] != 0) || (playersOnBoard[0] != 0 && playersOnBoard[1] == 0)){
			Player playerScript;
			switch(playersOnBoard[1]){
				case 1:
					playerScript = player1.GetComponent("Player") as Player;
				break;
				case 2:
					playerScript = player2.GetComponent("Player") as Player;
				break;
				case 3:
					playerScript = player3.GetComponent("Player") as Player;
				break;
				case 4:
					playerScript = player4.GetComponent("Player") as Player;
				break;
				default:
					playerScript = player4.GetComponent("Player") as Player;
				break;
			}
			playerScript.abandonShip(true);
			playersOnBoard[1] = playersOnBoard[0];
			playersOnBoard[0] = newPlayerIndex;
		}
		else
			playersOnBoard[0] = newPlayerIndex;
	}
	
	public void popPlayerAboard(int playerIndex){
		if(playersOnBoard[0] == playerIndex)
			playersOnBoard[0] = 0;
		else if(playersOnBoard[1] == playerIndex)
			playersOnBoard[1] = 0;
	}
	
	public bool isTop(int playerIndex){
		if(playersOnBoard[0] == playerIndex)
			return true;
		else
			return false;
	}
	public bool isFightPressed(int playerIndex){
		switch(playersOnBoard[playerIndex]){
			case 1:
				return Input.GetKeyUp(KeyCode.W);
			break;
			case 2:
				return Input.GetKeyUp(KeyCode.B);
			break;
			case 3:
				return Input.GetKeyUp(KeyCode.O);
			break;
			case 4:
				return Input.GetKeyUp(KeyCode.RightArrow);
			break;
			default:
				Debug.Log("Shouldn't happen");
				return false;
			break;
		}
	}
	public void updateFightStatus(){
		isFighting = isFightPressed(0) || isFightPressed(1);
		
	}
	
	public void fightWonBy(int playerIndex){
		isFighting = false;
		fightPressedPlayer1 = 0;
		fightPressedPlayer2 = 0;
		if (playerIndex	== 0){
			Player playerScript;
			switch(playersOnBoard[1]){
				case 1:
					playerScript = player1.GetComponent("Player") as Player;
				break;
				case 2:
					playerScript = player2.GetComponent("Player") as Player;
				break;
				case 3:
					playerScript = player3.GetComponent("Player") as Player;
				break;
				case 4:
					playerScript = player4.GetComponent("Player") as Player;
				break;
				default:
					playerScript = player4.GetComponent("Player") as Player;
				break;
			}
			playerScript.lostFight();
		} else {
			Player playerScript;
			switch(playersOnBoard[0]){
				case 1:
					playerScript = player1.GetComponent("Player") as Player;
				break;
				case 2:
					playerScript = player2.GetComponent("Player") as Player;
				break;
				case 3:
					playerScript = player3.GetComponent("Player") as Player;
				break;
				case 4:
					playerScript = player4.GetComponent("Player") as Player;
				break;
				default:
					playerScript = player4.GetComponent("Player") as Player;
				break;
			}
			playerScript.lostFight();
		}
	}
}
