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

public class Character : MonoBehaviour {
	protected Texture2D[] m_healthTextures;
	protected Texture2D[] m_otherTextures;
	protected Rigidbody2D m_body;
	protected Animator m_anim;
	protected float m_energy;
	public int m_RangedPP, m_MeleePP, m_maxPP;

	protected float m_damageTime = 0.0f;
	protected float m_health;
	protected bool m_canJump = true, m_blocking = false;

	protected float m_guiWidth = 200;
	public Vector2 m_guiPos;
	public bool m_isPlayer = false;
	public bool m_win = false;

	public DataComponent m_data;

	private AudioSource m_hitSrc;


	protected GUIStyle m_style;

	public int m_xp, m_level = 1;
	private void Awake() {
		m_guiPos.y = 20;
		m_data = gameObject.GetComponent<DataComponent> ();
		m_hitSrc = gameObject.AddComponent<AudioSource> ();
		m_hitSrc.clip = m_data.m_hit;
		m_body = GetComponent<Rigidbody2D> ();
		m_anim = GetComponent<Animator> ();	
		m_energy = 1.0f;

		m_maxPP = 15;
		m_RangedPP = m_MeleePP = m_maxPP;

		m_healthTextures = HelperFunctions.getHealthTextures ();
		m_otherTextures = HelperFunctions.getOtherTextures ();
		m_style = new GUIStyle ();
		m_style.normal.textColor = Color.black;
		m_health = getMaxHealth ();

	}

	protected void attack(Vector2 dir, int type) {
		if (m_energy < 0.99f) {
			return;
		}
		m_energy = 0;

		GameObject obj; 
		if (type == 0) {
			obj = (GameObject)Instantiate (m_data.m_RangedAttack, m_body.position, Quaternion.AngleAxis (HelperFunctions.GetRotationAngle (m_body.position, dir), Vector3.forward));
		} else {
			obj = (GameObject)Instantiate (m_data.m_MeleeAttack, m_body.position, Quaternion.AngleAxis (HelperFunctions.GetRotationAngle (m_body.position, dir), Vector3.forward));
		}
		Bullet b = obj.GetComponent<Bullet> () as Bullet;
		b.m_direction = dir - m_body.position;
		b.m_owner = gameObject;
		if (type == 0) {
			if (m_RangedPP == 0) {
				m_health = Mathf.Max(1, m_health - 5);
			}
			b.m_speed*= getLevelFactor();
			b.m_power*= getLevelFactor();
			m_RangedPP = Mathf.Max(0, m_RangedPP - 1);
		} else {
			if (m_MeleePP == 0) {
				m_health = Mathf.Max(1, m_health - 5);
			}
			b.m_speed = 32f;
			b.m_power = 20f * getLevelFactor();
			b.m_timeLeft = 0.1f;
			m_MeleePP = Mathf.Max(0, m_MeleePP - 1);
		}
	}

	protected void jump() {
		if (m_canJump) {
			m_canJump = false;
			Vector2 tmp = new Vector2(m_body.velocity.x, m_data.m_jumpSpeed);
			m_body.velocity = tmp;
		}
	}

	// Use this for initialization
	void Start () {
	
	}

	protected void commonUpdate(Vector2 mov, bool jumpInput) {
		m_damageTime -= Time.deltaTime;
		if (mov.magnitude > 1) {
			mov.Normalize ();
		}
		mov *= m_data.m_maxSpeed * (m_blocking ? 0.3f : 1.0f);
		mov.y = m_body.velocity.y;
		m_body.velocity = mov;
		m_energy = Mathf.Min (m_energy + Time.deltaTime, 1.0f);
		Vector3 tmp = transform.localScale;
		if (mov.x < -0.1) {
			tmp.x = -1;
		} else if (mov.x > 0.1) {
			tmp.x = 1;
		}
		transform.localScale = tmp;
		m_anim.SetFloat ("vert", mov.y);
		m_anim.SetFloat ("hori", mov.x);
		m_anim.SetBool ("block", m_blocking);
		m_anim.SetBool ("attack", m_energy < 0.5f);
		if (jumpInput && !m_blocking) {
			jump ();
		}
	}

	
	// Update is called once per frame
	void Update () {
	}

