using System;
using System.Collections.Generic;
using System.Linq;

namespace Cryville.Crtr {
	public class StampedEvent : IComparable<StampedEvent> {
		public float Time;
		public ChartEvent Unstamped;
		public EventContainer Container;
		public StampedEvent Origin;
		public List<StampedEvent> Subevents = new List<StampedEvent>();
		private StampedEvent attev = null;
		private StampedEvent relev = null;

		public float Duration {
			get {
				if (Unstamped == null) return 0;
				if (Unstamped.IsLong)
					return ReleaseEvent.Time - Time;
				else return 0;
			}
		}
		
		public virtual int Priority {
			get {
				if (Unstamped != null) return Unstamped.Priority;
				throw new NotImplementedException();
			}
		}
		
		public class PlaySound : StampedEvent {
			public new Chart.Sound Unstamped;
			public override int Priority {
				get { return 0; }
			}
		}

		public class Judge : StampedEvent {
			public float NoteTime;
			public JudgeDefinition TargetJudge;
			public Judge StartEvent;
			public bool IsEndJudge;
			public override int Priority {
				get { return StartEvent == null ? 4 : 6; }
			}
			protected override int cmpExtra(StampedEvent other) {
				return Equals(StartEvent, other) ? 1 : 0;
			}
		}
		
		public StampedEvent AttackEvent {
			get {
				if (attev == null) attev = Subevents.FirstOrDefault(ev => ev.Time == this.Time);
				return attev;
			}
		}

		public StampedEvent ReleaseEvent {
			get {
				if (relev == null) relev = Subevents.FirstOrDefault(ev => ((InstantEvent)ev.Unstamped).IsRelease);
				return relev;
			}
		}
		
		public override string ToString() {
			if (Unstamped == null)
				return string.Format("stmpev at {0} {1}", Time, this.GetType().Name);
			return string.Format("stmpev at {0} {1}", Time, Unstamped.GetType().Name);
		}

		public int CompareTo(StampedEvent other) {
			int u = this.Time.CompareTo(other.Time);
			if (u != 0) return u;
			u = this.Priority.CompareTo(other.Priority);
			if (u != 0) return u;
			u = this.Duration.CompareTo(other.Duration);
			if (u != 0) return u;
			u = cmpExtra(other);
			if (u != 0) return u;
			return GetHashCode().CompareTo(other.GetHashCode());
		}

		protected virtual int cmpExtra(StampedEvent other) {
			return 0;
		}
	}
}
