// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

namespace Microsoft.Samples.WindowsAzureMmc.SnapIn
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;

    public class ExecutionEngine
    {
        private static readonly ExecutionEngine instance = new ExecutionEngine();

        private ExecutionEngine()
        {
            this.PendingOperations = new OperationsDictionary();
        }

        public event EventHandler<OperationStatusChangedEventArgs> OperationStatusChanged;

        public static ExecutionEngine Instance
        {
            get { return instance; }
        }

        public OperationsDictionary PendingOperations { get; set; }

        public void ExecuteOperation(Action operation, string operationName, string operationDescription)
        {
            var operationId = Guid.NewGuid();
            var worker = new BackgroundWorker();
            this.OnOperationStatusChanged(operationId, operationName, operationDescription, OperationStatus.Started);
            worker.DoWork += (sender, e) => operation();
            worker.RunWorkerCompleted += (sender, e) => this.OnOperationStatusChanged(operationId, operationName, operationDescription, e.Error == null ? OperationStatus.Completed : OperationStatus.Error);
            worker.RunWorkerAsync();
        }

        protected virtual void OnOperationStatusChanged(Guid operationId, string name, string description, OperationStatus status)
        {
            var operationInfo = new OperationInfo
            {
                Id = operationId,
                Name = name,
                Description = description,
                Status = status,
                Time = DateTime.Now
            };

            this.EnsureOperation(operationInfo);

            if (this.OperationStatusChanged != null)
            {
                var eventArgs = new OperationStatusChangedEventArgs
                {
                    Operations = this.PendingOperations
                };

                this.OperationStatusChanged(this, eventArgs);
            }
        }

        private void EnsureOperation(OperationInfo operationInfo)
        {
            if (this.PendingOperations.ContainsKey(operationInfo.Id))
            {
                this.PendingOperations[operationInfo.Id] = operationInfo;
            }
            else
            {
                this.PendingOperations.Add(operationInfo.Id, operationInfo);
            }
        }
    }

    public class OperationStatusChangedEventArgs : EventArgs
    {
        public OperationsDictionary Operations { get; set; }
    }

    public class OperationInfo
    {
        public Guid Id { get; set; }

        public string Name { get; set; }

        public string Description { get; set; }

        public DateTime Time { get; set; }

        public OperationStatus Status { get; set; }
    }

    public class OperationsDictionary : Dictionary<Guid, OperationInfo>
    {
    }
}