#pragma strict

enum EPlayerState
{
	Dead,
	Standing,
	Running,
	WallHug,
	Falling,
	Landing,
	Shooting,
};


var FootTurnSfx : AudioClip;
var FootFinalSfx : AudioClip;
var ClothSfx : AudioClip;
var ClothReversedSfx : AudioClip;
var HurtSfx : AudioClip;
var DeathSfx : AudioClip;

var MusicController : GameObject;
//var AlertMusic : AudioClip;
//var HiddingMusic : AudioClip;

var Health : float;
var Direction : Vector3 = new Vector3(1,0,0);

private var CharCtrl : CharacterController;
private var SubAnim : Animation;
private var Rotation : Quaternion;
private var FallSpeed : float = 0;

// INPUT FEED
@HideInInspector var I_MoveDir : Vector2 = Vector2(0,0);
@HideInInspector var I_Fire : boolean = false;
@HideInInspector var I_Walk : boolean = false;
@HideInInspector var C_HitTimeout : float = 0.1;
//

private var MoveDir : Vector3;
@HideInInspector var WallHugDir : Vector3;
var State : EPlayerState = EPlayerState.Standing;
private var OnGround : boolean = false;
private var AlertTimeout : float = 0;
private var LandTimeout : float = 0;
private var ShootComponents;
private var ShootTimeout : float = 0;
private var HitTimeout : float = 0;

@HideInInspector var AlertGUIStyle : GUIStyle = new GUIStyle();
var AlertGUIFont : Font;


function MakeWeaponAnimLayered( anim : String )
{
	SubAnim[ anim ].AddMixingTransform( transform.Find("player/Armature/Base/Belly") );
	SubAnim[ anim ].layer = 10;
	SubAnim[ anim ].enabled = true;
	SubAnim[ anim ].weight = 1.0;
}

function SetShootMode( shoot : boolean )
{
	for( var cmpt in ShootComponents )
	{
		var obj : GameObject = (cmpt as Component).gameObject;
		obj.SetActive( shoot );
		if(obj.audio)
		{
			obj.audio.enabled = shoot;
		}
	}
}

function Start()
{
	Direction.Normalize();
	CharCtrl = GetComponent(CharacterController);
	SubAnim = GetComponentsInChildren(Animation)[0] as Animation;
	Rotation = transform.rotation;
	
	AlertGUIStyle.font = AlertGUIFont;
	AlertGUIStyle.alignment = TextAnchor.MiddleCenter;
	MakeWeaponAnimLayered( "assaultRifle_fire" );
	MakeWeaponAnimLayered( "assaultRifle_hold" );
	SubAnim[ "assaultRifle_fire" ].speed = 4;
	SubAnim[ "assaultRifle_hold" ].speed = 0.1;
	
	SubAnim.CrossFade( "assaultRifle_hold", 0.2 );
	ShootComponents = GetComponentsInChildren(ShootRoot);
	SetShootMode( false );
}

function CommonStandRunChecks()
{
	// SHOOT
	if( I_Fire )
	{
		State = EPlayerState.Shooting;
		SubAnim.CrossFade("stand", 0.2);
		SubAnim.CrossFade("assaultRifle_fire", 0.1);
		ShootTimeout = 0.1;
		Agent.PlayClipAt(ClothSfx, transform.position);
		return true;
	}
	// WALLHUG
	var hitinfo : RaycastHit;
	var perpMoveDir : Vector3 = Vector3( MoveDir.z, MoveDir.y, MoveDir.x ) * 0.02;
	if( Physics.Raycast( Ray( transform.position - perpMoveDir, MoveDir.normalized ), hitinfo, 0.3 ) &&
		Physics.Raycast( Ray( transform.position + perpMoveDir, MoveDir.normalized ), hitinfo, 0.3 ) )
	{
		WallHugDir = hitinfo.normal;
		transform.position = hitinfo.point + hitinfo.normal * 0.1;
		State = EPlayerState.WallHug;
		SubAnim.CrossFade("wall_stand", 0.2);
		Agent.PlayClipAt(ClothSfx, transform.position);
		return true;
	}
	return false;
}