	void OnTriggerEnter2D(Collider2D other) {
		Bullet b = other.gameObject.GetComponent<Bullet> () as Bullet;
		if (b != null) {
			if (b.m_owner == gameObject) {
				return;
			}
			if (m_blocking) {
				b.m_power /= 2;
			}
			m_health -= b.m_power;
			Destroy (other.gameObject);
			m_damageTime = 0.2f;
			m_hitSrc.Play();
		} else {
			if (other.name.Equals("Cube") || other.tag.Equals("Player") || other.tag.Equals("Enemy")) {
				m_canJump = true;
				return;
			}
		}
		if (m_health <= 0.1) {
			Character dest = b.m_owner.GetComponent<Character>();
			GameController cont = GameObject.FindWithTag("gamecontroller").GetComponent<GameController>();
			if (dest != null) {
				dest.grantXp((int) (HelperFunctions.getScaledRandom(80, 100) + m_level * HelperFunctions.getScaledRandom(50, 80)));
				cont.registerWin(m_body.position);
			} else {
				cont.gameOver();
			}
			GameObject.Destroy(gameObject);
		}
	}

	public void grantXp(int xp) {
		m_xp += xp;
		while (m_xp > getNextLevel()) {
			m_xp -= getNextLevel();
			m_level++;
		}
		m_level = Mathf.Min (m_level, 100);
		int max = getMaxHealth ();
		m_health = Mathf.Min (max, m_health + max * 0.65f);
		m_RangedPP = Mathf.Min (m_maxPP, m_RangedPP + (int) HelperFunctions.getScaledRandom (6, 10));
		m_MeleePP = Mathf.Min (m_maxPP, m_MeleePP + (int) HelperFunctions.getScaledRandom (6, 10));
		m_win = true;
	}

	public float getLevelFactor() {
		return 1f + (m_level-1) * 0.2f;
	}

	public int getNextLevel() {
		return (int) (100 * getLevelFactor ());
	}

	public int getMaxHealth() {
		return (int) (getLevelFactor() * m_data.m_maxHealth);
	}

	public void drawRect(string label, Vector2 off, float width, float curr, float max, Texture t) {
		GUI.DrawTexture (new Rect (m_guiPos + off, new Vector2((curr/max) * width, 20f)), t);
		GUI.Label (new Rect (m_guiPos + off, new Vector2(width, 30f)), label, m_style);
	}

	public void resetHealth() {
		m_health = getMaxHealth ();
	}

	public void OnGUI() {
		if (m_isPlayer) {
			m_guiPos.x = Screen.width / 2 - m_guiWidth - 20;
		} else {
			m_guiPos.x = Screen.width / 2 + 20;
		}
		GUI.Label (new Rect (m_guiPos, new Vector2(0, 30f)), m_data.m_name, m_style);
		drawRect ("Health: " + m_health + "/" + getMaxHealth(), new Vector2(0, 30), m_guiWidth, Mathf.Max(0, m_health),
		          getMaxHealth(), m_healthTextures[(int) Mathf.Max (0, ((m_health/getMaxHealth())*3.0f))]);
		drawRect ("Cooldown", new Vector2(0, 60), m_guiWidth, 1-m_energy, 1, m_healthTextures[0]);
		drawRect ("Xp: " + m_xp + "/" + getNextLevel(), new Vector2(0, 90), m_guiWidth, m_xp, getNextLevel(), m_otherTextures[1]);
		drawRect ("Level: " + m_level + "/100", new Vector2(0, 120), m_guiWidth, m_level, 100, m_otherTextures[1]);
		drawRect ("Melee PP: " + m_MeleePP + "/" + m_maxPP, new Vector2(0, 150), m_guiWidth, m_MeleePP, m_maxPP, m_otherTextures[0]);
		drawRect ("Ranged PP: " + m_RangedPP + "/" + m_maxPP, new Vector2(0, 180), m_guiWidth, m_RangedPP, m_maxPP, m_otherTextures[0]);
	}
}
