// ----------------------------------------------------------------------------------
// 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.Nodes
{
    using System;
    using System.Linq;
    using System.Windows.Forms;
    using Microsoft.ManagementConsole;
    using Microsoft.Samples.WindowsAzureMmc.Powershell.Host;
    using Microsoft.Samples.WindowsAzureMmc.SnapIn.Configuration;
    using Microsoft.Samples.WindowsAzureMmc.SnapIn.Forms;
    using Microsoft.Samples.WindowsAzureMmc.SnapIn.Views;

    class StorageExplorerNode : ScopeNode
    {
        private const string LOCALACCOUNTNAME = "devstoreaccount1";
        private const string LOCALACCOUNTKEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
        private const string LOCALACCOUTBLOBURL = "http://127.0.0.1:10000";
        private const string LOCALACCOUTQUEUEURL = "http://127.0.0.1:10001";
        private Account currentConnection;
        private ConfigurationData config;
        private const string REGKEYAPPROOT = @"Software\Microsoft\Windows Azure MMC";

        private Microsoft.ManagementConsole.Action connectLocalAction;
        private Microsoft.ManagementConsole.Action loginAction;
        private Microsoft.ManagementConsole.Action newConnectionAction;
        private Microsoft.ManagementConsole.Action deleteConnectionAction;

        private ErrorHandlingService errorHandler;

        public StorageExplorerNode()
            : this(new ErrorHandlingService())
        {
        }

        public StorageExplorerNode(ErrorHandlingService errorHandler)
        {
            this.errorHandler = errorHandler;
            this.DisplayName = "Storage Explorer";

            // get the connections from the registry
            config = RegistryConfiguration.GetConfiguration(REGKEYAPPROOT);

            this.AddContextualActions();
        }

        public AzurePSHost PowershellHost { get; private set; }

        private void AddContextualActions()
        {
            // action to delete an existing connection
            this.connectLocalAction = new Microsoft.ManagementConsole.Action("Connect Local", "Connect to the local Development Storage");
            this.connectLocalAction.Triggered += new Microsoft.ManagementConsole.Action.ActionEventHandler(ConnectLocalAction_Triggered);

            // action to connect to an existing connection
            this.loginAction = new Microsoft.ManagementConsole.Action("Connect", "Connect to Azure");
            this.loginAction.Triggered += new Microsoft.ManagementConsole.Action.ActionEventHandler(ConnectAction_Triggered);

            // action to create a new connection
            this.newConnectionAction = new Microsoft.ManagementConsole.Action("New Connection", "Create a connection to an Azure Account");
            this.newConnectionAction.Triggered += new Microsoft.ManagementConsole.Action.ActionEventHandler(NewConnectionAction_Triggered);

            // action to delete an existing connection
            this.deleteConnectionAction = new Microsoft.ManagementConsole.Action("Delete Connection", "Delete account connection");
            this.deleteConnectionAction.Triggered += new Microsoft.ManagementConsole.Action.ActionEventHandler(DeleteConnectionAction_Triggered);

            // Add actions to root node
            this.ActionsPaneItems.Add(loginAction);
            this.ActionsPaneItems.Add(connectLocalAction);
            this.ActionsPaneItems.Add(newConnectionAction);
            this.ActionsPaneItems.Add(deleteConnectionAction);

        }

        private void ConnectLocalAction_Triggered(object sender, ActionEventArgs e)
        {
            // need to know the current connection later
            Account local = new Account(LOCALACCOUNTNAME, LOCALACCOUNTKEY);
            local.Services.Add("Blobs", new Service(ServiceTypeEnum.Blob, LOCALACCOUTBLOBURL));
            local.Services.Add("Queues", new Service(ServiceTypeEnum.Queue, LOCALACCOUTQUEUEURL));
            local.IsLocal = true;
            currentConnection = local;

            ConnectToCurrentAccount();
        }

        private void ConnectAction_Triggered(object sender, ActionEventArgs e)
        {
            using (SelectConnection connectionForm = new SelectConnection(config, false, null))
            {
                if (this.SnapIn.Console.ShowDialog(connectionForm) == DialogResult.OK)
                {
                    try
                    {
                        currentConnection = connectionForm.SelectedAccount;
                        ConnectToCurrentAccount();
                    }
                    catch (Exception ex)
                    {
                        errorHandler.HandleException(ex);
                        CloseAccount();
                    }
                }
            }
        }

        private void NewConnectionAction_Triggered(object sender, ActionEventArgs e)
        {
            using (NewConnection newConnectionForm = new NewConnection(config))
            {
                if (this.SnapIn.Console.ShowDialog(newConnectionForm) == DialogResult.OK)
                {
                    // create the new account and save it
                    Account acc = new Account(newConnectionForm.AccountName, newConnectionForm.AccountKey);
                    acc.Services.Add("Blobs", new Service(ServiceTypeEnum.Blob, newConnectionForm.BlobServiceURL));
                    acc.Services.Add("Queues", new Service(ServiceTypeEnum.Queue, newConnectionForm.QueueServiceURL));
                    config.Accounts.Add(acc);
                    RegistryConfiguration.SaveConfiguration(config, REGKEYAPPROOT);

                    UpdateActions();

                    try
                    {
                        currentConnection = acc;
                        ConnectToCurrentAccount();
                    }
                    catch (Exception ex)
                    {
                        errorHandler.HandleException(ex);
                        CloseAccount();
                    }
                }
            }
        }

        private void DeleteConnectionAction_Triggered(object sender, ActionEventArgs e)
        {
            using (SelectConnection connectionForm = new SelectConnection(config, true, currentConnection))
            {
                if (this.SnapIn.Console.ShowDialog(connectionForm) == DialogResult.OK)
                {
                    // deleting the current account ? we should close it
                    if (currentConnection == connectionForm.SelectedAccount)
                    {
                        CloseAccount();
                    }

                    config.Accounts.Remove(connectionForm.SelectedAccount);
                    RegistryConfiguration.SaveConfiguration(config, REGKEYAPPROOT);
                    UpdateActions();
                }
            }
        }

        private void ConnectToCurrentAccount()
        {
            // if we already have a connection then we should get rid of it nicely
            if (this.PowershellHost != null)
            {
                this.PowershellHost.Dispose();
            }

            // try to get Host connection.
            this.PowershellHost = new AzurePSHost(
                currentConnection.AccountName,
                currentConnection.AccountKey,
                currentConnection.IsLocal,
                new Uri(currentConnection.Services["Blobs"].Url),
                new Uri(currentConnection.Services["Queues"].Url),
                new WindowsPSHostUserInterface(currentConnection.AccountName, currentConnection.AccountKey));

            // Setup Root Nodes
            SetupLoginNodes(currentConnection.AccountName);
        }

        private void CloseAccount()
        {
            this.Children.Clear();
            this.DisplayName = "Storage Explorer";
            currentConnection = null;
        }

        private void UpdateActions()
        {
            deleteConnectionAction.Enabled = loginAction.Enabled = config.Accounts.Count() > 0;
        }

        private void SetupLoginNodes(string loginName)
        {
            // clear any previous nodes
            this.Children.Clear();

            // Setup Root Node
            this.DisplayName = loginName;
            this.ImageIndex = 0;

            // Setup Blob Node
            ScopeNode blobNode = new ScopeNode();
            blobNode.DisplayName = "BLOB Containers";
            blobNode.ImageIndex = 1;
            blobNode.SelectedImageIndex = 1;

            // Setup Queue Node
            ScopeNode queueNode = new ScopeNode();
            queueNode.DisplayName = "Queues";
            queueNode.ImageIndex = 3;
            queueNode.SelectedImageIndex = 3;

            if (this.PowershellHost != null)
            {
                // Add blob user control
                FormViewDescription fvd = new FormViewDescription();
                fvd.DisplayName = "BLOB Containers";
                fvd.ViewType = typeof(BlobContainerFormView);
                fvd.ControlType = typeof(Forms.BlobContainerControl);

                blobNode.ViewDescriptions.Add(fvd);
                blobNode.ViewDescriptions.DefaultIndex = 0;

                // Add queue user control
                FormViewDescription fvdQueue = new FormViewDescription();
                fvdQueue.DisplayName = "Queues";
                fvdQueue.ViewType = typeof(QueueFormView);
                fvdQueue.ControlType = typeof(Forms.QueueControl);

                queueNode.ViewDescriptions.Add(fvdQueue);
                queueNode.ViewDescriptions.DefaultIndex = 0;
            }

            // Add blob node to the root
            this.Children.Add(blobNode);

            // Add queue node to the root
            this.Children.Add(queueNode);
        }
    }
}