//
// 2014/03/13 N.Kobyasahi
//
// Add Flying by Fumi.Iseki
// 2015/05/01 
// 2015/07/11
//

using UnityEngine;
using System.Collections;

namespace UnityChan
{
	// �K�v�ȃR���|�[�l���g�̗�L
	[RequireComponent(typeof(Animator))]
	[RequireComponent(typeof(CapsuleCollider))]
	[RequireComponent(typeof(Rigidbody))]
	
	public class UnityChanControlScriptWithRgidBody : MonoBehaviour
	{
        public bool  showInteraction = true;
		public float animSpeed = 1.5f;			// �A�j���[�V�����Đ����x�ݒ�
		public float lookSmoother = 3.0f;		// a smoothing setting for camera motion
		public bool  useCurves = true;			// Mecanim�ŃJ�[�u�������g�����ݒ肷��. ���̃X�C�b�`�������Ă��Ȃ��ƃJ�[�u�͎g���Ȃ�
		public float useCurvesHeight = 0.5f;	// �J�[�u�␳�̗L�������i�n�ʂ����蔲���₷�����ɂ͑傫������j
		
		public float flyingSpeed   = 10.0f;		// ��s���x
		public float runningSpeed  = 5.0f;		// ���鑬�x
		public float forwardSpeed  = 2.5f;		// �������x
		public float backwardSpeed = 2.0f;		// ��ޑ��x
		public float rotateSpeed   = 0.8f;		// ���񑬓x
		public float jumpPower     = 3.0f;		// �W�����v��
		
		private CapsuleCollider cldr;			// �L�����N�^�[�R���g���[���i�J�v�Z���R���C�_�j�̎Q��
		private Rigidbody rbdy;
		private Vector3 velocity;				// �L�����N�^�[�R���g���[���i�J�v�Z���R���C�_�j�̈ړ���
		private float orgColHight;
		private Vector3 orgVectColCenter;
		private Animator anim;					// �L�����ɃA�^�b�`�����A�j���[�^�[�ւ̎Q��
		private AnimatorStateInfo animState;	// base layer�Ŏg����A�A�j���[�^�[�̌��݂̏�Ԃ̎Q��
		private GameObject cameraObject;		// ���C���J�����ւ̎Q��

		// �A�j���[�^�[�e�X�e�[�g�ւ̎Q��
		static int idleState  = Animator.StringToHash ("Base Layer.Idle");
		static int runState   = Animator.StringToHash ("Base Layer.Running");
		static int jumpState  = Animator.StringToHash ("Base Layer.Jump");
		static int restState  = Animator.StringToHash ("Base Layer.Rest");
		//static int walkState  = Animator.StringToHash ("Base Layer.Walking");
		//static int hoverState = Animator.StringToHash ("Base Layer.Hovering");
		//static int upState    = Animator.StringToHash ("Base Layer.Up");
		//static int downState  = Animator.StringToHash ("Base Layer.Down");
		
		private int   flying  = 0;		// 0: Land, 1: Flaying
		private int   forward = 0;		// 0: Stop, 1: forwarding, 2:Running
		private uint  clicktm = 0;

		private bool  uparrowKey = false;
		private bool  homeKey    = false;
		private bool  jumpKey    = false;


		//
		// ������
		void Start ()
		{
			anim = GetComponent<Animator> ();			// Animator�R���|�[�l���g���擾����
			cldr = GetComponent<CapsuleCollider> ();	// CapsuleCollider�R���|�[�l���g���擾����i�J�v�Z���^�R���W�����j
			rbdy = GetComponent<Rigidbody> ();
			orgColHight = cldr.height;					// CapsuleCollider�R���|�[�l���g��Height�ACenter�̏����l��ۑ�����
			orgVectColCenter = cldr.center;
			cameraObject = GameObject.FindWithTag ("MainCamera");
		}


		void Update()
		{
			if (Input.GetKeyDown (KeyCode.UpArrow)) uparrowKey = true;
			if (Input.GetKeyDown (KeyCode.Home)) homeKey = true;
			if (Input.GetKeyDown (KeyCode.Space)) jumpKey = true;
		}


