/*
 * ******************************************************
 * Copyright 2016-2021 VMware, Inc.  All Rights Reserved.
 * ******************************************************
 */

using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.Xml;

namespace VsanHealthSdk
{
    class VsanApiHelper
    {
        public static string VSAN_VC_HEALTH_SYSTEM_TYPE = "VsanVcClusterHealthSystem";
        public static string VSAN_VC_HEALTH_SYSTEM_VALUE = "vsan-cluster-health-system";
        public static string VSAN_PERFORMANCE_SYSTEM_TYPE = "VsanPerformanceManager";
        public static string VSAN_PERFORMANCE_SYSTEM_VALUE = "vsan-performance-manager";
        public static string VSAN_HOST_HEALTH_SYSTEM_TYPE = "HostVsanHealthSystem";
        public static string VSAN_HOST_HEALTH_SYSTEM_VALUE = "ha-vsan-health-system";
        public static string VSAN_VC_DISK_MGMT_SYSTEM_TYPE = "VimClusterVsanVcDiskManagementSystem";
        public static string VSAN_VC_DISK_MGMT_SYSTEM_VALUE = "vsan-disk-management-system";
        public static string VSAN_VC_STRETCHED_CLUSTER_SYSTEM_TYPE = "VimClusterVsanVcStretchedClusterSystem";
        public static string VSAN_VC_STRETCHED_CLUSTER_SYSTEM_VALUE = "vsan-stretched-cluster-system";
        public static string VSAN_VC_CLUSTER_CONFIG_SYSTEM_TYPE = "VsanVcClusterConfigSystem";
        public static string VSAN_VC_CLUSTER_CONFIG_SYSTEM_VALUE = "vsan-cluster-config-system";
        public static string VSAN_VC_ISCSI_TARGET_SYSTEM_TYPE = "VsanIscsiTargetSystem";
        public static string VSAN_VC_ISCSI_TARGET_SYSTEM_VALUE = "vsan-cluster-iscsi-target-system";
        public static string VSAN_UPGRADE_SYSTEM_EX_SYSTEM_TYPE = "VsanUpgradeSystemEx";
        public static string VSAN_UPGRADE_SYSTEM_EX_SYSTEM_VALUE = "vsan-upgrade-systemex";
        public static string VSAN_SPACE_REPORT_SYSTEM_TYPE = "VsanSpaceReportSystem";
        public static string VSAN_SPACE_REPORT_SYSTEM_VALUE = "vsan-cluster-space-report-system";
        public static string VSAN_OBJECT_SYSTEM_SYSTEM_TYPE = "VsanObjectSystem";
        public static string VSAN_CLUSTER_OBJECT_SYSTEM_SYSTEM_VALUE = "vsan-cluster-object-system";
        public static string VSAN_OBJECT_SYSTEM_SYSTEM_VALUE = "vsan-object-system";
        public static string VSAN_VCSA_DEPLOYER_SYSTEM_TYPE = "VsanVcsaDeployerSystem";
        public static string VSAN_VCSA_DEPLOYER_SYSTEM_VALUE = "vsan-vcsa-deployer-system";
        public static string VSAN_SYSTEM_EX_TYPE = "vsanSystemEx";
        public static string VSAN_SYSTEM_EX_VALUE = "vsanSystemEx";
        public static string VSAN_VDS_SYSTEM_TYPE = "VsanVdsSystem";
        public static string VSAN_VDS_SYSTEM_VALUE = "vsan-vds-system";
        public static string VSAN_UPDATE_MANAGER_TYPE = "VsanUpdateManager";
        public static string VSAN_UPDATE_MANAGER_VALUE = "vsan-update-manager";
        public static string VSAN_CAPABILITY_SYSTEM_TYPE = "VsanCapabilitySystem";
        public static string VSAN_VC_CAPABILITY_SYSTEM_VALUE = "vsan-vc-capability-system";
        public static string VSAN_CAPABILITY_SYSTEM_VALUE = "vsan-capability-system";
        public static string VSAN_MASS_COLLECTOR_TYPE = "VsanMassCollector";
        public static string VSAN_MASS_COLLECTOR_VALUE = "vsan-mass-collector";
        public static string VSAN_PHONEHOME_SYSTEM_TYPE = "VsanPhoneHomeSystem";
        public static string VSAN_PHONEHOME_SYSTEM_VALUE = "vsan-phonehome-system";
        public static string VSAN_VUM_SYSTEM_TYPE = "VsanVumSystem";
        public static string VSAN_VUM_SYSTEM_VALUE = "vsan-vum-system";
        public static string VSAN_VC_FILE_SERVICE_SYSTEM_TYPE = "VsanFileServiceSystem";
        public static string VSAN_VC_FILE_SERVICE_SYSTEM_VALUE = "vsan-cluster-file-service-system";
        public static string VSAN_VC_REMOTE_DATASTORE_SYSTEM_TYPE = "VsanRemoteDatastoreSystem";
        public static string VSAN_VC_REMOTE_DATASTORE_SYSTEM_VALUE = "vsan-remote-datastore-system";
        public static string VSAN_IO_INSIGHT_MANAGER_TYPE = "VsanIoInsightManager";
        public static string VSAN_VC_IO_INSIGHT_MANAGER_VALUE = "vsan-cluster-ioinsight-manager";
        public static string VSAN_IO_INSIGHT_MANAGER_VALUE = "vsan-host-ioinsight-manager";
        public static string VSAN_VC_DIAGNOSTIC_SYSTEM_VALUE = "vsan-cluster-diagnostics-system";
        public static string VSAN_VC_CLUSTER_POWER_SYSTEM_VALUE = "vsan-cluster-power-system";
        public static string VSAN_VC_DIAGNOSTIC_SYSTEM_TYPE = "VsanDiagnosticsSystem";
        public static string VSAN_VC_CLUSTER_POWER_SYSTEM_TYPE = "VsanClusterPowerSystem";
        public static Dictionary<string, string> VsanMoTypes = new Dictionary<string, string>()
        {
            {VSAN_VC_HEALTH_SYSTEM_VALUE, VSAN_VC_HEALTH_SYSTEM_TYPE},
            {VSAN_PERFORMANCE_SYSTEM_VALUE, VSAN_PERFORMANCE_SYSTEM_TYPE},
            {VSAN_HOST_HEALTH_SYSTEM_VALUE, VSAN_HOST_HEALTH_SYSTEM_TYPE},
            {VSAN_VC_DISK_MGMT_SYSTEM_VALUE, VSAN_VC_DISK_MGMT_SYSTEM_TYPE},
            {VSAN_VC_STRETCHED_CLUSTER_SYSTEM_VALUE, VSAN_VC_STRETCHED_CLUSTER_SYSTEM_TYPE},
            {VSAN_VC_CLUSTER_CONFIG_SYSTEM_VALUE, VSAN_VC_CLUSTER_CONFIG_SYSTEM_TYPE},
            {VSAN_VC_ISCSI_TARGET_SYSTEM_VALUE, VSAN_VC_ISCSI_TARGET_SYSTEM_TYPE},
            {VSAN_UPGRADE_SYSTEM_EX_SYSTEM_VALUE,  VSAN_UPGRADE_SYSTEM_EX_SYSTEM_TYPE},
            {VSAN_SPACE_REPORT_SYSTEM_VALUE, VSAN_SPACE_REPORT_SYSTEM_TYPE},
            {VSAN_CLUSTER_OBJECT_SYSTEM_SYSTEM_VALUE, VSAN_OBJECT_SYSTEM_SYSTEM_TYPE},
            {VSAN_OBJECT_SYSTEM_SYSTEM_VALUE, VSAN_OBJECT_SYSTEM_SYSTEM_TYPE},
            {VSAN_VCSA_DEPLOYER_SYSTEM_VALUE, VSAN_VCSA_DEPLOYER_SYSTEM_TYPE},
            {VSAN_VC_CAPABILITY_SYSTEM_VALUE, VSAN_CAPABILITY_SYSTEM_TYPE},
            {VSAN_CAPABILITY_SYSTEM_VALUE, VSAN_CAPABILITY_SYSTEM_TYPE},
            {VSAN_SYSTEM_EX_VALUE, VSAN_SYSTEM_EX_TYPE},
            {VSAN_VDS_SYSTEM_VALUE, VSAN_VDS_SYSTEM_TYPE},
            {VSAN_UPDATE_MANAGER_VALUE, VSAN_UPDATE_MANAGER_TYPE},
            {VSAN_MASS_COLLECTOR_VALUE, VSAN_MASS_COLLECTOR_TYPE},
            {VSAN_PHONEHOME_SYSTEM_VALUE, VSAN_PHONEHOME_SYSTEM_TYPE},
            {VSAN_VUM_SYSTEM_VALUE, VSAN_VUM_SYSTEM_TYPE},
            {VSAN_VC_FILE_SERVICE_SYSTEM_VALUE, VSAN_VC_FILE_SERVICE_SYSTEM_TYPE},
            {VSAN_VC_REMOTE_DATASTORE_SYSTEM_VALUE, VSAN_VC_REMOTE_DATASTORE_SYSTEM_TYPE},
            {VSAN_VC_IO_INSIGHT_MANAGER_VALUE, VSAN_IO_INSIGHT_MANAGER_TYPE},
            {VSAN_IO_INSIGHT_MANAGER_VALUE, VSAN_IO_INSIGHT_MANAGER_TYPE},
            {VSAN_VC_DIAGNOSTIC_SYSTEM_VALUE, VSAN_VC_DIAGNOSTIC_SYSTEM_TYPE},
            {VSAN_VC_CLUSTER_POWER_SYSTEM_VALUE, VSAN_VC_CLUSTER_POWER_SYSTEM_TYPE}
        };

