using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Player : MonoBehaviour {

    public int health = 10;
	
	private static float maxAttackDistance = 5.0F;
	private static float attackConeAngle = 90.0F; // total arc, 5 degrees extra on each side of facing direction
	
	public List<PlayerAttackData> attackData = new List<PlayerAttackData>();
	private static float drawConeTime = 1.0F;

    private ArduinoHandler arduinoHandler;

    private Vector3[] Accels;
    private int numAccels = 4;
    private int deltaAccelPtr = 0;

    public float AttackThreshold = 400f;

    public float AttackCooldown = 1f;

    private float timeSinceAttack = 100f;

    public float attackPower = 0f;


	// Use this for initialization
	void Start () {

        arduinoHandler = GameObject.FindGameObjectWithTag("ArduinoHandler").GetComponent<ArduinoHandler>();

        Accels = new Vector3[numAccels];

        for (int i = 0; i < numAccels; i++)
        {
            Accels[i] = Vector3.zero;
        }
	}
	
	public void init()
	{
	for (int i = 0; i <= 10; i++)
		{
			health = i;
			updateHealth();
		}
		
		for (int i = 10; i >= 0; i--)
		{
			health = i;
			updateHealth();
		}
		
		for (int i = 0; i <= 10; i++)
		{
			health = i;
			updateHealth();
		}
	}

    // Update is called once per frame
    void Update()
    {
        timeSinceAttack += Time.deltaTime;
        UpdateAcceleration();
        CheckForAttack();
        UpdateRotation();
		
		updateHealth();
		
		if (health <= 0) {
			
		}
	}

    void UpdateAcceleration()
    {
        Vector3 accel = new Vector3(arduinoHandler.Nunchuck.AccelX, arduinoHandler.Nunchuck.AccelY, arduinoHandler.Nunchuck.AccelZ);

//        Debug.Log("Accel: " + accel.ToString());

        deltaAccelPtr++;
        if (deltaAccelPtr >= Accels.Length)
            deltaAccelPtr = 0;
        Accels[deltaAccelPtr] = accel;
    }

    void CheckForAttack()
    {
		if (health <= 0) 
			return;
		
        Vector3 total = Vector3.zero;

        for (int i = 1; i < Accels.Length; i++)
        {
            total += Accels[i] - Accels[i - 1];
        }

        attackPower = Mathf.Abs(total.magnitude);

        if (attackPower == 0 && Time.timeSinceLevelLoad > 10)
        {
            //Debug.Break();
        }

        if (timeSinceAttack > AttackCooldown && Mathf.Abs(total.magnitude) > AttackThreshold)
        {
            timeSinceAttack = 0;
            Attack();
        }
    }

    void UpdateRotation()
    {
        if (Mathf.Abs(arduinoHandler.gyroVal) > 15)
        {
            transform.Rotate(0, 0, arduinoHandler.gyroVal * Time.deltaTime);
        }
    }

    void OnCollisionEnter(Collision collision)
    {
		if (health <= 0)
			return;
		
        //Debug.Log("Collide");
        if (collision.collider.tag == "Monster")
        {
            Monster monster = (Monster)collision.collider.GetComponent<Monster>();

            health -= monster.damageDone;
			arduinoHandler.PlayerDamaged();
			updateHealth();

            monster.Kill();
        }
    }

    void OnTriggerEnter(Collider other)
    {
		if (health <= 0)
			return;
		
//        Debug.Log("Trigger");
        if (other.tag == "Monster")
        {
            Monster monster = (Monster)other.GetComponent<Monster>();

            health -= monster.damageDone;
			arduinoHandler.PlayerDamaged();
			
			updateHealth();

            monster.Kill();
        }
    }
	
	void updateHealth()
	{
		byte shiftMask = 0;
		for (int i = 1; i < 9; i++)
		{
			if (health >= i)
			{
				shiftMask |= (byte)((int)Mathf.Pow(2, i - 1));
			}
		}
		bool hp9 = false;
		bool hp10 = false;
		
		if (health >= 9)
			hp9 = true;
		
		if (health >= 10)
			hp10 = true;
		arduinoHandler.WriteHealth(shiftMask, hp9, hp10);
		
	}
	
	public void Attack()
	{
		
		MonsterSpawner spawner = GameObject.FindWithTag("MonsterSpawner").GetComponent<MonsterSpawner>();
		
		//Debug.Log("playerAngle = " + transform.eulerAngles.z);
		//Debug.Log("playerAngle = " + transform.eulerAngles.z);
		
		foreach (Monster monster in spawner.monsters)
        {
				float angleToMonster = Vector3.Angle(transform.up, monster.transform.position - transform.position);
				
				//Debug.Log("angleToMonster = " + angleToMonster);
				
				if(angleToMonster <= (attackConeAngle / 2.0F) && angleToMonster >= -(attackConeAngle / 2.0F))
				{
					if( (transform.position - monster.transform.position).magnitude <= maxAttackDistance)
					{
						monster.dieNextTick = true;
						arduinoHandler.MonsterKilled();
					}
				}
		}

        Vector3 eulerAngles = transform.eulerAngles;

        transform.Rotate(transform.forward, (attackConeAngle / 2.0F));
        Vector3 firstLineEnd = transform.position + (transform.up * maxAttackDistance);

        transform.eulerAngles = eulerAngles;

        transform.Rotate(transform.forward, 360.0F - (attackConeAngle / 2.0F));
        Vector3 secondLineEnd = transform.position + (transform.up * maxAttackDistance);

        transform.eulerAngles = eulerAngles;

        //Debug.Log("data2");
        //Debug.Log(firstLineEnd);
        //Debug.Log(secondLineEnd);

        attackData.Add(new PlayerAttackData(firstLineEnd, secondLineEnd, Time.time));
	}
	
	void OnDrawGizmos()
    {
		attackData.RemoveAll(TimeElapsed);
		
		Player player = GameObject.FindWithTag("Player").GetComponent<Player>();
		
		foreach(PlayerAttackData data in attackData)
		{
			Gizmos.color = Color.yellow;
			
			Gizmos.DrawLine(player.transform.position,  data.firstLineEnd);
			Gizmos.DrawLine(player.transform.position,  data.secondLineEnd);
		}
    }
	
	private static bool TimeElapsed(PlayerAttackData data)
	{
		//Debug.Log("curTime: " + Time.time);
		//Debug.Log("dataStartTime: " + data.startTime);
		if(Time.time - data.startTime >= Player.drawConeTime)
			return (true);
		
		return (false);
	}
	
	void OnGUI () {
		
		//GUI.BeginGroup(new Vect(0,0,0,0));
		//GUILayout.BeginVertical();
		
		GUI.Box (new Rect(10,10,150,60), "Time Elapsed: " + Mathf.Ceil(Time.timeSinceLevelLoad) + "\nHealth: " + health);
		//GUI.Box (new Rect (10,10,100,30), "Health: " + health);
		
		//GUILayout.EndVertical();
	}
}
