using System;
using System.Collections.Generic;
using CAnchor = Cryville.Crtr.Anchor;

namespace Cryville.Crtr.Event {
	public class StampedEvent : IComparable<StampedEvent> {
		public double Time;
		public ChartEvent Unstamped;
		public EventContainer Container;
		public StampedEvent Origin;
		public List<StampedEvent> Coevents;

		public double Duration {
			get {
				if (ReleaseEvent != null)
					return ReleaseEvent.Time - Time;
				else return 0;
			}
		}
		
		public virtual int Priority {
			get {
				if (Unstamped != null) return Unstamped.Priority;
				if (Origin != null) return Origin.Priority + 1;
				throw new NotImplementedException();
			}
		}

		public class Temporary : StampedEvent, IComparable<Temporary> {
			public virtual bool CanDiscard { get; set; }
			public int CompareTo(Temporary other) {
				return base.CompareTo(other);
			}
		}

		public class Anchor : Temporary {
			public CAnchor Target;
			int m_priority;
			public bool Forced { get; set; }
			public override bool CanDiscard { get { return !Forced; } }
			public override int Priority { get { return m_priority; } }
			public void SetPriority(int value) { m_priority = value + Container.Priority - 0x800; }
		}

		public class ClipBehind : StampedEvent {
			public override int Priority {
				get { return Origin.Priority - 0x8000; }
			}
		}

		public class ClipAhead : StampedEvent {
			public override int Priority {
				get { return 0x7fff - Origin.Priority; }
			}
		}

		public class RelativeMotion : Temporary {
			public int Name { get; set; }
			public MotionNode Node { get; set; }
			public override bool CanDiscard { get { return false; } }
			public override int Priority { get { return -2; } }
		}

		public StampedEvent ReleaseEvent { get; set; }
		
		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 = CompareExtra(other);
			if (u != 0) return u;
			return GetHashCode().CompareTo(other.GetHashCode());
		}

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