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


public class HitObject : MonoBehaviour {

	// Speed for expanding change at will
	public float Speed=2;
	public float Radius = 1;
	public float ScaledRadius{
		get{
			return Radius * transform.lossyScale.x;
		}
	}
	public ObjectType Type = ObjectType.obstacle;
	public float MaxDistance=10;

	public Vector2 Pos;
	public Distance[] Distances;

	bool isExpanding=false;
	public Segment[] Segments= new Segment[0];
	public bool[] expandingWaves=new bool[0];
	public int[] travelPositions=new int[0];
	public float[] expansionValues=new float[0];
	public int number=-1;
	int nextWave=0;

	public void Start(){
		MyStart ();
	}

	public void MyStart () {
		// for easier calculation in 2D space
		Pos = new Vector2 (transform.position.x,transform.position.y);
	}

	// Change the size of your objects if you are expanding.
	void Update () {
		if (isExpanding) {
			for (int i = 0; i < expandingWaves.Length; i++) {
				if (expandingWaves[i]) {
					expansionValues[i] += Time.deltaTime * Speed;
					Segments [i].UpdateDistance ();

					CheckExpansion (i);

				}
			}

		}	
	}

	public void Init(int i){
		number = i;

	}


	// Checks if the expansion is allready really or if an object gets hit
	public void CheckExpansion(int i){

		bool finished = false;

		if (expansionValues [i] >= MaxDistance) {
			finished = true;

		}

		if (finished) {
			expandingWaves [i] = false;
			Segments [i].IsOver ();
			Segments [i] = null;
			for (int j = 0; j < expandingWaves.Length; j++) {
				if (expandingWaves[j]) {
					finished = false;
					break;
				}
			}
			if (finished) {
				isExpanding = false;
				GameObject.Destroy (this.gameObject);
			}
			return;

		}

		if (travelPositions [i]>=Distances.Length) {
			return;
		}

		if (expansionValues [i] >= Distances [travelPositions [i]].Value) {
			//Debug.Log (Segments [i].CanHit (Distances [travelPositions [i]]));

			if (Segments [i].CanHit (Distances [travelPositions [i]])) {		
			
				Distances [travelPositions [i]].Object.GotHit (this);
				if (Distances [travelPositions [i]].Object.Type == ObjectType.obstacle || Distances [travelPositions [i]].Object.Type == ObjectType.destroyableObstacles) {
					Segments [i].Hit (Distances [travelPositions [i]], this);
				}

			}
			travelPositions [i]++;

		}


	}

	bool destroyed=false;
	// Gets called when an object is hit by a Wave.
	public void GotHit(HitObject source) {
		//Add Code for explosion etc.
		if ((Type== ObjectType.destroyable || Type== ObjectType.destroyableObstacles) && !destroyed) {
			destroyed = true;
			GameController.Instance.ObjectDestroyed(number);
			TargetObject target = GetComponent<TargetObject> ();
			if (target!=null) {
				target.StartHit ();
			}
		}

	}



	// Calculates the distance between another HitObject and this one
	public Distance CalculateDistance(HitObject Target){
		float dist = Vector2.Distance (Pos, Target.Pos);

		//float angle = Vector2.Angle (Pos- Target.Pos,Vector2.right);

		Vector2 dir = (-Pos + Target.Pos);
		dir.Normalize ();

		float angle = Mathf.Rad2Deg * Mathf.Acos (Vector2.Dot(dir,Vector2.up));
		float sign = Mathf.Sign( dir.x);
		//Debug.Log (angle + " " + sign + " " + Target.name);

		if (sign<0) {
			angle = 360 - angle;;
		}

		Distance value= new Distance ();
		value.Value = Mathf.Max( dist-Target.ScaledRadius,0);
		value.Angle = angle;
		value.Object = Target;

		return value;
	}

	// Start expansion
	public void Expand(){
		Invoke ("ExpandNow", GameController.WaveDelay);
		GetComponentInChildren<SpriteRenderer> ().color = GameController.WaveColor;
	}

	void ExpandNow(){
		isExpanding = true;
		travelPositions[nextWave] = 0;
		expansionValues[nextWave] = 0;
		expandingWaves [nextWave] = true;
		Segments [nextWave]=Segment.StartSegment();
		Segments [nextWave].Init (this, nextWave);
		nextWave++;

	}

}

// Object for holding the distance
[System.Serializable]
public struct Distance{
	public HitObject Object;
	public float Value;
	public float Angle;
}

// Need to know how to sort monsters, Implement a Comparer
public class DistanceSorter : IComparer  {
	#region IComparer implementation

	// For easy access
	private static DistanceSorter instance;
	public static DistanceSorter Instance{
		get {
			if (instance==null) {
				instance = new DistanceSorter ();
			}
			return instance;
		}
	}

	// Compares 2 Distances
	public int Compare (object x, object y)
	{
		// Cast to Distance
		Distance First = (Distance)x;
		Distance Second = (Distance)y;

		// wrong objects
		if (First.Object==null || Second.Object==null) {
			return 0;
		}

		if (First.Value>Second.Value) {
			//First bigger
			return 1;
		} else if (First.Value<Second.Value) {
			//Second bigger
			return -1;
		}
		//Same distance
		return 0;
	}

	#endregion




}

public enum ObjectType{
	obstacle,
	destroyable,
	destroyableObstacles,
	friend
}