using UnityEngine;
using System.Collections;

[RequireComponent (typeof (Rigidbody2D))]
[RequireComponent (typeof (PlayerStatus))]
public class PlayerMovementController : MonoBehaviour {

	//public float WalkSpeed=5f;
	private PlayerStatus pstat;

	public float BaseForwardSpeed;
	public float ForwardSpeedBonus;

	public float LowSpeed;
	public float MedSpeed;
	public float HighSpeed;
	public float Accel;

	public float SteerSpeed;
	public float SteerThrust;
	public float TurnRampupTime;
	public Vector2 MoveInput { get; set; }
	public int JukeInput;
	public bool UpKeyDown;
	public bool DownKeyDown;
	public bool LeftKeyDown;
	public bool RightKeyDown;

	private int throttle;
	private int steer;
	private float lastSteerIdleTime;


	void Start () {
		pstat = gameObject.GetComponent<PlayerStatus>();

	}
	
	void Update () {
		SetThrottle();
		SetSteer();
	}

	void FixedUpdate()
	{
		/*
		 * explore mode code has more buttons so you can turn the ship AND strafe, camera follows rotation etc.
		ExploreDrive ();
		ExploreTurn ();
		ExploreJuke();
		*/
		SimpleDrive();
		Turn ();
	}

	private void SetThrottle()
	{
		if(UpKeyDown)
		{
			if(throttle < 0)
				throttle = 0;
			else
				throttle++;

			if(throttle>3)
				throttle = 3;
			UpKeyDown = false;  // "consume" the keypress when we move the controls
		}
		else if(DownKeyDown)
		{
			if (throttle > 0)
				throttle = 0;
			else 
				throttle--;

			if(throttle < -2)
				throttle = -2;
			DownKeyDown = false;
		}
	}
	
	private void SetSteer()
	{
		if(MoveInput.x == -1)
		{
			steer = -1;
		}
		else if(MoveInput.x == 1)
		{
			steer = 1;
		}
		else
		{
			steer = 0;
			lastSteerIdleTime = Time.fixedTime;
		}
	}

	private void ExploreDrive()
	{
		float tspeed = 0;
		if(throttle == 1)
			tspeed = LowSpeed;
		else if(throttle == 2)
			tspeed = MedSpeed;
		else if(throttle == 3)
			tspeed = HighSpeed;
		else if(throttle == -1)
			tspeed = -LowSpeed*0.8f;
		else if(throttle == -2)
			tspeed = -MedSpeed*0.8f;

		Vector2 tdelta = (tspeed * (Vector2)transform.up.normalized) - rigidbody2D.velocity;
		float a = Accel * Time.fixedDeltaTime;
		if(Vector2.Dot((Vector2)rigidbody2D.velocity, tdelta) <0)  // double "turnaround accel"
			a *= 2;
		Vector2 delta = (tdelta.magnitude > a) ? tdelta.normalized*a : tdelta;
		Vector2 force = rigidbody2D.mass * delta / Time.fixedDeltaTime;

//		Debug.Log ("DRIVE: tspeed = " + tspeed + " delta = " + delta + " of " + tdelta + ", force = " + force + " forward is " + transform.up.normalized);
		rigidbody2D.AddForce(force);
	}
	
	private void ExploreTurn()
	{
		if(steer == 0)
			return;
		
		float ramp = Mathf.Min (1,(Time.fixedTime - lastSteerIdleTime) / TurnRampupTime);
		float factor = 0.3f + 0.7f*ramp*ramp;
		
		float turn = factor * SteerSpeed * -steer * Time.fixedDeltaTime;
		transform.eulerAngles += new Vector3(0, 0, turn);
		
		//Vector2 curr = new Vector2(rigidbody2D.velocity.x, 0);
		//Vector2 delta = new Vector2(factor*steer*SteerThrust, 0) - curr;
		//Vector2 force = rigidbody2D.mass * delta / Time.fixedDeltaTime;
		//rigidbody2D.AddRelativeForce(force);
	}

	private void ExploreJuke()
	{
		// a.b * a
		//Vector2 currSideVel = rigidbody2D.velocity * Vector3.Cross(transform.up, rigidbody2D.velocity).magnitude;
		Vector2 currSideVel   = ((Vector2)transform.right).normalized * Vector2.Dot((Vector2)transform.right, rigidbody2D.velocity);
		Vector2 targetSideVel = ((Vector2)transform.right).normalized * JukeInput * SteerThrust;
		Vector2 tdelta = targetSideVel - currSideVel;
		Vector2 delta = (tdelta.magnitude > Accel) ? tdelta.normalized*Accel : tdelta;

		Vector2 force = rigidbody2D.mass * delta / Time.fixedDeltaTime;

		//Debug.Log("JUKE: vel = " + rigidbody2D.velocity + " facing " + transform.eulerAngles.z + " currSideVel = " + currSideVel + " targetSideVel = " + targetSideVel + " tdelta " + tdelta + " capped to " + delta);
		rigidbody2D.AddForce(force);
	}

	private void Turn()
	{
		if(steer == 0)
			return;

		float ramp = Mathf.Min (1,(Time.fixedTime - lastSteerIdleTime) / TurnRampupTime);
		float factor = 0.3f + 0.7f*ramp*ramp;
				
		//float turn = factor * SteerSpeed * -steer * Time.fixedDeltaTime;
		//transform.eulerAngles += new Vector3(0, 0, turn);

		Vector2 curr = new Vector2(rigidbody2D.velocity.x, 0);
		Vector2 delta = new Vector2(factor*steer*SteerThrust, 0) - curr;
		Vector2 force = rigidbody2D.mass * delta / Time.fixedDeltaTime;
		rigidbody2D.AddRelativeForce(force);
	}

	private void SimpleDrive()
	{
		//float bonus = 0;
		//if(MoveInput.y > 0)
		//	bonus = ForwardSpeedBonus;
		//else if(MoveInput.y < 0)
		//	bonus = -ForwardSpeedBonus*0.5f;

		float tspeed = BaseForwardSpeed;// + bonus;

		Vector2 tdelta = (tspeed * (Vector2)transform.up.normalized) - rigidbody2D.velocity;
		float a = Accel * Time.fixedDeltaTime;
		Vector2 delta = (tdelta.magnitude > a) ? tdelta.normalized*a : tdelta;
		Vector2 force = rigidbody2D.mass * delta / Time.fixedDeltaTime;
		rigidbody2D.AddForce(force);
	}

	private void Walk()
	{
		Vector2 targetspeed = pstat.WalkingSpeed * MoveInput.normalized;
		Vector2 deltaspeed = targetspeed - rigidbody2D.velocity;
		Vector2 force = rigidbody2D.mass * deltaspeed / Time.fixedDeltaTime;
		rigidbody2D.AddForce(force);
	}

}
