using UnityEngine;
using System.Collections;

[System.Serializable]
//Structure for storing segments
public class Segment  {
	public SegmentType Type= SegmentType.leaf;

	public float Min = 0;
	public float Max = 360;
	public float MidValue= 0;

	//The position of the splits into smaller parts if they exist
	public float SplitOne = 0;
	public float SplitTwo = 0;

	// The splits into smaller parts
	public Segment Low;
	public Segment Mid;
	public Segment High;


	public int number;
	public HitObject Parent;

	// Change for letting visuals grow faster/slower
	public static float GrowthParameter = 1.8f;


	// Calculates where the hits are
	public void Hit(Distance hit, HitObject source){
		float length = Mathf.Pow( hit.Value, 2) + Mathf.Pow((hit.Object.ScaledRadius / 2) ,2);
		length = Mathf.Sqrt (length);
		float angle = (hit.Object.ScaledRadius / 2) / length;
		angle = Mathf.Abs( Mathf.Asin (angle));
		angle = Mathf.Rad2Deg * angle;
		float maxHit = hit.Angle + angle;
		float minHit = hit.Angle - angle;

		//Debug.Log (angle + " " + hit.Angle + " " + maxHit + " " + minHit);

		if (minHit < 0 || maxHit > 360) {
			maxHit = maxHit % (360);
			minHit = (minHit + (360)) % (360);
			DoHit (minHit, 0, hit);
			DoHit (360, maxHit, hit);
		} else {
			DoHit (maxHit, minHit, hit);
		}
	}

	public bool CanHit(Distance hit){
		if (Type== SegmentType.leaf) {
			return true;
		}
		if (Type==SegmentType.dead || Type== SegmentType.deadEnd) {
			return false;
		}
		if (Type==SegmentType.node) {
			//Debug.Log (hit.Angle);
			if (hit.Angle > SplitTwo) {
				return High.CanHit (hit);
			} else if (hit.Angle > SplitOne) {
				return Mid.CanHit (hit);
			} else {
				return Low.CanHit (hit);
			}
		}

		return false;
	}

	public void IsOver(){
		if (Type== SegmentType.deadEnd) {
			return;
		}
		if (Type== SegmentType.node) {
			High.IsOver ();
			Mid.IsOver ();
			Low.IsOver ();
			GameObject.Destroy (Wave.gameObject);
		}
		if (Type== SegmentType.dead) {
			if (Wave!=null) {
				GameObject.Destroy (Wave.gameObject);

			}
			if (High!=null) {
				High.IsOver ();
			}
			if (Mid!=null) {
				Mid.IsOver ();
			}
			if (Low!=null) {
				Low.IsOver ();
			}
		}
	}

	public WaveScript Wave;

	// Initialization
	public void Init(HitObject aParent, int aNumber){
		MidValue = (Max + Min) / 2;
		Parent = aParent;
		number = aNumber;
		if (Type != SegmentType.dead) {
			Wave = GameObject.Instantiate (GameController.Instance.Circle).GetComponent<WaveScript> ();
			Wave.transform.position = Parent.transform.position;
			Wave.Radius = Parent.expansionValues [number] * GrowthParameter;
			Wave.Seg = this;
		} else {
			this.IsOver ();
		}

	}

	public float overlap = 12;
	// Updates the distance and other values of the graphical representation
	public void UpdateDistance(){
		if (Type == SegmentType.deadEnd || Type==SegmentType.dead) {
			return;
		}
		if (Max>=360) {
			Wave.OpenAngle = Max - Min+overlap;		
			Wave.Angle = MidValue+overlap;

		} else if (Min<=0) {
			Wave.OpenAngle = Max - Min+overlap;		
			Wave.Angle = MidValue-overlap;

		} else {
			Wave.Angle = MidValue;
			Wave.OpenAngle = Max - Min;		
		}

		Wave.Radius = Parent.expansionValues [number] * GrowthParameter;


		if (Type == SegmentType.node) {
			if (Low != null) {
				Low.UpdateDistance ();
			}
			if (Mid != null) {
				Mid.UpdateDistance ();
			}
			if (High != null) {
				High.UpdateDistance ();
			}
		}

	}