        public static Dictionary<string, VsanHealthApi.ManagedObjectReference> GetVsanMos()
        {
            Dictionary<string, VsanHealthApi.ManagedObjectReference> VsanMoDict =
                new Dictionary<string, VsanHealthApi.ManagedObjectReference>();

            foreach (KeyValuePair<string, string>VsanMoType in VsanMoTypes)
            {
                VsanHealthApi.ManagedObjectReference vsanSystemMoRef = new VsanHealthApi.ManagedObjectReference();
                vsanSystemMoRef.Value = VsanMoType.Key;
                vsanSystemMoRef.type = VsanMoType.Value;
                VsanMoDict.Add(VsanMoType.Key, vsanSystemMoRef);
            };
            return VsanMoDict;
        }

        public static string getVmodlNamespace(AppUtil.AppUtil conn)
        {
            Uri connUrl = getConnectionUrl(conn);
            string hostname = connUrl.Host;
            string vsanServiceVersionXml = "https://" + hostname + "/sdk/vsanServiceVersions.xml";
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(vsanServiceVersionXml);
                string version = doc.GetElementsByTagName("version")[0].InnerText;
                if (version == "6.6")
                {
                    return VsanHealthApi.VsanhealthService.VSAN_VMODL_NAMESPACE + "/" + version;
                }
                return VsanHealthApi.VsanhealthService.VSAN_VMODL_NAMESPACE;
            }
            catch
            {
                return VsanHealthApi.VsanhealthService.VIM25_VMODL_NAMESPACE;
            }
        }

