using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AIscript : MonoBehaviour {
	public float speed; 
	public int difficult=2;
	
	private UnitStatus state;
	
	private int selectedWeapon;
	private float reloading;
	private GunController gunscontrol;
	
	private float runPriority;
	private float killPriority;
	private float weaponPriority;
	private float armorPriority;
	
	
	private BonusScript bonus;
	private UnitStatus enemy;
	
	//Deikstra 
	private DeikstraSystem WaySystem;
	
	private Vector3 newVec;
	private int[] walkPath;
	public int walkStep=-1;
	private float wayDebugDist=3;
	public float debugDist=0.5f;
	
	private bool isRoam;
	private Vector3 MoveVec;
	
	private Vector3 strafeVector;
	private float strafeTime;
	
	public GameObject preview;
	// Use this for initialization
	void Start () {
		gunscontrol= GameObject.FindGameObjectWithTag("Game").GetComponent<GunController>();
		
		state = transform.GetComponent<UnitStatus>();
		
		if(GameObject.FindGameObjectWithTag("WaypointSystem"))
			WaySystem = GameObject.FindGameObjectWithTag("WaypointSystem").gameObject.GetComponent<DeikstraSystem>();
		
		preview = Instantiate(gunscontrol.guns[selectedWeapon].preview,transform.FindChild("launch").position,transform.FindChild("launch").transform.rotation) as GameObject;
		preview.transform.localScale*=0.5f;
		preview.transform.parent = transform.FindChild("launch").transform;
	}
	
	// Update is called once per frame
	void Update () {
		
		UpdatePriority();
		
		
		Roaming();
		if(bonus!=null & (walkStep==-1 || isRoam==true))
		{
			GoTo(bonus.transform.position);
			GoTo(bonus.transform.position);	
			if(bonus.exist==false)
			{
				bonus = null;
			}
			isRoam = false;
		}
		Debug.Log(state.name+" "+newVec);
		if(enemy!=null)
		{	
			isRoam = false;
			if(enemy.alive==false)
			{
				enemy=null;
				return;
			}
			
			if(See(enemy.transform))
			{	
				walkStep = -1;
				selectedWeapon = ChooseWeapon(Vector3.Distance(transform.position,enemy.transform.position));
				Attack();
				Strafe(Vector3.Distance(transform.position,enemy.transform.position));
			}
			else
			{
				Debug.Log("Not See");
				GoTo(enemy.transform.position);	
			}
		}
		
		
		
		
		
		//Debug.Log("id:"+state.id+"  bonus:"+bonus+"  enemy:"+enemy+"  step:"+walkStep+"  roam:"+isRoam);
		
		if (walkStep>-1) {WalkingTo();}
	}
	
	
	void Roaming()
	{
		List<float> prioritys = new List<float>();
		prioritys.Add(killPriority);
		prioritys.Add(runPriority);
		prioritys.Add(weaponPriority);
		prioritys.Add(armorPriority);
		prioritys.Sort();
		prioritys.Reverse();
		

		bonus=null;
		enemy=null;
		bool sett=true;
		foreach(float i in prioritys)
		{
			if(i==killPriority & sett)
			{
				sett=LookingForEnemy();
			}
			else if(i==runPriority & sett)
			{
				sett=LookingForHealth();
			}
			else if(i==armorPriority & sett)
			{
				sett=LookingForArmor();
			}
			else if(sett)
			{
				sett=LookingForAmmo();
			}
		}
		
		
		if(walkStep==-1 & bonus==null & enemy==null)
		{
			if(WaySystem!=null)
			{
				GoTo(WaySystem.GetComponent<DeikstraSystem>().Waypoints[Random.Range(0,WaySystem.Waypoints.Length-1)].mesh.position);
				isRoam=true;
			}
		}
		
	}
	
	void Attack()
	{
		transform.LookAt(enemy.transform.position);
		//transform.rotation = new Quaternion(0,transform.rotation.y,0,transform.rotation.w);
		transform.FindChild("head").transform.LookAt(enemy.transform.position);
		
		Shoot ();
		
	}
	
	void Shoot()
	{		
		Gun g = gunscontrol.guns[selectedWeapon];
		
		reloading+=Time.deltaTime;
		if(reloading>=g.Reload)
		{
			state.Ammo[selectedWeapon]-=1;
			reloading=0;
			audio.Stop();
			
			if(g.sound)
			{
				audio.clip = g.sound;
				audio.volume=GameOptions.soundVolume;
				audio.Play();
			}
			
			
			
			for(int h=0;h<g.shoots;h++)
			{
				Vector3 direction = (Vector3.Normalize(enemy.transform.position-transform.FindChild("launch").position));
				direction.x+=Random.Range(-g.Recoil/600.1f,g.Recoil/600.1f);
				direction.y+=Random.Range(-g.Recoil/600.1f,g.Recoil/600.1f);
				direction.z+=Random.Range(-g.Recoil/600.1f,g.Recoil/600.1f);
				
				
				Ray ray = new Ray(transform.FindChild("launch").position,direction);
				RaycastHit hit;
				if(Physics.Raycast(ray, out hit,500,3))
				{
	
					if(hit.transform.GetComponent<DecorScript>())
					{
						hit.transform.GetComponent<DecorScript>().Shoot(transform.position,hit.point,g.Force);
						
					}
					
					if(g.missile)
					{
						GameObject m = Instantiate(g.missile,transform.FindChild("launch").position,transform.FindChild("head").transform.rotation)as GameObject;
						m.transform.LookAt(hit.point);
						m.transform.GetComponent<MissileScript>().id = state.id;
						Physics.IgnoreCollision(m.collider,collider);
					}
					
					if(hit.transform.GetComponent<UnitStatus>())
					{
						hit.transform.GetComponent<UnitStatus>().ApplyDamage(g.Damage * (difficult/2),state.id);
					}
					
					
					//Animation
					if(g.touchEffect)
					{
						GameObject k = Instantiate(g.touchEffect,hit.point,new Quaternion(hit.normal.x,hit.normal.y,hit.normal.z,0)) as GameObject;
						k.transform.Translate(hit.normal*0.1f);
					}
				}
			}
		}
	}
	
	void Strafe(float dist)
	{
		if(strafeTime==0)
		{
			strafeVector = new Vector3(Random.Range(-1.01f,1.01f),0,Random.Range(-1.01f,1.01f));
		}
		strafeTime+=Time.deltaTime;
		transform.Translate(strafeVector*speed*Time.deltaTime);
		if(strafeTime>dist/200 * 7)
			strafeTime=0;
	}
	
	void UpdatePriority()
	{
		runPriority = (200.0f-state.health)/10;
		killPriority = 12;
		weaponPriority = 3;
		armorPriority = 2;
	}
	
	void GoTo(Vector3 end) {
		if(WaySystem==null)
		{
			newVec = end;
			walkStep=0;
			return;
		}
		
		DeikstraSystem sys = WaySystem;
		walkPath = sys.SmartMoveTo(transform.position,end);
		walkStep = walkPath.Length-1;
		MoveVec = end;
		
		
		newVec = new Vector3(WaySystem.Waypoints[walkPath[walkStep]].mesh.position.x,transform.position.y,WaySystem.Waypoints[walkPath[walkStep]].mesh.position.z);
		if(Vector3.Distance(newVec,transform.position)<debugDist & walkStep==0)
		{
			newVec = end;	
			//Debug.Log("This 1");
		}
		
		if(walkStep==0 & WaySystem!=null)
		{
			if(Vector3.Distance(transform.position,end)<Vector3.Distance(WaySystem.Waypoints[walkStep].mesh.position,end))
			{
				if(!Physics.Raycast(new Ray(transform.position,Vector3.Normalize(end-transform.position)),Vector3.Distance(transform.position,end),3))
				{
					newVec = end;
					//Debug.Log("This 2");
				}
			}	
		}
	}
	
	void WalkingTo() {
		RaycastHit hit;
		
		
		if(walkStep==0 & WaySystem!=null)
		{
			if(Vector3.Distance(transform.position,MoveVec)<Vector3.Distance(WaySystem.Waypoints[walkStep].mesh.position,MoveVec))
			{
				if(SeeVec(MoveVec))
				{
					newVec = MoveVec;
					//Debug.Log("This 4");
				}
			}	
		}
		
		
		if (Distance2(transform.position,newVec)>debugDist) 
		{
			transform.LookAt(newVec);
			transform.rotation = new Quaternion(0,transform.rotation.y,0,transform.rotation.w);
			transform.Translate(Vector3.forward * speed * Time.deltaTime);
			//Debug.Log(Vector3.Distance(transform.position,newVec));
		}
		else 
		{
			walkStep -= 1;
			if (walkStep>-1)
				newVec = new Vector3(WaySystem.Waypoints[walkPath[walkStep]].mesh.position.x,transform.position.y,WaySystem.Waypoints[walkPath[walkStep]].mesh.position.z);	
		}
		
		if (walkStep<0) {walkStep=-1;}
	}
	
	
	
	bool LookingForArmor()
	{
		List<Transform> armor = new List<Transform>();
		foreach(BonusScript i in GameBrain.armor)
		{
			if(!Physics.Raycast(transform.position,(i.transform.position-transform.position),Vector3.Distance(i.transform.position,transform.position),3))
			{
				armor.Add(i.transform);
			}
		}
		
		
		float lastdist = 99999;
		foreach(Transform e in armor)
		{
			if(Vector3.Distance(e.position,transform.position)<lastdist)
			{
				lastdist = Vector3.Distance(e.position,transform.position);
				bonus = e.transform.GetComponent<BonusScript>();
			}
		}
		
		if(armor.Count!=0)
		{
			return false;
		}
		return true;
	}
	
	bool LookingForHealth()
	{
		List<Transform> health = new List<Transform>();
		foreach(BonusScript i in GameBrain.health)
		{
			if(!Physics.Raycast(transform.position,(i.transform.position-transform.position),Vector3.Distance(i.transform.position,transform.position),3))
			{
				health.Add(i.transform);
			}
		}
		
		float lastdist = 99999;
		foreach(Transform e in health)
		{
			if(Vector3.Distance(e.position,transform.position)<lastdist)
			{
				lastdist = Vector3.Distance(e.position,transform.position);
				bonus = e.transform.GetComponent<BonusScript>();
			}
		}
		
		if(health.Count!=0)
		{
			return false;
		}
		return true;
	}
	
	bool LookingForAmmo()
	{
		List<Transform> ammo = new List<Transform>();
		foreach(BonusScript i in GameBrain.ammo)
		{
			if(!Physics.Raycast(transform.position,(i.transform.position-transform.position),Vector3.Distance(i.transform.position,transform.position),3))
			{
				ammo.Add(i.transform);
			}
		}
		
		float lastdist = 99999;
		foreach(Transform e in ammo)
		{
			if(Vector3.Distance(e.position,transform.position)<lastdist)
			{
				lastdist = Vector3.Distance(e.position,transform.position);
				bonus = e.transform.GetComponent<BonusScript>();
			}
		}
		
		if(ammo.Count!=0)
		{
			return false;
		}
		return true;
	}
	
	bool LookingForEnemy()
	{
		List<Transform> enemys = new List<Transform>();
		foreach(UnitStatus i in GameBrain.units)
		{
			if(Vector3.Distance(i.transform.position,transform.position)<500)
			{
				if(Vector3.Distance(i.transform.position,transform.position)>0.25f)
				{
					i.gameObject.layer = 3;
					if(!Physics.Raycast(transform.position,(i.transform.position-transform.position),Vector3.Distance(i.transform.position,transform.position),3))
					{
						enemys.Add(i.transform);
					}
					i.gameObject.layer = 0;
				}
			}
		}
		
		Debug.Log("Count:"+enemys.Count);
		float lastdist = 99999;
		foreach(Transform e in enemys)
		{
			if(Vector3.Distance(e.position,transform.position)<lastdist)
			{
				lastdist = Vector3.Distance(e.position,transform.position);
				enemy = e.transform.GetComponent<UnitStatus>();
			}
		}
		
		if(enemys.Count!=0)
		{
			walkStep=-1;
			return false;
		}
		return true;
	}
	
	
	bool See(Transform item)
	{	
		RaycastHit hit;
		item.gameObject.layer=3;
		if(!Physics.Raycast(transform.position,(item.position-transform.position),out hit,Vector3.Distance(item.position,transform.position),3))
		{
			item.gameObject.layer=0;
			return true;
		}
		//Debug.Log(hit.rigidbody.gameObject.GetComponent<UnitStatus>().name);
		item.gameObject.layer=0;
		return false;
	}
	
		bool SeeVec(Vector3 item)
	{
		if(Vector3.Distance(transform.position,item)<=debugDist)
		{
			return true;
		}
		
		
		RaycastHit hit;
		if(!Physics.Raycast(transform.position,(item-transform.position),out hit,Vector3.Distance(item,transform.position),3))
		{
			return true;
		}
		return false;
	}
	
	
	
	int ChooseWeapon(float dist)
	{
		if(dist>20)
		{
			if(state.Ammo[3]>0)
			{
				Destroy(preview);
				preview = Instantiate(gunscontrol.guns[selectedWeapon].preview,transform.FindChild("launch").position,transform.FindChild("launch").transform.rotation) as GameObject;
				preview.transform.localScale*=0.5f;
				preview.transform.parent = transform.FindChild("launch").transform;
				return 3;
			}
		}
		
		if(dist<10)
		{
			if(state.Ammo[2]>0)
			{
				Destroy(preview);
				preview = Instantiate(gunscontrol.guns[selectedWeapon].preview,transform.FindChild("launch").position,transform.FindChild("launch").transform.rotation) as GameObject;
				preview.transform.localScale*=0.5f;
				preview.transform.parent = transform.FindChild("launch").transform;
				return 2;	
			}
		}
		
		if(state.Ammo[1]>0)
		{
			Destroy(preview);
			preview = Instantiate(gunscontrol.guns[selectedWeapon].preview,transform.FindChild("launch").position,transform.FindChild("launch").transform.rotation) as GameObject;
			preview.transform.localScale*=0.5f;
			preview.transform.parent = transform.FindChild("launch").transform;
			return 1;
		}
		
		Destroy(preview);
		preview = Instantiate(gunscontrol.guns[selectedWeapon].preview,transform.FindChild("launch").position,transform.FindChild("launch").transform.rotation) as GameObject;
		preview.transform.localScale*=0.5f;
		preview.transform.parent = transform.FindChild("launch").transform;
		return 0;
	}
	
	float Distance2(Vector3 vec1,Vector3 vec2)
	{
		return Vector2.Distance(new Vector2(vec1.x,vec1.z),new Vector2(vec2.x,vec2.z));
	}
}