function Kill()
{
	SubAnim.CrossFade("death", 0.2);
	State = EPlayerState.Dead;
	SubAnim[ "assaultRifle_fire" ].enabled = false;
	SubAnim[ "assaultRifle_hold" ].enabled = false;
	Health = 0;
	Agent.PlayClipAt(DeathSfx, transform.position, 0.6);
	GetComponent(CharacterController).enabled = false;
}

function BulletHit()
{
	if( Health <= 0 || HitTimeout > 0 )
		return;
	SubAnim.CrossFade("hurt", 0.1);
	LandTimeout = 0.1;
	HitTimeout = C_HitTimeout;
	State = EPlayerState.Landing;
	Health -= 5;
	//if(Health % 20 == 0)
	//{
		Agent.PlayClipAt(HurtSfx, transform.position, 0.6);
	//}
	if( Health <= 0 )
		Kill();
}

// Called externally
function AlertTrigger()
{
	AlertTimeout = 15;
	if( MusicController != null )
		MusicController.SendMessage("Alert");
}

function Update()
{
	var OldMoveDir = MoveDir;
	MoveDir = new Vector3( I_MoveDir.x, 0, I_MoveDir.y );
	if(MoveDir != OldMoveDir && (State == EPlayerState.Standing || State == EPlayerState.Shooting))
	{
		if(MoveDir != Vector3.zero)
		{
			//Debug.Log("Turned");
			Agent.PlayClipAt(FootTurnSfx, transform.position);
		}
		else {
			//Debug.Log("Stopped");
			Agent.PlayClipAt(FootFinalSfx, transform.position);
		}
	}
	
	var velocity : Vector3 = new Vector3(0,0,0);
	
	if( HitTimeout > 0 )
		HitTimeout -= Time.deltaTime;
	
	// STATE MACHINE
	for(;;)
	{
		if( State == EPlayerState.Dead )
		{
			velocity += Vector3( 0, -6, 0 );
		}
		else if( State == EPlayerState.Standing )
		{
			velocity += Vector3( 0, -6, 0 );
			if( MoveDir.magnitude > 0.1 )
			{
				Direction = MoveDir.normalized;
				State = EPlayerState.Running;
				SubAnim.CrossFade("run", 0.2);
				break;
			}
			if( CommonStandRunChecks() ) break;
		}
		else if( State == EPlayerState.Falling )
		{
			FallSpeed += 20 * Time.deltaTime;
			velocity += Vector3( 0, -FallSpeed, 0 );
			if( OnGround )
			{
				State = EPlayerState.Landing;
				LandTimeout = 0.1;
				SubAnim.CrossFade("land", 0.01);
				Agent.PlayClipAt(FootFinalSfx, transform.position);
				break;
			}
		}
		else if( State == EPlayerState.Landing )
		{
			LandTimeout -= Time.deltaTime;
			if( LandTimeout <= 0 )
			{
				SubAnim.CrossFade("stand", 0.2);
				State = EPlayerState.Standing;
				break;
			}
		}
		else if( State == EPlayerState.Running )
		{
			var movevec : Vector3 = ( MoveDir.magnitude < 0.9 ? MoveDir : Direction ) * ( I_Walk ? 1.5 : 4 );
			if( movevec.magnitude < 2 )
				SubAnim.CrossFade("walk", 0.2);
			else
				SubAnim.CrossFade("run", 0.2);
			
			Direction = Vector3.RotateTowards( Direction, MoveDir.normalized, Time.deltaTime * Mathf.PI * 2, 0.0f );
			Rotation = Quaternion.LookRotation( Direction );
			
			velocity += movevec;
			
			if( !OnGround ){ State = EPlayerState.Falling; FallSpeed = 0; SubAnim.CrossFade("falling", 0.2); break; }
			if( MoveDir.magnitude <= 0.1 ){ State = EPlayerState.Standing; SubAnim.CrossFade("stand", 0.2); break; }
			if( CommonStandRunChecks() ) break;
			
			velocity += Vector3( 0, -6, 0 );
		}
		else if( State == EPlayerState.WallHug )
		{
			Direction = WallHugDir;
			Rotation = Quaternion.LookRotation( Direction );
			
			var hitinfo : RaycastHit;
			if( Physics.Raycast( Ray( transform.position + WallHugDir * 0.1, -WallHugDir ), hitinfo, 0.3 ) )
			{
				transform.position = hitinfo.point + WallHugDir * 0.1;
			}
			
			if( Vector3.Dot( MoveDir, WallHugDir ) > -0.71 )
			{
				transform.position += WallHugDir * 0.1;
				State = EPlayerState.Standing;
				break;
			}
			
			var allowedMove : Vector3 = Vector3( WallHugDir.z, WallHugDir.y, -WallHugDir.x );
			var movement : Vector3 = Vector3.Dot( allowedMove, MoveDir ) * allowedMove;
			var moveDirSign : float = Mathf.Sign( Vector3.Dot( allowedMove, MoveDir.normalized ) );
			var movementNormalized : Vector3 = moveDirSign * allowedMove;
			
			if( movement.magnitude > 0.1 && Physics.Raycast( transform.position + movementNormalized * 0.1, ( movementNormalized - WallHugDir ).normalized, 0.3 ) )
			{
				SubAnim.CrossFade( moveDirSign > 0 ? "wall_left" : "wall_right", 0.2 );
				velocity += movement * 0.4;
			}
			else
				SubAnim.CrossFade( "wall_stand", 0.2 );
		}
		else if( State == EPlayerState.Shooting )
		{
			Direction = Vector3.RotateTowards( Direction, MoveDir.normalized, Time.deltaTime * Mathf.PI * 2, 0.0f );
			Rotation = Quaternion.LookRotation( Direction );
			
			velocity += Vector3( 0, -6, 0 );
			
			if( ShootTimeout <= 0 )
			{
				SetShootMode( true );
				ShootTimeout = 0.12;
			}
			else
				ShootTimeout -= Time.deltaTime;
			if( !I_Fire )
			{
				State = EPlayerState.Standing;
				SetShootMode( false );
				SubAnim.CrossFade("assaultRifle_hold", 0.2);
				Agent.PlayClipAt(ClothReversedSfx, transform.position);
				break;
			}
		}
		break;
	}
	
	CharCtrl.Move( velocity * Time.deltaTime );
	OnGround = CharCtrl.isGrounded;
	
	transform.rotation = Quaternion.RotateTowards( transform.rotation, Rotation, Time.deltaTime * 1000 );
	
	if( AlertTimeout > 0 )
	{
		AlertTimeout -= Time.deltaTime;
		if( AlertTimeout <= 0 )
		{
			if( MusicController != null )
				MusicController.SendMessage("AlertStopped");
			//MusicController.SendMessage("Interrupt", HiddingMusic);
		}
	}
}

function OnGUI()
{
	var W = Screen.width;
	var H = Screen.height;
	var min_size = Mathf.Min( W, H );
	var unit_big = min_size / 10;
	var unit_small = min_size / 50;
	var unit_xsm = min_size / 200;
	//GUI.Box( new Rect( unit_small, unit_small, unit_big * 3, unit_small * 2 ), "" );
	//GUI.Box( new Rect( unit_small + unit_xsm, unit_small + unit_xsm, unit_big * 3 - unit_xsm * 2, unit_small * 2 - unit_xsm * 2 ), "" );
	if( AlertTimeout > 0 )
	{
		GUI.color = Color(0.8,0.2,0,Mathf.Sin(Time.time*Mathf.PI*2)*0.2+0.8);
		AlertGUIStyle.fontSize = unit_big;
		AlertGUIStyle.normal.textColor = GUI.color;
		GUI.Label( new Rect( W - unit_big * 3, unit_small, unit_big * 3 - unit_small, unit_big ), "ALERT", AlertGUIStyle );
		GUI.color = Color(1,1,1);
	}
}

function Action(){ Debug.Log("Action"); }

