using System; using System.Collections.Generic; using System.Text; namespace SalsaModel.Scheduling { class ActiveEvent { double _pct; IAction _evt; public ActiveEvent(double percent, IAction evt) { _pct = percent; _evt = evt; } public double Percent { get { return _pct; } } public IAction Event { get { return _evt; } } } class EventRecord { readonly public double Start; readonly public double Duration; readonly public IAction Event; public EventRecord(double start, double duration, IAction evt) { Start = start; Duration = duration; Event = evt; } public double Stop { get { return Start + Duration; } } } public class TimeLine { List _events = new List(); internal void Add(double at, double duration, IAction theEvent) { if (duration < 0) { throw new ArgumentException("Negative duration"); } _events.Add(new EventRecord(at, duration, theEvent)); } internal IEnumerable EventsBetween(double start, double end) { foreach (EventRecord rec in _events) { if (rec.Start < end && rec.Stop > start) { yield return rec; } } } internal List StartedEventsBetween(double prev, double now) { List rv = new List(); foreach (EventRecord evt in _events) { if (evt.Start > prev && evt.Start <= now) { rv.Add(evt.Event); } } return rv; } internal List EndedEventsBetween(double prev, double now) { List rv = new List(); foreach (EventRecord evt in _events) { if (evt.Stop > prev && evt.Stop <= now) { rv.Add(evt.Event); } } return rv; } internal List ActiveEventsAt(double now) { List rv = new List(); foreach (EventRecord evt in _events) { if (now > evt.Start && now < evt.Stop) { rv.Add(new ActiveEvent((now - evt.Start) / (evt.Stop - evt.Start), evt.Event)); } } return rv; } public void RunActions(double prev, double now) { // XXX this is incorrect: if events occur fully enclosed in the time period, // we need to start them before finishing them! foreach (IAction action in EndedEventsBetween(prev, now)) { action.Update(1.0); action.End(); } foreach (IAction action in StartedEventsBetween(prev, now)) { action.Start(); action.Update(0.0); } foreach (ActiveEvent evt in ActiveEventsAt(now)) { evt.Event.Update(evt.Percent); } } internal bool HasEventsAfter(double now) { foreach (EventRecord evt in _events) { if (evt.Stop >= now || evt.Start >= now) { return true; } } return false; } } }