	//Splits segments if needed when they get hit
	public void DoHit(float maxHit, float minHit, Distance hit){
		if (maxHit<Min || minHit>Max) {
			//Debug.Log ("not my problem");

			return;
		}
		switch (Type) {
		case SegmentType.dead:
			// Do nothing you are dead
			break;
		case SegmentType.leaf:
			// Makes split

			if (minHit <= Min) {
				if (maxHit >= Max) {
					// whole was hit
					this.Type = SegmentType.dead;
					Wave.PutOff ();
					this.IsOver ();
					//DoHit (maxHit, minHit, hit);
				} else {


					// hit whole lower part
					Type = SegmentType.node;
					SplitOne = Min;
					SplitTwo = maxHit;
					Wave.PutOff ();

					Low = DeadEnd;

					if (TestSize (maxHit, Min)) {
					
						Mid = new Segment ();
						Mid.Min = Min;
						Mid.Max = maxHit;
						Mid.Type = SegmentType.dead;
						Mid.Init (Parent, number);
					} else {
						Mid = Segment.DeadEnd;
					}
					if (TestSize (Max, maxHit)) {
						
						High = new Segment ();
						High.Type = SegmentType.leaf;
						High.Min = maxHit;
						High.Max = Max;
						High.Init (Parent, number);
					} else {
						High = Segment.DeadEnd;
					}
				}
			} else if (maxHit > Max) {


				Wave.PutOff ();

				//hit whole upper part
				Type = SegmentType.node;
				SplitOne = minHit;
				SplitTwo = Max;

				High = DeadEnd;

				if (TestSize (Max, minHit)) {
					
					Mid = new Segment ();
					Mid.Min = minHit;
					Mid.Max = Max;
					Mid.Type = SegmentType.dead;
					Mid.Init (Parent, number);

				} else {
					Mid = Segment.DeadEnd;
				}

				if (TestSize (minHit, Min)) {					

					Low = new Segment ();
					Low.Type = SegmentType.leaf;
					Low.Min = Min;
					Low.Max = minHit;
					Low.Init (Parent, number);

				} else {
					Low = Segment.DeadEnd;
				}

			} else if (minHit > Max || maxHit < Min) {
				//No hit!
				// DO NOTHING!

			} else {


				// Hit in middle
				Wave.PutOff ();

				Type = SegmentType.node;
				SplitOne = minHit;
				SplitTwo = maxHit;

				if (TestSize (minHit, Min)) {					
					
					Low = new Segment ();
					Low.Type = SegmentType.leaf;
					Low.Min = Min;
					Low.Max = minHit;
					Low.Init (Parent, number);

				} else {
					Low = Segment.DeadEnd;
				}

				if (TestSize (maxHit, minHit)) {					
						
					Mid = new Segment ();
					Mid.Min = minHit;
					Mid.Max = maxHit;
					Mid.Type = SegmentType.dead;
					Mid.Init (Parent, number);

				} else {

					Mid = Segment.DeadEnd;
				}

				if (TestSize (Max, maxHit)) {					
							
					High = new Segment ();
					High.Type = SegmentType.leaf;
					High.Min = maxHit;
					High.Max = Max;
					High.Init (Parent, number);

				} else  {
					High = Segment.DeadEnd;
				}

			}
			break;
			// goes further down in recursion
		case SegmentType.node:
			Low.DoHit (maxHit, minHit, hit);
			Mid.DoHit (maxHit, minHit, hit);
			High.DoHit (maxHit, minHit, hit);
			break;
		default:
			break;
		}

	}

	static Segment deadEnd;
	static bool isSet=false;
	// Used as a static placeholder for unused leafs
	public static Segment DeadEnd{
		get{
			if (!isSet) {
				deadEnd = new Segment ();
				deadEnd.Type = SegmentType.deadEnd;
				isSet = true;
			}
			return deadEnd;
		}
	}

	// Segment to Start with
	public static Segment StartSegment(){
		Segment segment = new Segment ();
		return segment;
	}

	float min=6;
	bool TestSize(float max, float min){
		if (max-min>6) {
			return true;
		}
		return false;
	}
}


public enum SegmentType{
	node,
	leaf,
	dead,
	deadEnd,
	specialNode
}