using Helpers.Common;
using Microsoft.Win32;
using SimpleWifi.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Net.Sockets;

public class NetworkInterfaceInfo
{
    #region Properties

    public string DefaultGateway { get; set; }
    public string Description { get; set; }
    public bool? DhcpEnabled { get; set; }
    public bool? Enabled { get; set; }
    public string Id { get; set; }
    public string Ip4Address { get; set; }
    public bool? IsDnsServerAutomatic { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public string PreferredDns { get; set; }
    public string Subnetmask { get; set; }

    #endregion

    #region Constructors

    public NetworkInterfaceInfo() { }

    #endregion

    #region Methods

    public override string ToString()
    {
        try
        {
            return Helper.ObjectToString(this);
        }
        catch
        {
            return "";
        }
    }

    #endregion

    #region Static Methods

    public static NetworkInterfaceInfo GetNetworkInterfaceInfo(string nicName)
    {
        NetworkInterfaceInfo netInterfaceInfo = null;

        NetworkInterface netInterface = NetworkInterfaceInfo.GetNetworkInterface(nicName);


        if (netInterface != null)
        {
            var netInterfaceProps = netInterface.GetIPProperties();

            var netInterfacePropsIpv4 = netInterfaceProps.GetIPv4Properties();

            netInterfaceInfo = new NetworkInterfaceInfo
            {
                Description = netInterface.Description,
                Id = netInterface.Id,
                IsDnsServerAutomatic = NetworkInterfaceInfo.IsDnsServerObtainedAutomatically(netInterface.Id),
                Name = nicName,
            };


            //Default gateway.
            if (netInterfaceProps.GatewayAddresses.Count > 0)
                netInterfaceInfo.DefaultGateway = netInterfaceProps.GatewayAddresses.First().Address.ToString();

            //Dhcp enabled.
            if (netInterfacePropsIpv4 != null)
                netInterfaceInfo.DhcpEnabled = netInterfacePropsIpv4.IsDhcpEnabled;


            //Dns server.
            if (netInterfaceProps.DnsAddresses.Count > 0)
                netInterfaceInfo.PreferredDns = netInterfaceProps.DnsAddresses.First().ToString();

            if (netInterfaceProps.UnicastAddresses.Count > 0)
            {
                var address = (netInterfaceProps.UnicastAddresses.Count == 1)
                                    ? netInterfaceProps.UnicastAddresses[0]
                                    : netInterfaceProps.UnicastAddresses[1];

                //Ipv4 address.
                netInterfaceInfo.Ip4Address = address.Address.ToString();

                //Subnetmask.
                netInterfaceInfo.Subnetmask = address.IPv4Mask.ToString();
            }
        }
        else
        {
            netInterfaceInfo = NetworkInterfaceInfo.GetNetworkInterfaceInfoFromRegistry(nicName);
        }

        return netInterfaceInfo;
    }
    private static NetworkInterfaceInfo GetNetworkInterfaceInfoFromRegistry(string nicName)
    {
        NetworkInterfaceInfo netInterfaceInfo = null;

        ManagementObject nicAdapObj = WMIHelper.GetNetworkAdapterByName(nicName);

        if (nicAdapObj != null)
        {
            string nicId = (string)nicAdapObj["GUID"];
            string regTemplate = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}";

            bool dhcpEnabled = ((int)Registry.GetValue(string.Format(regTemplate, nicId), "EnableDHCP", null) == 1);

            string regDhcpPrefix = (dhcpEnabled == true)
                                            ? "Dhcp"
                                            : "";

            //Watch out with default gateway because it can be null.
            object defaultGatewayReg = Registry.GetValue(string.Format(regTemplate, nicId), regDhcpPrefix + "DefaultGateway", null);
            object ipAddressReg = Registry.GetValue(string.Format(regTemplate, nicId), regDhcpPrefix + "IPAddress", null);
            object preferredDnsReg = Registry.GetValue(string.Format(regTemplate, nicId), "NameServer", null);
            object subnetmaskReg = Registry.GetValue(string.Format(regTemplate, nicId), regDhcpPrefix + "SubnetMask", null);

            string preferredDns = NetworkInterfaceInfo.ParseNicNullableField(preferredDnsReg);

            netInterfaceInfo = new NetworkInterfaceInfo
            {
                DefaultGateway = NetworkInterfaceInfo.ParseNicNullableField(defaultGatewayReg),
                Description = (string)nicAdapObj["Name"],
                DhcpEnabled = dhcpEnabled,
                Enabled = (bool)nicAdapObj["NetEnabled"],
                Id = nicId,
                Ip4Address = NetworkInterfaceInfo.ParseNicNullableField(ipAddressReg),
                IsDnsServerAutomatic = string.IsNullOrWhiteSpace(preferredDns),
                Name = nicName,
                PreferredDns = preferredDns,
                Subnetmask = NetworkInterfaceInfo.ParseNicNullableField(subnetmaskReg),
            };
        }

        return netInterfaceInfo;
    }    
    public static NetworkInterface GetNetworkInterface(string nicName = null, string description = null, NetworkInterfaceType type = NetworkInterfaceType.Unknown, List<String> excludeNames = null, List<String> excludeDescriptions = null)
    {
        NetworkInterface netInterfaceFound = null;
        NetworkInterface[] netInterfaces = NetworkInterface.GetAllNetworkInterfaces();

        excludeNames = (excludeNames != null) ? excludeNames.ConvertAll(d => d.ToUpper()) : null;
        excludeDescriptions = (excludeDescriptions != null) ? excludeDescriptions.ConvertAll(d => d.ToUpper()) : null; 

        foreach (NetworkInterface netInterface in netInterfaces)
        {
            if (
                (netInterface.Name.Equals(nicName, StringComparison.OrdinalIgnoreCase) == true || nicName == null)
                && (netInterface.Description.Equals(description, StringComparison.OrdinalIgnoreCase) == true || description == null)
                && (netInterface.NetworkInterfaceType == type || type == NetworkInterfaceType.Unknown)
                && (excludeNames == null || !excludeNames.Contains(netInterface.Name.ToUpper()))
                && (
                    excludeDescriptions == null || !excludeDescriptions.Exists(t => netInterface.Description.ToUpper().StartsWith(t.ToUpper()))
                )
            )
            {
                ManagementObject mo = WMIHelper.GetNetworkAdapterById(netInterface.Id);
                if (mo != null)
                {
                    netInterfaceFound = netInterface;
                    break;
                }
            }
        }

        return netInterfaceFound;
    }
    public static WlanInterface GetWlanNetworkInterface(string nicName)
    {
        WlanInterface wlanIfaceFound = null;

        WlanClient client = new WlanClient();

        foreach (WlanInterface wlanIface in client.Interfaces)
        {
            if (wlanIface.NetworkInterface.Name.Equals(nicName, StringComparison.OrdinalIgnoreCase) == true)
            {
                wlanIfaceFound = wlanIface;

                break;
            }
        }

        return wlanIfaceFound;
    }
    private static bool IsDnsServerObtainedAutomatically(string nicId)
    {
        string dnsServerName = (string)Registry.GetValue(
            string.Format(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{0}",
                nicId
            ),
            "NameServer",
            null
        );

        return string.IsNullOrEmpty(dnsServerName);
    }
    private static string ParseNicNullableField(object regValue)
    {
        string parsedValue = (regValue != null)
                                    ? (regValue is string)
                                        ? (string)regValue
                                        : ((string[])regValue)[0]
                                    : "";
        return parsedValue;
    }

    #endregion
}