// ----------------------------------------------------------------------------------
// 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.Powershell.Host.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using System.Management.Automation;
    using System.Management.Automation.Runspaces;
    using System.Security;

    public static class PSHelper
    {
        private const string QUEUEDRIVENAME = "queue";
        private const string BLOBDRIVENAME = "blob";

        public static Collection<PSObject> ExecuteCommand(AzurePSHost host, Command command)
        {
            var pipelineResults = new Collection<PSObject>();

            using (Runspace rs = CreateRunspace(host))
            {
                Pipeline pipeline = rs.CreatePipeline();
                pipeline.Commands.Add(command);
                pipelineResults = pipeline.Invoke();

                PSObject error = (PSObject)pipeline.Error.Read();

                if (error != null)
                {
                    ErrorRecord record = error.BaseObject as ErrorRecord;

                    if (record != null)
                    {
                        throw record.Exception;
                    }
                }
            }

            return pipelineResults;
        }

        public static Collection<PSObject> ExecuteScript(AzurePSHost host, string[] scripts, Dictionary<string, object> variables)
        {
            var pipelineResults = new Collection<PSObject>();

            using (Runspace rs = CreateRunspace(host))
            {
                Pipeline pipeline = rs.CreatePipeline();

                foreach (var script in scripts)
                {
                    pipeline.Commands.AddScript(script);
                }

                foreach (KeyValuePair<string, object> variable in variables)
                {
                    rs.SessionStateProxy.SetVariable(variable.Key, variable.Value);
                }

                pipelineResults = pipeline.Invoke();

                PSObject error = (PSObject)pipeline.Error.Read();

                if (error != null && error.BaseObject is ErrorRecord)
                {
                    ErrorRecord record = error.BaseObject as ErrorRecord;

                    if (record != null)
                    {
                        throw record.Exception;
                    }
                }
                else
                {
                    var keys = variables.Keys.ToArray();
                    for (int i = 0; i < keys.Length; i++)
                    {
                        var key = keys[i];
                        variables[key] = rs.SessionStateProxy.GetVariable(key);
                    }
                }
            }

            return pipelineResults;
        }

        public static Collection<PSObject> ExecuteScript(AzurePSHost host, string script, Dictionary<string, object> variables)
        {
            return PSHelper.ExecuteScript(host, new string[] { script }, variables);
        }

        public static Collection<PSObject> ExecuteScript(AzurePSHost host, string script)
        {
            return PSHelper.ExecuteScript(host, new string[] { script }, null);
        }

        private static Runspace CreateRunspace(AzurePSHost host)
        {
            // create a RunSpace, using this for the custom host
            var runspace = RunspaceFactory.CreateRunspace(host);

            // it might be useful to know the current state of the runspace
            runspace.StateChanged += new EventHandler<RunspaceStateEventArgs>(host.RunspaceStateChanged);
            runspace.Open();

            // add the snapin providers for Azure (ignore the warning for now)
            PSSnapInException warning;
            runspace.RunspaceConfiguration.AddPSSnapIn("CloudDriveSnapin", out warning);

            // Create the credentials using a SecureString
            SecureString securePassword = new SecureString();
            foreach (char ch in host.Credentials.AccountKey)
            {
                securePassword.AppendChar(ch);
            }

            PSCredential cred = new PSCredential(host.Credentials.AccountName, securePassword);

            // Mount storage service as a drive
            using (Pipeline pipe = runspace.CreatePipeline())
            {
                // use a script
                string script = @"new-psdrive -psprovider ""{0}"" -root ""{1}"" -name ""{2}"" -cred $cred -scope ""global"" -ErrorAction stop";

                // add the script twice - once for each drive
                pipe.Commands.AddScript(string.Format(CultureInfo.InvariantCulture, script, "BlobDrive", host.Credentials.BlobServiceEndpoint, BLOBDRIVENAME));
                pipe.Commands.AddScript(string.Format(CultureInfo.InvariantCulture, script, "QueueDrive", host.Credentials.QueueServiceEndpoint, QUEUEDRIVENAME));

                // add the creds variable
                runspace.SessionStateProxy.SetVariable("cred", cred);

                // let it rip!
                pipe.Invoke();
            }

            return runspace;
        }
    }
}