        public static VsanHealthApi.VsanhealthService ConstructVsanHealthConnection(AppUtil.AppUtil conn)
        {
            VsanHealthApi.VsanhealthService vsanhealthConn = new VsanHealthApi.VsanhealthService();
            Uri connUrl = getConnectionUrl(conn);
            string Url = getServiceEndpoint(conn, connUrl);
            CookieContainer cookieContainer = new CookieContainer();
            cookieContainer.Add(getConnectionCookie(conn, connUrl));
            int timeout = 600000;

            string ns = getVmodlNamespace(conn);
            vsanhealthConn.ConnectVsanService(ns, Url, cookieContainer, timeout);

            return vsanhealthConn;
        }

        public static bool IsEsx(AppUtil.AppUtil conn)
        {
            Vim25Api.AboutInfo aboutInfo = conn.getConnection().ServiceContent.about;
            return (aboutInfo.apiType == "HostAgent" ? true : false);
        }

        public static VsanHealthApi.ManagedObjectReference convertMo(Vim25Api.ManagedObjectReference vim25Mo)
        {
            VsanHealthApi.ManagedObjectReference vsanMo = new VsanHealthApi.ManagedObjectReference();
            vsanMo.type = vim25Mo.type;
            vsanMo.Value = vim25Mo.Value;
            return vsanMo;
        }

        public static Vim25Api.ManagedObjectReference convertMo(VsanHealthApi.ManagedObjectReference vim25Mo)
        {
            Vim25Api.ManagedObjectReference vsanMo = new Vim25Api.ManagedObjectReference();
            vsanMo.type = vim25Mo.type;
            vsanMo.Value = vim25Mo.Value;
            return vsanMo;
        }

        public static void monitorTask(AppUtil.AppUtil vimConn, string taskName, VsanHealthApi.ManagedObjectReference task)
        {

            if (task != null)
            {
                String result = vimConn.getServiceUtil().WaitForTask(convertMo(task));
                if (result.Equals("sucess"))
                {
                    Console.WriteLine(taskName + " Completed Successfully");
                }
                else
                {
                    Console.WriteLine(taskName + " Failed: " + result);
                }
            }
        }

        private static Uri getConnectionUrl(AppUtil.AppUtil conn)
        {
            string urlString = conn.getServiceUrl();
            return new Uri(urlString);
        }

        private static string getServiceEndpoint(AppUtil.AppUtil conn, Uri connUrl)
        {
            string serverUrl = connUrl.Host;
            string vsanUrlPath = IsEsx(conn) ? "/vsan" : "/vsanHealth";
            string healthEndpoint = "https://" + serverUrl + vsanUrlPath;
            return healthEndpoint;
        }

        private static CookieCollection getConnectionCookie(AppUtil.AppUtil conn, Uri connUrl)
        {
            var cookieManager = ((IContextChannel)conn.getConnection()._service).GetProperty<IHttpCookieContainerManager>();
            CookieCollection cookie = cookieManager.CookieContainer.GetCookies(connUrl);
            return cookie;
        }
    }
}
