using Helpers.Log;
using log4net;
using Microsoft.Win32;
using System;
using System.Collections;
using System.Management;
using System.Reflection;

/// <summary>
/// A Helper class which provides convenient methods to set/get network
/// configuration
/// </summary>
public class WMIHelper
{
    #region Static Fields

    private static ILog logger = Logger.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);

    #endregion

    #region Static Methods

    /// <summary>
    /// Returns the network card configuration of the specified NIC
    /// </summary>
    /// <param name="nicId">Name of the NIC</param>
    /// <param name="ipAdresses">Array of IP</param>
    /// <param name="subnets">Array of subnet masks</param>
    /// <param name="gateways">Array of gateways</param>
    /// <param name="dnses">Array of DNS IP</param>
    public static void GetIP(string nicId, out string[] ipAdresses, out string[] subnets, out string[] gateways, out string[] dnses)
    {
        ipAdresses = null;
        subnets = null;
        gateways = null;
        dnses = null;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            //By Nicolas Lareu (ATK) - 2015-05-14: Comment out the if with IPEnabled because when the network interface card
            //to use is wifi, this property only returns true if it is just connected to a wifi network.

            //// Make sure this is a IP enabled device. Not something like memory card or VM Ware
            //if ((bool)mo["IPEnabled"])
            //{
            if (mo["SettingID"].ToString().Equals(nicId, StringComparison.OrdinalIgnoreCase))
            {
                ipAdresses = (string[])mo["IPAddress"];
                subnets = (string[])mo["IPSubnet"];
                gateways = (string[])mo["DefaultIPGateway"];
                dnses = (string[])mo["DNSServerSearchOrder"];

                break;
            }
            //}
        }
    }
    public static ManagementObject GetNetworkAdapterById(string nicId)
    {
        ManagementObject nic = null;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
        ManagementObjectCollection moc = mc.GetInstances();

        if (nicId.StartsWith("{") == false)
            nicId = "{" + nicId + "}";

        foreach (ManagementObject mo in moc)
        {
            string guid = (string)mo["GUID"];

            if ((string.IsNullOrWhiteSpace(guid) == false) && (guid.Equals(nicId, StringComparison.OrdinalIgnoreCase) == true))
            {
                nic = mo;

                break;
            }
        }

        return nic;
    }
    public static ManagementObject GetNetworkAdapterByName(string nicName)
    {
        ManagementObject nic = null;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string netConnectionId = (string)mo["NetConnectionID"];

            if ((string.IsNullOrWhiteSpace(netConnectionId) == false) && (netConnectionId.Equals(nicName, StringComparison.OrdinalIgnoreCase) == true))
            {
                nic = mo;

                break;
            }
        }

        return nic;
    }
    public static ManagementObject GetNetworkAdapterConfiguration(string nicId)
    {
        ManagementObject nic = null;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string settingID = (string)mo["SettingID"];

            if ((string.IsNullOrWhiteSpace(settingID) == false) && (settingID.Equals(nicId, StringComparison.OrdinalIgnoreCase) == true))
            {
                nic = mo;

                break;
            }
        }

        return nic;
    }
    public static string GetNicId(string nicName)
    {
        string nicId = "";

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string caption = (string)mo["Caption"];

            if ((string.IsNullOrWhiteSpace(caption) == false) && (caption.Equals(nicName, StringComparison.OrdinalIgnoreCase) == true))
            {
                nicId = mo["NetConnectionId"].ToString();

                break;
            }
        }

        return nicId;
    }
    /// <summary>
    /// Returns the list of Network Interfaces installed
    /// </summary>
    /// <returns>Array list of string</returns>
    public static ArrayList GetNICNames()
    {
        ArrayList nicNames = new ArrayList();

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            //By Nicolas Lareu (ATK) - 2015-05-14: Comment out the if with IPEnabled because when the network interface card
            //to use is wifi, this property only returns true if it is just connected to a wifi network.

            //// Make sure this is a IP enabled device. Not something like memory card or VM Ware
            //if ((bool)mo["IPEnabled"])
            //{
            nicNames.Add(mo["Caption"]);
            //}
        }

        return nicNames;
    }
    public static bool IsNicEnable(string nicId)
    {
        bool enable = false;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string netConnectionId = (string)mo["NetConnectionId"];

            if ((string.IsNullOrWhiteSpace(netConnectionId) == false) && (netConnectionId.Equals(nicId, StringComparison.OrdinalIgnoreCase) == true))
            {
                enable = (bool)mo["NetEnabled"];

                break;
            }
        }

        return enable;
    }
	/// <summary>
	/// Enable DHCP on the NIC
	/// </summary>
	/// <param name="nicName">Name of the NIC</param>
	public static void SetDHCP(string nicId)
	{
        Registry.SetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "EnableDhcp",
            1
        );

        //cleaning values for DefaultGateway, IPAddress and SubnetMask when switching to DHCP.
        Registry.SetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "DefaultGateway",
            string.Empty
        );

        Registry.SetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "IPAddress",
            string.Empty
        );

        Registry.SetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "SubnetMask",
            string.Empty
        );

        //ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        //ManagementObjectCollection moc = mc.GetInstances();

        //foreach(ManagementObject mo in moc)
        //{
        //    //By Nicolas Lareu (ATK) - 2015-05-14: Comment out the if with IPEnabled because when the network interface card
        //    //to use is wifi, this property only returns true if it is just connected to a wifi network.

        //    //// Make sure this is a IP enabled device. Not something like memory card or VM Ware
        //    //if( (bool)mo["IPEnabled"] )
        //    //{
        //        if (mo["SettingID"].ToString().Equals(nicId, StringComparison.OrdinalIgnoreCase))
        //        {
        //            ManagementBaseObject methodParamsObj;
        //            ManagementBaseObject resultObj;
        //            uint resultCode;


        //            resultObj = mo.InvokeMethod("EnableDHCP", null, null);
        //            resultCode = (uint)resultObj["ReturnValue"];
        //            logger.Debug(string.Format("{0} - 'Win32_NetworkAdapterConfiguration.EnableDHCP' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));


        //            methodParamsObj = mo.GetMethodParameters("SetDNSServerSearchOrder");
        //            methodParamsObj["DNSServerSearchOrder"] = null;
        //            resultObj = mo.InvokeMethod("SetDNSServerSearchOrder", methodParamsObj, null);
        //            resultCode = (uint)resultObj["ReturnValue"];
        //            logger.Debug(string.Format("{0} - 'Win32_NetworkAdapterConfiguration.EnableDHCP' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));

        //            break;
        //        }
        //    //}
        //}
	}
    public static bool SetDisable(string nicId)
    {
        bool success = false;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string netConnectionId = (string)mo["NetConnectionId"];

            if ((string.IsNullOrWhiteSpace(netConnectionId) == false) && (netConnectionId.Equals(nicId, StringComparison.OrdinalIgnoreCase) == true))
            {
                ManagementBaseObject resultObj;
                uint resultCode;

                resultObj = mo.InvokeMethod("Disable", null, null);

                resultCode = (uint)resultObj["ReturnValue"];

                logger.Debug(string.Format("{0} - 'Win32_NetworkAdapter.Disable' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));

                if (resultCode == 0)
                    success = true;

                break;
            }
        }

        return success;
    }
    public static void SetDNS(string nicId, string dnsSearchOrder)
    {
        Registry.SetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "NameServer",
            (dnsSearchOrder != null) ? dnsSearchOrder : ""
        );

        //ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        //ManagementObjectCollection moc = mc.GetInstances();

        //foreach (ManagementObject mo in moc)
        //{
        //    //By Nicolas Lareu (ATK) - 2015-05-14: Comment out the if with IPEnabled because when the network interface card
        //    //to use is wifi, this property only returns true if it is just connected to a wifi network.

        //    //// Make sure this is a IP enabled device. Not something like memory card or VM Ware
        //    //if ((bool)mo["IPEnabled"])
        //    //{
        //        if (mo["SettingID"].ToString().Equals(nicId, StringComparison.OrdinalIgnoreCase))
        //        {
        //            ManagementBaseObject methodParamsObj;
        //            ManagementBaseObject resultObj;
        //            uint resultCode;

        //            methodParamsObj = mo.GetMethodParameters("SetDNSServerSearchOrder");

        //            methodParamsObj["DNSServerSearchOrder"] = DnsSearchOrder.Split(',');

        //            resultObj = mo.InvokeMethod("SetDNSServerSearchOrder", methodParamsObj, null);

        //            resultCode = (uint)resultObj["ReturnValue"];

        //            logger.Debug(string.Format("{0} - 'Win32_NetworkAdapterConfiguration.SetDNSServerSearchOrder' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));

        //            break;
        //        }
        //    //}
        //}
    }
    public static bool SetEnable(string nicId)
    {
        bool success = false;

        ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            string netConnectionId = (string)mo["NetConnectionId"];

            if ((string.IsNullOrWhiteSpace(netConnectionId) == false) && (netConnectionId.Equals(nicId, StringComparison.OrdinalIgnoreCase) == true))
            {
                ManagementBaseObject resultObj;
                uint resultCode;

                resultObj = mo.InvokeMethod("Enable", null, null);

                resultCode = (uint)resultObj["ReturnValue"];

                logger.Debug(string.Format("{0} - 'Win32_NetworkAdapter.Enable' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));


                if (resultCode == 0)
                    success = true;

                break;
            }
        }

        return success;
    }
	/// <summary>
	/// Set IP for the specified network card name
	/// </summary>
	/// <param name="nicId">Caption of the network card</param>
	/// <param name="ipAddresses">Comma delimited string containing one or more IP</param>
	/// <param name="subnetMask">Subnet mask</param>
	/// <param name="gateway">Gateway IP</param>
	/// <param name="dnsSearchOrder">Comma delimited DNS IP</param>
	public static void SetIP(string nicId, string ipAddresses, string subnetMask, string gateway, string dnsSearchOrder)
	{
        ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
        ManagementObjectCollection moc = mc.GetInstances();

        foreach (ManagementObject mo in moc)
        {
            //By Nicolas Lareu (ATK) - 2015-05-14: Comment out the if with IPEnabled because when the network interface card
            //to use is wifi, this property only returns true if it is just connected to a wifi network.

            //// Make sure this is a IP enabled device. Not something like memory card or VM Ware
            //if ((bool)mo["IPEnabled"])
            //{
                if (mo["SettingID"].ToString().Equals(nicId, StringComparison.OrdinalIgnoreCase))
                {
                    ManagementBaseObject methodParamsObj;
                    ManagementBaseObject resultObj;
                    uint resultCode;


                    methodParamsObj = mo.GetMethodParameters("EnableStatic");
                    methodParamsObj["IPAddress"] = ipAddresses.Split(',');
                    methodParamsObj["SubnetMask"] = new string[] { subnetMask };
                    resultObj = mo.InvokeMethod("EnableStatic", methodParamsObj, null);
                    resultCode = (uint)resultObj["ReturnValue"];
                    logger.Debug(string.Format("{0} - 'Win32_NetworkAdapterConfiguration.EnableStatic' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));


                    methodParamsObj = mo.GetMethodParameters("SetGateways");
                    methodParamsObj["DefaultIPGateway"] = new string[] { gateway };
                    methodParamsObj["GatewayCostMetric"] = new int[] { 1 };
                    resultObj = mo.InvokeMethod("SetGateways", methodParamsObj, null);
                    resultCode = (uint)resultObj["ReturnValue"];
                    logger.Debug(string.Format("{0} - 'Win32_NetworkAdapterConfiguration.SetGateways' result code: {1}", MethodBase.GetCurrentMethod().Name, resultCode));


                    WMIHelper.SetDNS(nicId, dnsSearchOrder);

                    break;
                }
            //}
        }
	}

	#endregion
}