namespace Caliburn.Micro.Core {
    using System;
    using System.Threading.Tasks;
    /// 
    /// Extension methods to bring   and   together.
    ///  
    public static class TaskExtensions {
        /// 
        /// Executes an   asynchronous.
        ///  
        ///  The coroutine to execute.
        ///  The context to execute the coroutine within.
        /// A task that represents the asynchronous coroutine. 
        public static Task ExecuteAsync(this IResult result, CoroutineExecutionContext context = null) {
            return InternalExecuteAsync(result, context);
        }
        /// 
        /// Executes an   asynchronous.
        ///  
        /// The type of the result. 
        ///  The coroutine to execute.
        ///  The context to execute the coroutine within.
        /// A task that represents the asynchronous coroutine. 
        public static Task ExecuteAsync(this IResult result,
                                                          CoroutineExecutionContext context = null) {
            return InternalExecuteAsync(result, context);
        }
        static Task InternalExecuteAsync(IResult result, CoroutineExecutionContext context) {
            var taskSource = new TaskCompletionSource();
            EventHandler completed = null;
            completed = (s, e) => {
                result.Completed -= completed;
                if (e.Error != null)
                    taskSource.SetException(e.Error);
                else if (e.WasCancelled)
                    taskSource.SetCanceled();
                else {
                    var rr = result as IResult;
                    taskSource.SetResult(rr != null ? rr.Result : default(TResult));
                }
            };
            try {
                IoC.BuildUp(result);
                result.Completed += completed;
                result.Execute(context ?? new CoroutineExecutionContext());
            }
            catch (Exception ex) {
                result.Completed -= completed;
                taskSource.SetException(ex);
            }
            return taskSource.Task;
        }
        /// 
        /// Encapsulates a task inside a couroutine.
        ///  
        ///  The task.
        /// The coroutine that encapsulates the task. 
        public static TaskResult AsResult(this Task task) {
            return new TaskResult(task);
        }
        /// 
        /// Encapsulates a task inside a couroutine.
        ///  
        /// The type of the result. 
        ///  The task.
        /// The coroutine that encapsulates the task. 
        public static TaskResult AsResult(this Task task) {
            return new TaskResult(task);
        }
    }
}