		//
		// �ȉ��A���C������.���W�b�h�{�f�B�Ɨ��߂�̂ŁAFixedUpdate���ŏ������s��.
		void FixedUpdate ()
		{
			float h = Input.GetAxis ("Horizontal");
			float v = Input.GetAxis ("Vertical");

			if (flying==0) {
				if (uparrowKey) {
					if (clicktm <= 20) {
						//Debug.Log("Run! "+clicktm);
						forward = 2;
						anim.SetBool ("Running", true);
						anim.SetBool ("Walking", false);
					}
					uparrowKey = false;
					clicktm = 0;
				}
				//
				else {
					if (forward == 0 && v>0.1f) {
						//Debug.Log("Walk!");
						forward = 1;
						anim.SetBool ("Walking", true);
						anim.SetBool ("Running", false);
					}
					//
					else if ((forward == 1 || forward == 2) && v <=0.1f) {
						//Debug.Log("Stop!");
						forward = 0;
						anim.SetBool ("Running", false);
						anim.SetBool ("Walking", false);
					}
				}

				// to Fly
				if (homeKey && forward==0) {
					flying = 1;
					rbdy.useGravity = false;
					rbdy.linearVelocity = new Vector3 (0, 0, 0);
					transform.localPosition += Vector3.up * 0.2f;
					anim.SetBool ("Hovering", true);
					homeKey = false;
				}

				if (Input.GetKey(KeyCode.PageUp)) {
					flying = 1;
					forward = 0;
					rbdy.useGravity = false;
					rbdy.linearVelocity = new Vector3 (0, 0, 0);
					transform.localPosition += Vector3.up * 0.2f;
					anim.SetBool ("Walking", false);
					anim.SetBool ("Running", false);
					anim.SetBool ("Up", true);
					anim.SetBool ("Hovering", true);
					v = 0.0f;
				}
				//
				if (jumpKey) {		
					if (forward==2) {
						if (!anim.IsInTransition (0)) {
							rbdy.AddForce (Vector3.up * jumpPower, ForceMode.VelocityChange);
							anim.SetBool ("Jump", true);
						}
					}
					else if (forward==0) {
						if (!anim.IsInTransition (0)) {
							anim.SetBool ("Rest", true);
						}
					}
					jumpKey = false;
				}
			}
			//
			else if (flying==1) {
				anim.SetBool ("Up", false);
				anim.SetBool ("Down", false);
				//
				if (homeKey && forward==0) {
					flying = 0;
					anim.SetBool ("Hovering", false);
					rbdy.useGravity = true;
					homeKey = false;
					v = 0.0f;
				}
				//
				if (Input.GetKey (KeyCode.PageUp)) {
					transform.localPosition += Vector3.up * Time.fixedDeltaTime * 3.5f;
					anim.SetBool ("Up", true);
					v = 0.0f;
				}
				//
				else if (Input.GetKey (KeyCode.PageDown)) {
					anim.SetBool ("Down", true);
					transform.localPosition += Vector3.down * Time.fixedDeltaTime*3.5f;
					v = 0.0f;
				}
			}

			//
			// �ȉ��AAnimator�̊e�X�e�[�g���ł̏���
			animState = anim.GetCurrentAnimatorStateInfo (0);
			// Run���̏���
			if (animState.fullPathHash == runState) {
				if (useCurves) {
					resetCollider ();
				}
			}
			// Jump���̏���
			else if (animState.fullPathHash == jumpState) {
				if (!anim.IsInTransition (0)) {
					anim.SetBool ("Jump", false);
				}
			}
			// Idle���̏���
			else if (animState.fullPathHash == idleState) {
				if (useCurves) {
					resetCollider ();
				}
			}
			// Rest���̏���
			else if (animState.fullPathHash == restState) {
				cameraObject.SendMessage("setCameraPositionFrontView");
				if (!anim.IsInTransition (0)) {
					anim.SetBool ("Rest", false);
					v = 0.0f;
					h = 0.0f;
				}
			}

			//
			// �ړ�����
			anim.SetFloat ("Speed", v);							// Animator���Őݒ肵�Ă���"Speed"�p�����^��v��n��
			anim.SetFloat ("Direction", h); 					// Animator���Őݒ肵�Ă���"Direction"�p�����^��h��n��
			anim.speed = animSpeed;								// Animator�̃��[�V�����Đ����x�� animSpeed��ݒ肷��
			
			velocity = transform.TransformDirection (new Vector3 (0, 0, v));
			if (v > 0.1) {
				if (flying==1) {
					velocity *= flyingSpeed;
				}
				else if (forward == 1) {
					velocity *= forwardSpeed;
				}
				else if (forward == 2) {
					velocity *= runningSpeed;
				}
			}
			else if (v < -0.1) {
				velocity *= backwardSpeed;
			}
			//
			transform.localPosition += velocity * Time.fixedDeltaTime;	// �㉺�̃L�[���͂ŃL�����N�^�[���ړ�������
			transform.Rotate (0, h * rotateSpeed, 0);					// ���E�̃L�[���͂ŃL�����N�^��Y���Ő��񂳂���

			//
			uparrowKey = false;
			homeKey = false;
			jumpKey = false;
			clicktm++;
		}


		//
		// ���j���[
		void OnGUI ()
		{
            Rect rect = new Rect(10, Screen.height - 60, 400, 30);
            showInteraction = GUI.Toggle(rect, showInteraction, "Show Interaction");

            if (showInteraction)
            {
                GUI.Box(new Rect(Screen.width - 260, 10, 250, 165), "Interaction");
                GUI.Label(new Rect(Screen.width - 245, 30, 250, 30), "Up Arrow : Walk");
                GUI.Label(new Rect(Screen.width - 245, 50, 250, 30), "Up Arrow x2 : Run");
                GUI.Label(new Rect(Screen.width - 245, 70, 250, 30), "Home : Fly / Land");
                GUI.Label(new Rect(Screen.width - 245, 90, 250, 30), "PageUp / PageDown : Up / Down");
                GUI.Label(new Rect(Screen.width - 245, 110, 250, 30), "Left Control : Front Camera");
                GUI.Label(new Rect(Screen.width - 245, 130, 250, 30), "Mouse Wheel : Zoom");
                GUI.Label(new Rect(Screen.width - 245, 150, 250, 30), "Space Bar : Jump (Run) / Rest (Idle)");
            }
		}


		//
		// �L�����N�^�[�̃R���C�_�[�T�C�Y�̃��Z�b�g�֐�
		void resetCollider ()
		{
			cldr.height = orgColHight;
			cldr.center = orgVectColCenter;
		}	
	}
}
