namespace Caliburn.Micro.Core {
    using System;
    using System.Collections.Generic;
    /// 
    ///   An implementation of  that enables sequential execution of multiple results.
    /// 
    public class SequentialResult : IResult {
        readonly IEnumerator enumerator;
        CoroutineExecutionContext context;
        /// 
        ///   Initializes a new instance of the  class.
        /// 
        /// The enumerator.
        public SequentialResult(IEnumerator enumerator) {
            this.enumerator = enumerator;
        }
        /// 
        ///   Occurs when execution has completed.
        /// 
        public event EventHandler Completed = delegate { };
        /// 
        ///   Executes the result using the specified context.
        /// 
        /// The context.
        public void Execute(CoroutineExecutionContext context) {
            this.context = context;
            ChildCompleted(null, new ResultCompletionEventArgs());
        }
        void ChildCompleted(object sender, ResultCompletionEventArgs args) {
            var previous = sender as IResult;
            if (previous != null) {
                previous.Completed -= ChildCompleted;
            }
            if(args.Error != null || args.WasCancelled) {
                OnComplete(args.Error, args.WasCancelled);
                return;
            }
            var moveNextSucceeded = false;
            try {
                moveNextSucceeded = enumerator.MoveNext();
            }
            catch(Exception ex) {
                OnComplete(ex, false);
                return;
            }
            if(moveNextSucceeded) {
                try {
                    var next = enumerator.Current;
                    IoC.BuildUp(next);
                    next.Completed += ChildCompleted;
                    next.Execute(context);
                }
                catch(Exception ex) {
                    OnComplete(ex, false);
                    return;
                }
            }
            else {
                OnComplete(null, false);
            }
        }
        void OnComplete(Exception error, bool wasCancelled) {
            enumerator.Dispose();
            Completed(this, new ResultCompletionEventArgs { Error = error, WasCancelled = wasCancelled });
        }
    }
}