/// <summary>
 /// Simply returns the numerical difference between the current tick and the tick at which the given EventScheduling would execute - therefore the result can be negative.
 /// Does not perform any validation such as checking whether the given EventScheduling was created by this EventScheduler.
 /// </summary>
 public long CalculateTicksInFuture(EventScheduling eventScheduling)
 {
     if (eventScheduling == null)
     {
         throw new ArgumentNullException(nameof(eventScheduling));
     }
     return(eventScheduling.ExecutionTick - currentTick);
 }
        //todo xml?
        public Initiative CreateInitiative(RelativeInitiativeOrder relativeOrder, EventScheduling targetEventScheduling)
        {
            if (targetEventScheduling == null)
            {
                throw new ArgumentNullException(nameof(targetEventScheduling));
            }
            if (!targetEventScheduling.IsLive)
            {
                throw new InvalidOperationException("This event scheduling has already executed or been canceled, and can't be reused");
            }
            var es = targetEventScheduling as InternalEventScheduling;

            if (es == null)
            {
                throw new InvalidOperationException("User-created subtypes of EventScheduling are not supported");
            }
            return(CreateInitiative(relativeOrder, es.Initiative));
        }
        //todo - definitely needs xml doc notes about what it does.
        public Initiative GetInitiativeFromEventScheduling(EventScheduling eventScheduling)
        {
            if (eventScheduling == null)
            {
                throw new ArgumentNullException(nameof(eventScheduling));
            }
            if (!eventScheduling.IsLive)
            {
                throw new InvalidOperationException("This event scheduling has already executed or been canceled, and can't be reused");
            }
            InternalInitiative init = (eventScheduling as InternalEventScheduling)?.Initiative as InternalInitiative;

            if (init == null)
            {
                throw new InvalidOperationException("No initiative found");
            }
            init.AutoRemove = false;
            return(init);
        }
        // todo xml-- note that this returns false if the ES is not scheduled, but still changes its value
        //  ... and that this does NOT change insertion order.
        public bool ChangeEventScheduling(EventScheduling eventScheduling, long newTicksInFuture)
        {
            if (eventScheduling == null)
            {
                throw new ArgumentNullException(nameof(eventScheduling));
            }
            if (!eventScheduling.IsLive)
            {
                throw new InvalidOperationException("This event scheduling has already executed or been canceled, and can't be rescheduled");
            }
            var es = eventScheduling as InternalEventScheduling;

            if (es == null)
            {
                throw new InvalidOperationException("User-created subtypes of EventScheduling are not supported");
            }
            if (es == currentlyExecuting)
            {
                throw new InvalidOperationException("This EventScheduling is currently executing and can't be rescheduled");
            }
            return(pq.ChangePriority(es, () => { es.Delay = newTicksInFuture; }));
        }
        //todo xml: returns false if not actually scheduled -- nah, make it void,
        public void CancelEventScheduling(EventScheduling eventScheduling)
        {
            if (eventScheduling == null)
            {
                throw new ArgumentNullException(nameof(eventScheduling));
            }
            var es = eventScheduling as InternalEventScheduling;

            if (es == null)
            {
                throw new InvalidOperationException("User-created subtypes of EventScheduling are not supported");
            }
            if (es == currentlyExecuting)
            {
                throw new InvalidOperationException("This EventScheduling is currently executing and can't be canceled");
            }
            if (!es.IsLive)
            {
                return;
            }
            es.Canceled = true;             // mark it Canceled instead of removing from the PQ, to avoid the O(n) remove operation
            RemoveSchedulingForInitiative(es);
        }