//#define NODB

using Helpers.Log;
using log4net;
using Security;
using SimpleWifi;
using SimpleWifi.Win32;
using SimpleWifi.Win32.Interop;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Reflection;
using System.ServiceProcess;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.Win32;
using System.Diagnostics;
using System.Xml.Linq;

/// <summary>
/// Summary description for SystemInitConfiguration
/// </summary>
public static class IhBoxSystemtConfiguration
{
    private static ILog logger = Logger.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);
    private static string systemConnectionString = ConfigurationManager.ConnectionStrings["SYSTEM"].ConnectionString;
    private static NetworkInterfaceInfo tempEthernetConfig;
    private static WifiNetworkInterfaceInfo tempWifiConfig;
    private static SystemDatetimeConfiguration tempSysDatetimeConfig;
    private static Wifi _wifi;
    private static Wifi wifi
    {
        get
        {
            if (_wifi == null)
            {
                while (true)
                {
                    _wifi = new Wifi();

                    if (_wifi.NoWifiAvailable == false)
                        break;
                    else
                        Thread.Sleep(50);
                }
            }

            return _wifi;
        }
    }

    public const string NETWORK_TYPE_ETHERNET = "ETHERNET";
    public const string NETWORK_TYPE_WIFI = "WIFI";

    public static string NETWORK_ETHERNET_NIC_NAME = "Ethernet";
    public static string NETWORK_WIFI_NIC_NAME = "Wi-Fi";

#if NODB
    private static SystemInitialConfigurationStatus _initialConfigurationStatus;
#endif

    public static SystemInitialConfigurationStatus InitialConfigurationStatus
    {
#if !NODB
        get
        {
            SystemInitialConfigurationStatus configStatus = SystemInitialConfigurationStatus.Unknown;

            while (configStatus == SystemInitialConfigurationStatus.Unknown)
            {
                try
                {
                    SqlConnection sqlCon = new SqlConnection();
                    sqlCon.ConnectionString = IhBoxSystemtConfiguration.systemConnectionString;
                    sqlCon.Open();
                    SqlCommand comm = new SqlCommand("FrontEnd.CheckSystemConfigured", sqlCon);
                    comm.CommandType = CommandType.StoredProcedure;

                    SqlParameter sqlParam = new SqlParameter("@UserName", SqlDbType.VarChar);
                    sqlParam.Value = "admin";
                    comm.Parameters.Add(sqlParam);

                    var result = comm.ExecuteScalar();

                    //If the system is reseting to factory default at the moment that this code is executed, it is possible
                    //that this query return null and it is ok. So check if query result is null. If yes, return unknown status.
                    if (result != null)
                        configStatus = (SystemInitialConfigurationStatus)result;

                    sqlCon.Close();
                    sqlCon.Dispose();
                }
                catch (Exception ex)
                {
                    configStatus = SystemInitialConfigurationStatus.Unknown;
                    logger.Error("Error getting ConfigurationStatus. Waiting 1 second to get the ConfigurationStatus from DB.", ex);
                    Thread.Sleep(1000);
                }
            }

            return configStatus;
        }
#else
        get {
            return _initialConfigurationStatus;
        }
#endif
    }
    public static Response previousConfigurationResult;
    public static Response PreviousConfigurationResult
    {
        get { return previousConfigurationResult; }
        private set
        {
            previousConfigurationResult = value;

            PreviousConfigurationResultId = Guid.NewGuid().ToString();
        }
    }
    public static string PreviousConfigurationResultId { get; private set; }

    static IhBoxSystemtConfiguration()
    {
        try
        {
            logger.Debug("Starting IHBoxSystemConfiguration ...");
            SystemInitialConfigurationStatus status = IhBoxSystemtConfiguration.InitialConfigurationStatus;

            Thread thread;
            logger.Debug(string.Format("IHBoxSystem status: [{0}]", status.ToString()));
            switch (status)
            {
                case SystemInitialConfigurationStatus.ResetToFactoryDefaults:
                    thread = new Thread(new ThreadStart(delegate()
                    {
                        IhBoxSystemtConfiguration.ResetToFactoryDefaults();
                    }));
                    thread.Start();
                    break;
                case SystemInitialConfigurationStatus.Recovering:
                case SystemInitialConfigurationStatus.Configuring:
                    IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.Recovering);
                    thread = new Thread(new ThreadStart(delegate()
                    {
                        IhBoxSystemtConfiguration.ResetToFactoryDefaults();
                    }));
                    thread.Start();
                    break;
            }

            NetworkInterface ni_ethernet = NetworkInterfaceInfo.GetNetworkInterface(null, null, NetworkInterfaceType.Ethernet, null, new List<string>() { "Microsoft Hosted Network Virtual Adapter", "Microsoft Wi-Fi Direct Virtual Adapter", "TeamViewer VPN Adapter" });
            NetworkInterface ni_wifi = NetworkInterfaceInfo.GetNetworkInterface(null, null, NetworkInterfaceType.Wireless80211, null, new List<string>() { "Microsoft Hosted Network Virtual Adapter", "Microsoft Wi-Fi Direct Virtual Adapter", "TeamViewer VPN Adapter" });

            if (ni_ethernet != null) NETWORK_ETHERNET_NIC_NAME = ni_ethernet.Name;
            if (ni_wifi != null) NETWORK_WIFI_NIC_NAME = ni_wifi.Name;

            logger.Debug("Detected Ethernet Nic Name: " + NETWORK_ETHERNET_NIC_NAME);
            logger.Debug("Detected WiFi Nic Name: " + NETWORK_WIFI_NIC_NAME);

            //logger.Debug("Starting ad-hoc network with IIS...");
            //try
            //{
            //    logger.Debug("Creating ad-hoc network for IHBOX for computer: " + Environment.MachineName + " ...");
            //    ExecuteCommandOnServer(null, "netsh wlan set hostednetwork mode=allow ssid=" + Environment.MachineName + " key=historianbox");

            //    NetworkInterface adhocni = NetworkInterfaceInfo.GetNetworkInterface(null, "Microsoft Hosted Network Virtual Adapter", NetworkInterfaceType.Wireless80211);
            //    if (adhocni != null)
            //    {
            //        logger.Debug("Found ad-hoc network interface, setting ip to 192.168.137.1");
            //        WMIHelper.SetIP(adhocni.Id, "192.168.137.1", "255.255.255.0", "", "");
            //        logger.Debug("Setting ad-hoc network to enabled");
            //        WMIHelper.SetEnable(adhocni.Name);
            //    }

            //    ExecuteCommandOnServer(null, "netsh wlan start hostednetwork");
            //}
            //catch (Exception ex)
            //{
            //    logger.Debug("Error while creating ad-hoc network for IHBOX: " + ex.Message);
            //}
        }
        catch (Exception ex)
        {
            logger.Error("IhBoxSystemtConfiguration.", ex);
            IhBoxSystemtConfiguration.RestartSystem();
        }
    }

    public static Response ConfigureDatetime(SystemDatetimeConfiguration sysDatetimeConfig)
    {
        return IhBoxSystemtConfiguration.ConfigureDatetime(sysDatetimeConfig, false);
    }
    private static Response ConfigureDatetime(SystemDatetimeConfiguration sysDatetimeConfig, bool forced)
    {
        Response response;

        if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
        {
            response = IhBoxSystemtConfiguration.ValidateSystemDatetimeConfiguration(sysDatetimeConfig);

            if (response.Success == true)
            {
                TimeZoneInfo newTimeZone = TimeZoneInfo.FindSystemTimeZoneById(sysDatetimeConfig.TimeZoneId);

                DateTime sysDatetimeUtc = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse(sysDatetimeConfig.Datetime), newTimeZone);

                //TimeZoneInformation sysTimeZone = new TimeZoneInformation
                //{
                //    bias = newTimeZone.sf,
                //    daylightBias = newTimeZone.sf,
                //    bias = newTimeZone.sf,
                //    bias = newTimeZone.sf,
                //    bias = newTimeZone.sf,

                //};

                //Pinvoke.SetTimeZoneInformation(red 

                SystemTime sysTime = new SystemTime
                {
                    wYear = (short)sysDatetimeUtc.Year,
                    wMonth = (short)sysDatetimeUtc.Month,
                    wDay = (short)sysDatetimeUtc.Day,
                    wDayOfWeek = (short)sysDatetimeUtc.DayOfWeek,
                    wHour = (short)sysDatetimeUtc.Hour,
                    wMinute = (short)sysDatetimeUtc.Minute,
                    wSecond = (short)sysDatetimeUtc.Second,
                    wMilliseconds = (short)sysDatetimeUtc.Millisecond,
                };

                response = new Response
                {
                    Success = Pinvoke.SetSystemTime(ref sysTime),
                };

                if (response.Success)
                {
                    response = SetSyncWithInternetTime(sysDatetimeConfig.SyncWithInternetEnabled);
                }
            }
        }
        else
        {
            response = new Response();
        }

        return response;
    }
    public static Response ConfigureNetworkInterface(NetworkInterfaceInfo networkConfig)
    {
        return IhBoxSystemtConfiguration.ConfigureNetworkInterface(networkConfig, false, true);
    }
    public static Response ConfigureNetworkInterface(NetworkInterfaceInfo networkConfig, bool forced)
    {
        return IhBoxSystemtConfiguration.ConfigureNetworkInterface(networkConfig, forced, true);
    }
    private static Response ConfigureNetworkInterface(NetworkInterfaceInfo networkConfig, bool forced, bool validateConfig, bool restartInterfaces = true)
    {
        Response response = new Response();
        NetworkInterfaceInfo netIfaceInfo = null;

        try
        {
            if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
            {
                if (validateConfig == true)
                    response = IhBoxSystemtConfiguration.ValidateNetworkInterfaceConfiguration(networkConfig);

                if (response.Success == true)
                {
                    string nicName = networkConfig.Name;

                    string default_gateway = networkConfig.DefaultGateway;
                    bool dhcpEnabled = (networkConfig.DhcpEnabled != null) ? (bool)networkConfig.DhcpEnabled : true;
                    string ip_address = networkConfig.Ip4Address;
                    bool isDnsServerAutomatic = (networkConfig.IsDnsServerAutomatic != null) ? (bool)networkConfig.IsDnsServerAutomatic : true;
                    string preferred_dns = networkConfig.PreferredDns;
                    string subnet_mask = networkConfig.Subnetmask;


                    netIfaceInfo = IhBoxSystemtConfiguration.GetNetworkConfiguration(nicName, forced);

                    if (netIfaceInfo != null)
                    {
                        if (netIfaceInfo != null)
                        {
                            logger.Debug(string.Format("Current status of nic '{0}': {1}", nicName, netIfaceInfo));

                            if (dhcpEnabled == false)
                            {
                                if (validateConfig == true)
                                {
                                    string otherNicName = (nicName.Equals(NETWORK_ETHERNET_NIC_NAME, StringComparison.OrdinalIgnoreCase) == true)
                                                                ? NETWORK_WIFI_NIC_NAME
                                                                : NETWORK_ETHERNET_NIC_NAME;

                                    NetworkInterfaceInfo otherNicInfo = IhBoxSystemtConfiguration.GetNetworkConfiguration(otherNicName);

                                    if (otherNicInfo != null)
                                    {
                                        if (otherNicInfo.DhcpEnabled == true)
                                        {
                                            try
                                            {
                                                WMIHelper.SetIP(netIfaceInfo.Id, ip_address, subnet_mask, default_gateway, preferred_dns);
                                            }
                                            catch (Exception ex)
                                            {
                                                response = new Response
                                                {
                                                    Success = false,
                                                    Message = string.Format(
                                                        "Error when getting info of nic '{0}' before validate if unless one network card has dhcp enable.",
                                                        nicName
                                                    ),
                                                };
                                            }

                                            response = new Response();
                                        }
                                        else
                                        {
                                            response = new Response
                                            {
                                                Success = false,
                                                //Message = "response_error_both_static_ip",
                                                Message = "Error: Both networks, Ethernet and Wi-Fi, can not be configured with static ip simultaneously.",
                                            };
                                        }
                                    }
                                    else
                                    {
                                        response = new Response
                                        {
                                            Success = false,
                                            Message = string.Format(
                                                "Can not get info of nic '{0}' before validate if unless one network card has dhcp enable.",
                                                otherNicName
                                            ),
                                        };
                                    }
                                }
                                else
                                {
                                    WMIHelper.SetIP(netIfaceInfo.Id, ip_address, subnet_mask, default_gateway, preferred_dns);
                                }
                            }
                            else
                            {
                                try
                                {
                                    WMIHelper.SetDHCP(netIfaceInfo.Id);
                                }
                                catch (Exception ex)
                                {
                                    throw new FriendlyMessageException(string.Format("Error when setting dhcp enable to nic '{0}'", nicName), ex);
                                }


                                if (isDnsServerAutomatic == false)
                                {
                                    try
                                    {
                                        WMIHelper.SetDNS(netIfaceInfo.Id, preferred_dns);
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new FriendlyMessageException(string.Format("Error when setting static dns server to nic '{0}'", nicName), ex);
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        WMIHelper.SetDNS(netIfaceInfo.Id, "");
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new FriendlyMessageException(string.Format("Error when setting automatic dns server to nic '{0}'", nicName), ex);
                                    }
                                }
                            }
                        }
                        else
                        {
                            response = new Response
                            {
                                Success = false,
                                Message = string.Format("Can not get info of nic '{0}' before set the new configuration.", nicName),
                            };
                        }


                        if (response.Success == true)
                        {
                            bool result;

                            if (restartInterfaces)
                            {
                                try
                                {
                                    result = WMIHelper.SetDisable(netIfaceInfo.Name);
                                }
                                catch (Exception ex)
                                {
                                    throw new FriendlyMessageException(string.Format("Error when setting disable nic '{0}'", nicName), ex);
                                }
                            }
                            else
                            {
                                result = true;
                            }

                            if (restartInterfaces)
                            {
                                if (result == true)
                                {
                                    try
                                    {
                                        result = WMIHelper.SetEnable(netIfaceInfo.Name);
                                    }
                                    catch (Exception ex)
                                    {
                                        throw new FriendlyMessageException(string.Format("Error when setting enable nic '{0}'", nicName), ex);
                                    }
                                }
                            }
                            else
                            {
                                result = true;
                            }

                            if (result == false)
                            {
                                response = new Response
                                {
                                    Success = false,
                                    //Message = "response_error_both_static_ip",
                                    Message = "Error: Both networks, Ethernet and Wi-Fi, can not be configured with static ip simultaneously.",
                                };
                            }
                        }


                        if (response.Success == true)
                        {
                            try
                            {
                                DateTime startDatetime = DateTime.Now;
                                TimeSpan timeout = new TimeSpan(0, 0, 30);

                                while (DateTime.Now - startDatetime < timeout)
                                {
                                    //Check if configuration has been applied correctly.
                                    netIfaceInfo = NetworkInterfaceInfo.GetNetworkInterfaceInfo(nicName);

                                    if (netIfaceInfo == null)
                                        Thread.Sleep(100);
                                    else
                                        break;
                                }


                                if (netIfaceInfo != null)
                                {
                                    bool changesApplied = false;

                                    if (netIfaceInfo.DhcpEnabled == dhcpEnabled)
                                    {
                                        if (netIfaceInfo.DhcpEnabled == false)
                                        {
                                            if ((netIfaceInfo.DefaultGateway.Equals(default_gateway, StringComparison.OrdinalIgnoreCase) == true)
                                                && (netIfaceInfo.Ip4Address.Equals(ip_address, StringComparison.OrdinalIgnoreCase) == true)
                                                && (netIfaceInfo.Subnetmask.Equals(subnet_mask, StringComparison.OrdinalIgnoreCase) == true)
                                                && ((netIfaceInfo.PreferredDns.Equals(preferred_dns, StringComparison.OrdinalIgnoreCase) == true)
                                                    || ((netIfaceInfo.IsDnsServerAutomatic == true) && (string.IsNullOrWhiteSpace(preferred_dns) == true))))
                                            {
                                                changesApplied = true;
                                            }
                                        }
                                        else
                                        {
                                            if ((netIfaceInfo.IsDnsServerAutomatic == isDnsServerAutomatic)
                                                && ((isDnsServerAutomatic == true)
                                                    || (netIfaceInfo.PreferredDns.Equals(preferred_dns, StringComparison.OrdinalIgnoreCase) == true)))
                                            {
                                                changesApplied = true;
                                            }
                                        }
                                    }


                                    if (changesApplied == false)
                                    {
                                        response = new Response
                                        {
                                            Success = false,
                                            //Message = "response_error_change_not_apply",
                                            Message = "Error: Changes has not been applied.",
                                        };
                                    }
                                }
                                else
                                {
                                    response = new Response
                                    {
                                        Success = false,
                                        //Message = "response_error_change_not_apply",
                                        Message = string.Format("Error when getting info of nic '{0}' after be disabled/enabled.", nicName),
                                    };
                                }
                            }
                            catch (Exception ex)
                            {
                                throw new FriendlyMessageException(string.Format("Error when checking if changes on nic '{0}' has been applied or not.", nicName), ex);
                            }
                        }

                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception(
                (ex is FriendlyMessageException)
                    ? ex.Message
                    : string.Format("Error when configuring nic '{0}'.", networkConfig.Name),
                ex
            );
        }

        return response;
    }
    public static Response ConnectToAccessPoint(string name, string username = null, string password = null, string domain = null)
    {
        return IhBoxSystemtConfiguration.ConnectToAccessPoint(name, false, username, password, domain);
    }
    private static Response ConnectToAccessPoint(string name, bool forced, string username = null, string password = null, string domain = null)
    {
        Response response = new Response();

        logger.Debug(string.Format("Connecting to WiFi Access Point {0} ...", name));
        if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
        {
            //Wifi wifi = new Wifi();
            logger.Debug("Searching for access point ...");
            List<AccessPoint> accessPoints = wifi.GetAccessPoints().OrderByDescending(ap => ap.SignalStrength).ToList();
            AccessPoint selectedAP = accessPoints.FirstOrDefault(a => a.Name == name);

            if (selectedAP != null)
            {
                logger.Debug("Selected AP: " + selectedAP.ToString());
            }
            else { logger.Debug("Selected AP not found."); }

            int retries = 0;
            while (selectedAP == null && retries < 5)
            {
                Thread.Sleep(1000);
                logger.Debug(string.Format("Retrying searching access point Retry [{0}] ...", retries));
                accessPoints = wifi.GetAccessPoints().OrderByDescending(ap => ap.SignalStrength).ToList();
                selectedAP = accessPoints.FirstOrDefault(a => a.Name == name);

                if (selectedAP != null)
                {
                    logger.Debug("Selected AP: " + selectedAP.ToString());
                }
                else { logger.Debug("Selected AP not found."); }

                retries++;
            }

            if (selectedAP != null)
            {
                logger.Debug("Access point found. Trying to connect to access point ...");
                //Auth
                AuthRequest authRequest = new AuthRequest(selectedAP);

                if (authRequest.IsPasswordRequired) authRequest.Password = password;
                if (authRequest.IsUsernameRequired) authRequest.Username = username;
                if (authRequest.IsDomainSupported) authRequest.Domain = domain;

                //logger.Debug(string.Format("Current wifi profile:\n{0}", selectedAP.GetProfileXML()));
                //logger.Debug(string.Format("New wifi profile:\n{0}", ProfileFactory.Generate(selectedAP.Network, password)));

                //selectedAP.ConnectAsync(authRequest, true, OnConnectedComplete); 
                logger.Debug("Connecting to access point...");
                bool connected = selectedAP.Connect(authRequest, true);
                logger.Debug("Access Point Connection Status: " + connected.ToString());

                if (connected == false)
                {
                    response = new Response
                    {
                        Success = false,
                        Message = "Can not connecto to wifi network. Please check credentials."
                    };
                }
            }
            else
            {
                logger.Debug("Access point was not found.");
                response = new Response
                {
                    Success = false,
                    Message = string.Format("SSID '{0}' does not exist.", name),
                };
            }
        }

        response.Data = IhBoxSystemtConfiguration.GetNetworkStatus(NETWORK_TYPE_WIFI);

        return response;
    }
    public static Response DisconnectWifi()
    {
        return IhBoxSystemtConfiguration.DisconnectWifi(false);
    }
    public static Response DeleteAllWifiProfiles()
    {
        Response response = new Response() { Success = true };
        logger.Debug("Deleting all Wifi profiles ...");
        try
        {
            //wifi.DeleteAllProfiles(new string[] { "DUMMY" });

            ProcessStartInfo startInfo = new ProcessStartInfo(@"cmd.exe", "/C netsh wlan delete profile name=* i=*");
            Process.Start(startInfo);

            logger.Debug("Wifi profiles deleted.");
        }
        catch (Exception ex)
        {
            logger.Error(ex.Message, ex);
            response = new Response() { Success = false };
        }

        return response;
    }
    private static Response DisconnectWifi(bool forced)
    {
        Response response;
        logger.Debug("Disconnecting from Wifi network ...");
        if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
        {
            logger.Debug("Calling wifi disconnect method...");
            wifi.Disconnect();

            response = new Response
            {
                Data = IhBoxSystemtConfiguration.GetNetworkStatus(NETWORK_TYPE_WIFI),
            };
        }
        else
        {
            logger.Debug("The system is already being configured and the force value was not true.");
            response = new Response();
        }

        return response;
    }
    public static object GetNetworkStatus(string networkType)
    {
        return IhBoxSystemtConfiguration.GetNetworkStatus(networkType, false);
    }
    private static object GetNetworkStatus(string networkType, bool forced)
    {
        //logger.Debug("Getting network status for network card NIC: " + nicName); 
        if (string.IsNullOrWhiteSpace(networkType) == false)
        {
            if (networkType.Equals(NETWORK_TYPE_ETHERNET, StringComparison.OrdinalIgnoreCase) == true)
                return IhBoxSystemtConfiguration.GetNetworkStatusEthernet();
            else if (networkType.Equals(NETWORK_TYPE_WIFI, StringComparison.OrdinalIgnoreCase) == true)
                return IhBoxSystemtConfiguration.GetNetworkStatusWifi(forced);
        }

        return null;
    }
    private static object GetNetworkStatusEthernet()
    {
        return new
        {
            Status = IhBoxSystemtConfiguration.GetNetworkStatusEthernetProperty(),
        };
    }
    private static string GetNetworkStatusEthernetProperty()
    {
        NetworkInterface nicIface = NetworkInterfaceInfo.GetNetworkInterface(NETWORK_ETHERNET_NIC_NAME, null, NetworkInterfaceType.Ethernet);
        return (nicIface != null)
                    ? nicIface.OperationalStatus.ToString()
                    : "";
    }
    public static object GetNetworkStatusWifi()
    {
        return IhBoxSystemtConfiguration.GetNetworkStatusWifi(false);
    }
    private static object GetNetworkStatusWifi(bool forced)
    {
        //logger.Debug("Getting access points..."); 
        if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
        {
            List<string> SSIDs = new List<string>();
            List<AccessPoint> accessPoints = new List<AccessPoint>();
            string current_ssid = null;
            string interfaceState = null;

            if (!wifi.NoWifiAvailable)
            {
                accessPoints =
                    wifi.GetAccessPoints()
                        .OrderByDescending(ap => ap.SignalStrength)
                        .ToList();

                SSIDs = accessPoints.Select(t => t.Name).ToList();

                //logger.Debug("Getting SSIDs, listing: ");
                //SSIDs.ForEach(ssid => logger.Debug("SSID found: " + ssid.ToString())); 

                if (wifi.ConnectionStatus == WifiStatus.Connected)
                {
                    //logger.Debug("Wifi is currently connected, finding current SSID"); 
                    AccessPoint current = accessPoints.FirstOrDefault(t => t.IsConnected == true);

                    if (current != null)
                    {
                        //logger.Debug("Current SSID connected: " + current.Name); 
                        current_ssid = current.Name;
                    }
                    else
                    {
                        //logger.Debug("Current SSID was not found, disconnecting from wifi ..."); 
                        wifi.Disconnect();
                    }
                }

                WlanClient client = new WlanClient();
                if (client.Interfaces != null)
                {
                    WlanInterface wlanIface = client.Interfaces.FirstOrDefault(i => i.InterfaceState != WlanInterfaceState.NotReady);
                    if (wlanIface != null) interfaceState = wlanIface.InterfaceState.ToString();
                }
            }

            return new
            {
                Status = (current_ssid != null) ? IhBoxSystemtConfiguration.GetNetworkStatusWifiProperty() : "Disconnected",
                InterfaceState = interfaceState,
                CurrentSSID = current_ssid,
                SSIDs = accessPoints.Select(item =>
                {
                    return new
                    {
                        Name = item.Name
                    };
                }),
            };
        }
        else
        {
            return new
            {
                Status = "Configuring",
                InterfaceState = "Configuring",
                CurrentSSID = IhBoxSystemtConfiguration.tempWifiConfig.SSID,
                SSIDs = new List<string>() { IhBoxSystemtConfiguration.tempWifiConfig.SSID },
            };
        }
    }
    private static string GetNetworkStatusWifiProperty()
    {
        return wifi.ConnectionStatus.ToString();
    }
    public static NetworkInterfaceInfo GetNetworkConfiguration(string nicName)
    {
        return IhBoxSystemtConfiguration.GetNetworkConfiguration(nicName, false);
    }
    private static NetworkInterfaceInfo GetNetworkConfiguration(string nicName, bool forced)
    {
        NetworkInterfaceInfo netIntInfo = null;

        if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring) || (forced == true))
        {
            netIntInfo = NetworkInterfaceInfo.GetNetworkInterfaceInfo(nicName);
        }
        else
        {
            if (nicName.Equals(NETWORK_ETHERNET_NIC_NAME, StringComparison.OrdinalIgnoreCase) == true)
                netIntInfo = IhBoxSystemtConfiguration.tempEthernetConfig;
            else if (nicName.Equals(NETWORK_WIFI_NIC_NAME, StringComparison.OrdinalIgnoreCase) == true)
                netIntInfo = IhBoxSystemtConfiguration.tempWifiConfig;
        }

        return netIntInfo;
    }
    //public static List<object> GetSystemTimeZones()
    //{
    //    List<object> timeZones = new List<object>();
    //    int retryCountLeft = 3;

    //    //For some reason, sometimes the method TimeZoneInfo.GetSystemTimeZones returns null.
    //    //So try again a few times if that method returns before exit.
    //    while (retryCountLeft > 0)
    //    {
    //        var sysTimeZones = TimeZoneInfo.GetSystemTimeZones();

    //        if (sysTimeZones.Count > 0)
    //        {
    //            foreach (TimeZoneInfo sysTimeZone in sysTimeZones)
    //            {
    //                timeZones.Add(new
    //                {
    //                    Id = sysTimeZone.Id,
    //                    Name = sysTimeZone.DisplayName,
    //                });
    //            }
    //        }
    //        else
    //        {
    //            retryCountLeft--;

    //            Thread.Sleep(100);
    //        }
    //    }

    //    return timeZones;
    //}
    //public static Response RestartIhWindowsServices()
    //{
    //    List<ServiceController> servCtrlToStop = new List<ServiceController>();
    //    ServiceController[] allServCtrl = ServiceController.GetServices();
    //    bool servRestartFailed = false;

    //    foreach (ServiceController servCtrl in allServCtrl)
    //    {
    //        if (servCtrl.DisplayName.StartsWith("Industrial Historian", StringComparison.OrdinalIgnoreCase) == true)
    //            servCtrlToStop.Add(servCtrl);
    //    }


    //    servCtrlToStop.ForEach(servCtrl =>
    //    {
    //        try
    //        {
    //            if ((servCtrl.Status != ServiceControllerStatus.Stopped) && (servCtrl.Status != ServiceControllerStatus.StopPending))
    //                servCtrl.Stop();

    //            servCtrl.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 5));

    //            servCtrl.Start();

    //            servCtrl.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 5));
    //        }
    //        catch (Exception ex)
    //        {
    //            try
    //            {
    //                if ((servCtrl.Status != ServiceControllerStatus.Stopped) && (servCtrl.Status != ServiceControllerStatus.StopPending))
    //                    servCtrl.Stop();

    //                servCtrl.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 5));

    //                servCtrl.Start();

    //                servCtrl.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 5));
    //            }
    //            catch
    //            {
    //                servRestartFailed = true;
    //            }
    //        }
    //    });


    //    return new Response
    //    {
    //        Success = !servRestartFailed,
    //    };
    //}
    public static Response SetInitialConfiguration(
        NetworkInterfaceInfo ethernetConfig,
        WifiNetworkInterfaceInfo wifiConfig,
        SystemDatetimeConfiguration sysDatetimeConfig
    )
    {
        string methodName = MethodBase.GetCurrentMethod().Name;

        TransactionLogger tranLogger = new TransactionLogger(logger, methodName)
        {
            ParametersCollection = new Dictionary<string, object>
            {
                { "EthernetConfig", ethernetConfig },
                { "WifiConfig", wifiConfig },
                { "SysDatetimeConfig", sysDatetimeConfig },
            },
        };

        tranLogger.LogBegin();

        Response response = new Response();

        try
        {
            if ((IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configured)
                && (IhBoxSystemtConfiguration.InitialConfigurationStatus != SystemInitialConfigurationStatus.Configuring))
            {
                if (response.Success == true)
                {
                    string nicEthernetStatus = IhBoxSystemtConfiguration.GetNetworkStatusEthernetProperty();
                    string nicWifiStatus = IhBoxSystemtConfiguration.GetNetworkStatusWifiProperty();

                    if ((nicEthernetStatus.Equals("UP", StringComparison.OrdinalIgnoreCase) == false)
                        && (nicWifiStatus.Equals("CONNECTED", StringComparison.OrdinalIgnoreCase) == false))
                    {
                        response = new Response
                        {
                            Success = false,
                            //Message = "response_error_both_static_ip",
                            Message = "Error: Both networks, Ethernet and Wi-Fi, are disconnected.",
                        };
                    }
                }

                if (response.Success == true)
                {
                    if ((ethernetConfig.DhcpEnabled == false) && (wifiConfig.DhcpEnabled == false))
                    {
                        response = new Response
                        {
                            Success = false,
                            //Message = "response_error_both_static_ip",
                            Message = "Error: Both networks, Ethernet and Wi-Fi, can not be configured with static ip simultaneously.",
                        };
                    }
                }

                if (response.Success == true)
                    response = IhBoxSystemtConfiguration.ValidateNetworkInterfaceConfiguration(ethernetConfig);

                if (response.Success == true)
                    response = IhBoxSystemtConfiguration.ValidateNetworkInterfaceConfiguration(wifiConfig);

                if (response.Success == true)
                    response = IhBoxSystemtConfiguration.ValidateSystemDatetimeConfiguration(sysDatetimeConfig);

                //if (response.Success == true)
                //    response = IhBoxSystemtConfiguration.ValidateWifiConfiguration(wifiConfig);

                if (response.Success == true)
                {
                    Thread thread = new Thread(new ThreadStart(delegate()
                    {
                        #region Set Initial Configuration

                        TransactionLogger tranLoggerThread = new TransactionLogger(logger, methodName + "_Thread")
                        {
                            ParametersCollection = new Dictionary<string, object>
                            {
                                { "EthernetConfig", ethernetConfig },
                                { "WifiConfig", wifiConfig },
                                { "SysDatetimeConfig", sysDatetimeConfig },
                            },
                        };

                        tranLoggerThread.LogBegin();


                        Response responseThread = new Response();

                        bool serviceManageFailed = false;
                        List<ServiceController> servCtrlToStop = new List<ServiceController>();
                        TimeSpan serviceHandlingTimeout = new TimeSpan(0, 1, 0);

                        try
                        {
                            tranLoggerThread.Log("Setting system as 'Configuring' on db...");

                            IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.Configuring);

                            IhBoxSystemtConfiguration.tempEthernetConfig = ethernetConfig;
                            IhBoxSystemtConfiguration.tempWifiConfig = wifiConfig;
                            IhBoxSystemtConfiguration.tempSysDatetimeConfig = sysDatetimeConfig;


                            ///Delete OEE cube file if exists.
                            String internalPath = "app\\custom-screens\\modules\\oee\\oee-report\\cube-api\\";
                            String path = AppDomain.CurrentDomain.BaseDirectory + internalPath;
                            String cubeFullPath = path + "cube\\cube.cub";

                            if (File.Exists(cubeFullPath) == true)
                            {
                                logger.DebugFormat("Deleting cube file '{0}' to reset OEE to factory defaults.", cubeFullPath);

                                File.Delete(cubeFullPath);
                            }


                            ServiceController[] allServCtrl = ServiceController.GetServices();

                            //Get reference of all Industrial Historian windows services.
                            foreach (ServiceController servCtrl in allServCtrl)
                            {
                                if (servCtrl.DisplayName.StartsWith("Industrial Historian", StringComparison.OrdinalIgnoreCase) == true)
                                    servCtrlToStop.Add(servCtrl);
                            }

                            servCtrlToStop = servCtrlToStop
                                .OrderByDescending(servCtrl => servCtrl.DisplayName)
                                .ToList();

                            //Stop all IH windows services.
                            tranLoggerThread.Log("Stopping IH services...");

                            servCtrlToStop.ForEach(servCtrl =>
                            {
                                try
                                {
                                    logger.Debug(string.Format("IH service '{0}' status: {1}.", servCtrl.DisplayName, servCtrl.Status));

                                    if ((servCtrl.Status != ServiceControllerStatus.Stopped) && (servCtrl.Status != ServiceControllerStatus.StopPending))
                                    {
                                        logger.Debug(string.Format("Stopping IH service '{0}'.", servCtrl.DisplayName));

                                        servCtrl.Stop();

                                        servCtrl.WaitForStatus(ServiceControllerStatus.Stopped, serviceHandlingTimeout);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    serviceManageFailed = true;

                                    logger.Error(ex);
                                }
                            });


                            tranLoggerThread.Log(string.Format("Configuring nic '{0}'...", wifiConfig.Name));

                            responseThread = IhBoxSystemtConfiguration.ConfigureNetworkInterface(wifiConfig, true, false);

                            //if (responseThread.Success == true)
                            //{
                            //    tranLoggerThread.Log(string.Format("Connecting wifi to ssid '{0}'...", wifiConfig.SSID));

                            //    responseThread = IhBoxSystemtConfiguration.ConnectToAccessPoint(wifiConfig.SSID, true, null, wifiConfig.Password, null);
                            //}

                            if (responseThread.Success == true)
                            {
                                tranLoggerThread.Log(string.Format("Configuring nic '{0}'...", ethernetConfig.Name));

                                responseThread = IhBoxSystemtConfiguration.ConfigureNetworkInterface(ethernetConfig, true, false);
                            }

                            //if (prevConfResult.Success == true)
                            //{
                            //    tranLoggerThread.Log("Setting system as configured on db.");

                            //    prevConfResult = IhBoxSystemtConfiguration.SetSystemAsConfigured();
                            //}

                            if (responseThread.Success == true)
                            {
                                tranLoggerThread.Log(
                                    string.Format(
                                        "Setting system datetime (Datetime: '{0}', TimeZone: '{1}')...",
                                        sysDatetimeConfig.Datetime,
                                        sysDatetimeConfig.TimeZoneId
                                    )
                                );

                                responseThread = IhBoxSystemtConfiguration.ConfigureDatetime(sysDatetimeConfig, true);
                            }

                            //try
                            //{
                            //    tranLoggerThread.Log("Creating ad-hoc network for IHBOX for computer: " + Environment.MachineName + " ..."); 
                            //    ExecuteCommandOnServer(null, "netsh wlan set hostednetwork mode=allow ssid=" + Environment.MachineName + " key=historianbox");

                            //    NetworkInterface adhocni = NetworkInterfaceInfo.GetNetworkInterface(null, "Microsoft Hosted Network Virtual Adapter", NetworkInterfaceType.Wireless80211);
                            //    if (adhocni != null)
                            //    {
                            //        tranLoggerThread.Log("Found ad-hoc network interface, setting ip to 192.168.137.1");
                            //        WMIHelper.SetIP(adhocni.Id, "192.168.137.1", "255.255.255.0", "", "");
                            //        tranLoggerThread.Log("Setting ad-hoc network to enabled"); 
                            //        WMIHelper.SetEnable(adhocni.Name);
                            //    }

                            //    ExecuteCommandOnServer(null, "netsh wlan start hostednetwork");
                            //}
                            //catch (Exception ex)
                            //{
                            //    tranLoggerThread.Log("Error while creating ad-hoc network for IHBOX: " + ex.Message); 
                            //}

                            if (responseThread.Success == true)
                            {
                                tranLoggerThread.Log("Setting system as 'Configured' on db...");

                                IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.Configured);
                            }
                            else
                            {
                                tranLoggerThread.Log("Setting system as 'NotConfigured' on db...");

                                IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.NotConfigured);
                            }
                        }
                        catch (Exception ex)
                        {
                            tranLoggerThread.Log(ex);

                            tranLoggerThread.Log("Setting system as 'NotConfigured' on db...");

                            try
                            {
                                IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.NotConfigured);
                            }
                            catch (Exception ex2)
                            {
                                tranLoggerThread.Log(ex2);
                            }

                            responseThread = new Response
                            {
                                Success = false,
                                //Message = "response_error_current_oper_not_finish",
                                Message = ex.Message,
                            };
                        }
                        finally
                        {
                            //Start all IH windows services.
                            tranLoggerThread.Log("Starting IH services...");

                            servCtrlToStop.ForEach(servCtrl =>
                            {
                                try
                                {
                                    if (servCtrl.Status == ServiceControllerStatus.Stopped)
                                    {
                                        logger.Debug(string.Format("Starting IH service '{0}'.", servCtrl.DisplayName));
                                        servCtrl.Start();
                                        servCtrl.WaitForStatus(ServiceControllerStatus.Running, serviceHandlingTimeout);
                                    }
                                    else
                                    {
                                        logger.Debug(string.Format("IH Service '{0}' is not stopped. Current status: [{1}].", servCtrl.DisplayName, servCtrl.Status.ToString()));
                                    }
                                }
                                catch (Exception ex)
                                {
                                    serviceManageFailed = true;

                                    //if OEE Demo fails, then remove it and add it again.
                                    if (servCtrl.DisplayName.Contains("OEEAGENTLOCAL"))
                                    {
                                        try
                                        {
                                            logger.Debug("Removing OEE Demo ...");
                                            IhBoxSystemtConfiguration.RemoveOEEAgent(false);
                                        }
                                        catch (Exception ex1)
                                        {
                                            logger.Error("Error while removing OEE Demo.", ex1);
                                        }

                                        try
                                        {
                                            logger.Debug("Adding default OEE Demo");
                                            IhBoxSystemtConfiguration.AddOEEDemo();

                                            serviceManageFailed = false;
                                        }
                                        catch (Exception ex1)
                                        {
                                            logger.Error("Error while adding default OEE Demo.", ex1);
                                        }
                                    }

                                    tranLoggerThread.Log(ex);
                                }
                            });

                            if (serviceManageFailed)
                            {
                                logger.Debug("IH Services failed to start, restarting machine to allow automatic starting.");
                                RestartSystem();
                            }

                            IhBoxSystemtConfiguration.PreviousConfigurationResult = responseThread;

                            tranLoggerThread.LogEnd();
                        }

                        #endregion
                    }));
                    thread.Start();
                }
            }
            else
            {
                response = new Response
                {
                    Success = false,
                    //Message = "response_error_current_oper_not_finish",
                    Message = "Error: Previous operation did not finish.",
                };
            }

            tranLogger.LogEnd();
        }
        catch (Exception ex)
        {
            tranLogger.LogEnd(ex);

            response = new Response
            {
                Success = false,
                Message = ex.Message,
            };
        }

        return response;
    }
#if !NODB
    private static void SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus newStatus)
    {
        int i = 0;
        while (i < 5)
        {
            try
            {
                SqlConnection sqlCon = new SqlConnection();
                sqlCon.ConnectionString = IhBoxSystemtConfiguration.systemConnectionString;
                sqlCon.Open();
                SqlCommand comm = new SqlCommand("FrontEnd.SetSystemAsConfigured", sqlCon);
                comm.CommandType = CommandType.StoredProcedure;

                comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar)).Value = "admin";
                comm.Parameters.Add(new SqlParameter("@ConfigStatus", SqlDbType.Int)).Value = (int)newStatus;

                comm.ExecuteNonQuery();

                sqlCon.Close();
                sqlCon.Dispose();
                break;
            }
            catch (Exception ex)
            {
                i++;
                logger.Error(string.Format("SaveInitialConfigurationStatusToDatabase, retry [{0}]", i), ex);
            }
        }

        if (i == 5)
        {
            throw new Exception("Error when saving system config status to database.");
        }
    }
#else
    public static void SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus newStatus)
    {
        _initialConfigurationStatus = newStatus;
    }
#endif
    //private static Response SetSystemAsConfigured()
    //{
    //    SqlConnection sqlCon = new SqlConnection();
    //    sqlCon.ConnectionString = IhBoxSystemtConfiguration.systemConnectionString;
    //    sqlCon.Open();
    //    SqlCommand comm = new SqlCommand("FrontEnd.SetSystemAsConfigured", sqlCon);
    //    comm.CommandType = CommandType.StoredProcedure;

    //    SqlParameter sqlParam = new SqlParameter("@UserName", SqlDbType.VarChar);
    //    sqlParam.Value = "admin";
    //    comm.Parameters.Add(sqlParam);

    //    comm.ExecuteNonQuery();

    //    sqlCon.Close();

    //    return new Response();
    //}
    private static Response ValidateNetworkInterfaceConfiguration(NetworkInterfaceInfo nicConfig)
    {
        if (nicConfig.DhcpEnabled == false)
        {
            if (string.IsNullOrWhiteSpace(nicConfig.Ip4Address) == true)
            {
                return new Response
                {
                    Success = false,
                    Message = string.Format("Error: {0} ip address must be specified.", nicConfig.Name),
                };
            }

            if (string.IsNullOrWhiteSpace(nicConfig.Subnetmask) == true)
            {
                return new Response
                {
                    Success = false,
                    Message = string.Format("Error: {0} subnet mask must be specified.", nicConfig.Name),
                };
            }

            if (string.IsNullOrWhiteSpace(nicConfig.DefaultGateway) == true)
            {
                return new Response
                {
                    Success = false,
                    Message = string.Format("Error: {0} default gateway must be specified.", nicConfig.Name),
                };
            }
        }

        if ((nicConfig.IsDnsServerAutomatic == false) && (string.IsNullOrWhiteSpace(nicConfig.PreferredDns) == true))
        {
            return new Response
            {
                Success = false,
                Message = string.Format("Error: {0} preferred dns must be specified.", nicConfig.Name),
            };
        }

        return new Response();
    }
    private static Response ValidateSystemDatetimeConfiguration(SystemDatetimeConfiguration sysDatetimeConfig)
    {
        if (string.IsNullOrWhiteSpace(sysDatetimeConfig.Datetime) == true)
        {
            return new Response
            {
                Success = false,
                Message = "Error: System datetime must be specified.",
            };
        }

        if (Regex.IsMatch(sysDatetimeConfig.Datetime, @"([0-9]{1,2}[-\/]){2}([0-9]{4}|[0-9]{2})(\s.+)?") == false)
        {
            return new Response
            {
                Success = false,
                Message = "Error: System date must be specified.",
            };
        }

        if (Regex.IsMatch(sysDatetimeConfig.Datetime, @"(.+\s)?([0-9]{1,2}:){2}[0-9]{1,2}") == false)
        {
            return new Response
            {
                Success = false,
                Message = "Error: System time must be specified.",
            };
        }

        if (string.IsNullOrWhiteSpace(sysDatetimeConfig.TimeZoneId) == true)
        {
            return new Response
            {
                Success = false,
                Message = "System timezone must be specified.",
            };
        }

        return new Response();
    }
    public static Response SetSystemModeToResetToFactoryDefaults()
    {
        bool success = true;
        try
        {
            IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.ResetToFactoryDefaults);
        }
        catch (Exception ex) { success = false; }

        return new Response() { Success = success };
    }
    public static Response ResetToFactoryDefaults()
    {
        try
        {
            logger.Debug("Removing all existing Local PLCs ...");
            IhBoxSystemtConfiguration.RemoveAllLocalPLCs(false);

            try
            {
                logger.Debug("Removing OEE Demo ...");
                IhBoxSystemtConfiguration.RemoveOEEAgent(false);
            }
            catch (Exception ex)
            {
                logger.Error("Error while removing OEE Demo.", ex);
            }

            StopAllIHWindowsServices();

            ClearAllIHData();

            //logger.Debug("Adding default Local PLC PLCAGENTLOCAL"); 
            //IhBoxSystemtConfiguration.AddLocalPLC(name: null, defaultPLC: true);

            try
            {
                logger.Debug("Adding default OEE Demo");
                IhBoxSystemtConfiguration.AddOEEDemo();
            }
            catch (Exception ex)
            {
                logger.Error("Error while adding default OEE Demo.", ex);
            }

            logger.Debug("Deleting all wifi profiles...");
            DeleteAllWifiProfiles();

            logger.Debug("Resetting initial configuration status to NotConfigured ...");
            IhBoxSystemtConfiguration.SaveInitialConfigurationStatusToDatabase(SystemInitialConfigurationStatus.NotConfigured);
            logger.Debug("Reseted initial configuration status successfully.");
        }
        catch (Exception ex)
        {
            logger.Error("ResetToFactoryDefaults.", ex);
            RestartSystem();
        }

        return new Response();
    }
    public static void ResetNetworkCardsToAutomatic(bool restartInterfaces = true)
    {
        NetworkInterfaceInfo ethernetInterface = new NetworkInterfaceInfo()
        {
            Name = NETWORK_ETHERNET_NIC_NAME,
            DhcpEnabled = true,
            Enabled = true,
            IsDnsServerAutomatic = true,
        };

        NetworkInterfaceInfo wifiInterface = new NetworkInterfaceInfo()
        {
            Name = NETWORK_WIFI_NIC_NAME,
            DhcpEnabled = true,
            Enabled = true,
            IsDnsServerAutomatic = true,
        };

        logger.Debug("Setting ETHERNET interface to automatic ip and dns ...");
        ConfigureNetworkInterface(ethernetInterface, true, false, restartInterfaces);

        logger.Debug("Setting WIFI interface to automatic ip and dns ...");
        ConfigureNetworkInterface(wifiInterface, true, false, restartInterfaces);

        logger.Debug("WIFI and ETHERNET network cards reset to automatic.");
    }
    private static void ClearAllIHData()
    {
        try
        {
            bool success = false;
            int retryInterval = 1000;

            do
            {
                try
                {
                    logger.Debug("Executing SYSTEM.ClearAllData ...");

                    using (SqlConnection sqlCon = new SqlConnection())
                    {
                        sqlCon.ConnectionString = IhBoxSystemtConfiguration.systemConnectionString;

                        SqlCommand comm = new SqlCommand("SYSTEM.ClearAllData", sqlCon);
                        comm.CommandType = CommandType.StoredProcedure;

                        SqlParameter sqlParam = new SqlParameter("@AccountNumber", SqlDbType.Int);
                        sqlParam.Value = 100020;
                        comm.Parameters.Add(sqlParam);

                        logger.Debug("Calling secured procedure ...");
                        DataSet ds = DALSecurity.CallSecuredProcedure(sqlCon, comm);

                        success = true;

                        if (ds != null)
                        {
                            logger.Debug("DAL returned dataset.");
                        }
                        else
                        {
                            logger.Debug("Dataset returned is null.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (success == false)
                    {
                        logger.Error(string.Format("Error when executing clear all ih data procedure. Retry in {0} millisecond/s.", retryInterval), ex);

                        Thread.Sleep(retryInterval);
                    }
                    else
                    {
                        logger.Error("Error when executing clear all ih data procedure.", ex);
                    }
                }
            }
            while (success == false);
        }
        catch (Exception ex)
        {
            logger.Error("Error when clearing all ih data.", ex);
        }
    }
    private static Response StopAllIHWindowsServices()
    {
        logger.Debug("Stopping all IH Windows Services...");
        bool serviceManageFailed = false;
        List<ServiceController> servCtrlToStop = new List<ServiceController>();
        TimeSpan serviceHandlingTimeout = new TimeSpan(0, 1, 0);
        ServiceController[] allServCtrl = ServiceController.GetServices();

        //Get reference of all Industrial Historian windows services.
        foreach (ServiceController servCtrl in allServCtrl)
        {
            if (servCtrl.DisplayName.StartsWith("Industrial Historian", StringComparison.OrdinalIgnoreCase) == true)
                servCtrlToStop.Add(servCtrl);
        }

        servCtrlToStop = servCtrlToStop
            .OrderByDescending(servCtrl => servCtrl.DisplayName)
            .ToList();

        //Stop all IH windows services.
        logger.Debug("Stopping IH services...");

        servCtrlToStop.ForEach(servCtrl =>
        {
            try
            {
                logger.Debug(string.Format("IH service '{0}' status: {1}.", servCtrl.DisplayName, servCtrl.Status));

                if ((servCtrl.Status != ServiceControllerStatus.Stopped) && (servCtrl.Status != ServiceControllerStatus.StopPending))
                {
                    logger.Debug(string.Format("Stopping IH service '{0}'.", servCtrl.DisplayName));

                    servCtrl.Stop();

                    servCtrl.WaitForStatus(ServiceControllerStatus.Stopped, serviceHandlingTimeout);
                }
            }
            catch (Exception ex)
            {
                serviceManageFailed = true;

                logger.Error(ex);
            }
        });

        return new Response()
        {
            Success = !serviceManageFailed,
        };
    }
    public static Response SetSyncWithInternetTime(bool val)
    {
        Response response = new Response() { Success = true };
        string regValue = (val == true) ? "NTP" : "NoSync";

        try
        {
            Registry.SetValue(
                @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\W32Time\Parameters",
                "Type",
                regValue
            );
        }
        catch (Exception ex) { logger.Error(ex.Message, ex); response = new Response() { Success = false }; }

        return response;
    }
    public static void RestartSystem()
    {
        try
        {
            logger.Debug("Restarting system...");
            ProcessStartInfo startInfo = new ProcessStartInfo(@"C:\Windows\System32\shutdown.exe", "/r /f /t 2");
            Process.Start(startInfo);
        }
        catch (Exception ex)
        {
            logger.Error("RestartSystem.", ex);
        }
    }
    public static void AddLocalPLC(string name, string accountNumber = "100020", bool defaultPLC = false)
    {
        string localAgentsFolder = ConfigurationManager.AppSettings["IHLocalAgentsFolder"];
        string IHAgentsSourcesFolder = ConfigurationManager.AppSettings["IHAgentsSourcesFolder"];
        if (!String.IsNullOrEmpty(localAgentsFolder))
        {
            if (Directory.Exists(localAgentsFolder))
            {
                string[] dirs = Directory.GetDirectories(localAgentsFolder, "PLCAGENTLOCAL*");
                if (dirs.Count() < 10)
                {
                    string localName = "PLCAGENTLOCAL-" + name;
                    localName = (defaultPLC) ? "PLCAGENTLOCAL" : localName;

                    string plcFiles = "//PLCSiemensS7/install/program files/australtek/IHPLCSiemensAgent/";
                    string sourcePath = IHAgentsSourcesFolder + plcFiles;
                    string destPath = localAgentsFolder + localName + "/";
                    DirectoryCopy(sourcePath, destPath, true);

                    Dictionary<string, string> DefaultConfigurationValuesDictionary = DAL.GetDefaultConfigurationValuesForSetup(accountNumber);

                    EditXML(destPath, "IHPLCSiemensAgentService.exe.Config", localName, accountNumber, false, null);
                    ExecuteCommandOnServer(destPath, @"IHPLCSiemensAgentService.exe -i -n=" + localName);
                    ExecuteCommandOnServer(destPath, @"net start IHPLCSiemensAgent:" + localName);
                }
                else
                {
                    throw new Exception("MAXLOCALAGENTSREACHED");
                }
            }
            else
            {
                logger.Error("IHLocalAgentsFolder directory does not exists. Please check Web.config to make to set a correct path.");
            }
        }
    }

    public static void AddOEEDemo(string accountNumber = "100020")
    {
        string oeeDemoAgentFolder = ConfigurationManager.AppSettings["IHLocalAgentsFolder"];
        string oeeDemoSourcesFolder = ConfigurationManager.AppSettings["IHAgentsSourcesFolder"];
        if (!String.IsNullOrEmpty(oeeDemoAgentFolder))
        {
            if (Directory.Exists(oeeDemoAgentFolder))
            {
                List<string> oeeDemos = Directory.GetDirectories(oeeDemoSourcesFolder, "OEEDemoAgent*").ToList();

                int c = 0;
                foreach (string name in oeeDemos)
                {
                    string localName = "OEEAGENTLOCAL-OEEDEMO{0}";
                    localName = string.Format(localName, c.ToString());
                    logger.Debug(string.Format("Installing OEE Demo with local name [{0}] ...", localName));
                    try
                    {
                        if (Directory.Exists(oeeDemoAgentFolder + localName + "/"))
                        {
                            Directory.Delete(oeeDemoAgentFolder + localName + "/", true);
                        }

                        //string[] dirs = Directory.GetDirectories(oeeDemoAgentFolder, "OEEDEMO");

                        //if (dirs.Count() == 0)
                        //{
                        //string oeeDemoFiles = "//OEEDemoAgent/";
                        //string oeeDemoFiles = "//"+name+"/";
                        //string sourcePath = oeeDemoSourcesFolder + oeeDemoFiles;
                        string sourcePath = name;
                        string destPath = oeeDemoAgentFolder + localName + "/";

                        logger.Debug(string.Format("Copying source files from [{0}] ...", sourcePath));

                        DirectoryCopy(sourcePath, destPath, true);

                        Dictionary<string, string> DefaultConfigurationValuesDictionary = DAL.GetDefaultConfigurationValuesForSetup(accountNumber);

                        //For  local agents use the default local agent ih port, not the default ih server port.
                        string ihPort = DefaultConfigurationValuesDictionary["DefaultLocalAgentIHServerPort"];

                        EditXML(destPath, "IHOEESimulatorAgentService.exe.Config", localName, accountNumber, false, ihPort);
                        ExecuteCommandOnServer(destPath, @"IHOEESimulatorAgentService.exe -i -n=" + localName);
                        ExecuteCommandOnServer(destPath, @"net start IHOEESimulatorAgent:" + localName);
                        //}
                    }
                    catch (Exception ex)
                    {
                        logger.Error(string.Format("Error while installing OEE Demo with local name [{0}] ...", localName), ex);
                    }
                    c++;
                }
            }
            else
            {
                logger.Error("OEEDemoAgentFolder directory does not exists. Please check Web.config to make to set a correct path.");
            }
        }
    }

    public static void RemoveOEEAgent(bool doUnregister = true)
    {
        string localAgentsFolder = ConfigurationManager.AppSettings["IHLocalAgentsFolder"];
        if (!String.IsNullOrEmpty(localAgentsFolder))
        {
            List<string> oeeDemos = Directory.GetDirectories(localAgentsFolder, "OEEAGENTLOCAL*").ToList();

            int c = 0;
            foreach (string name in oeeDemos)
            {
                string localName = "OEEAGENTLOCAL-OEEDEMO{0}";
                localName = string.Format(localName, c.ToString());
                logger.Debug(string.Format("Uninstalling and deleting OEE Agent [{0}] ...", localName));

                try
                {
                    string destPath = localAgentsFolder + localName + "/";

                    DateTime start = DateTime.Now;
                    DateTime end = DateTime.Now;
                    ExecuteCommandOnServer(destPath, @"net stop IHOEESimulatorAgent:" + localName);
                    end = DateTime.Now;
                    logger.Debug("Time elapsed to stop OEE agent: " + (end - start).TotalSeconds);

                    if (doUnregister)
                    {
                        start = end;
                        ExecuteCommandOnServer(destPath, @"IHAgentUnregister.exe");
                        end = DateTime.Now;
                        logger.Debug("Time elapsed to unregister OEE agent: " + (end - start).TotalSeconds);
                    }

                    start = end;
                    ExecuteCommandOnServer(destPath, @"IHOEESimulatorAgentService.exe -u -n=" + localName);
                    end = DateTime.Now;
                    logger.Debug("Time elapsed to uninstall service OEE agent: " + (end - start).TotalSeconds);

                    if (Directory.Exists(destPath))
                    {
                        Directory.Delete(destPath, true);
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(string.Format("Error while uninstalling and deleting OEE Agent [{0}] ...", localName), ex);
                }

                c++;
            }
        }
    }

    public static void RemoveAllLocalPLCs(bool doUnregister = true)
    {
        string localAgentsFolder = ConfigurationManager.AppSettings["IHLocalAgentsFolder"];
        if (!String.IsNullOrEmpty(localAgentsFolder))
        {
            foreach (var dir in Directory.GetDirectories(localAgentsFolder))
            {
                DirectoryInfo dinfo = new DirectoryInfo(dir);
                if (dinfo.Name.Contains("PLCAGENTLOCAL"))
                {
                    bool isDefaultPLC = false;
                    if (dinfo.Name.Equals("PLCAGENTLOCAL")) isDefaultPLC = true;

                    try
                    {
                        RemoveLocalPLC(dinfo.Name.Replace("PLCAGENTLOCAL-", String.Empty).Replace("PLCAGENTLOCAL", String.Empty), isDefaultPLC, doUnregister);
                    }
                    catch (Exception ex)
                    {
                        logger.Error("Error while trying to remove Local PLC: " + dinfo.Name.ToString(), ex);
                    }
                }
            }
        }
    }

    public static void RemoveLocalPLC(string name, bool defaultPLC = false, bool doUnregister = true)
    {
        string localAgentsFolder = ConfigurationManager.AppSettings["IHLocalAgentsFolder"];
        if (!String.IsNullOrEmpty(localAgentsFolder))
        {
            string localName = "PLCAGENTLOCAL-" + name;
            localName = (defaultPLC) ? "PLCAGENTLOCAL" : localName;

            string destPath = localAgentsFolder + localName + "/";

            DateTime start = DateTime.Now;
            DateTime end = DateTime.Now;
            ExecuteCommandOnServer(destPath, @"net stop IHPLCSiemensAgent:" + localName);
            end = DateTime.Now;
            logger.Debug("Time elapsed to stop local agent: " + (end - start).TotalSeconds);

            if (doUnregister)
            {
                start = end;
                ExecuteCommandOnServer(destPath, @"IHAgentUnregister.exe");
                end = DateTime.Now;
                logger.Debug("Time elapsed to unregister: " + (end - start).TotalSeconds);
            }

            start = end;
            ExecuteCommandOnServer(destPath, @"IHPLCSiemensAgentService.exe -u -n=" + localName);
            end = DateTime.Now;
            logger.Debug("Time elapsed to uninstall service local agent: " + (end - start).TotalSeconds);

            if (Directory.Exists(destPath))
            {
                Directory.Delete(destPath, true);
            }
        }
    }

    private static bool ExecuteCommandOnServer(string workingDirectory, string oneLineCommand)
    {
        bool ret = false;
        try
        {
            // Create the ProcessInfo object
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo("cmd.exe");
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;

            if (workingDirectory != null)
                psi.WorkingDirectory = workingDirectory;

            // Start the process
            System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi);
            // Open the batch file for reading
            //System.IO.StreamReader strm = System.IO.File.OpenText(strFilePath);
            // Attach the output for reading
            System.IO.StreamReader sOut = proc.StandardOutput;
            // Attach the in for writing
            System.IO.StreamWriter sIn = proc.StandardInput;
            // Write each line of the batch file to standard input
            sIn.WriteLine(@oneLineCommand);
            //strm.Close();
            // Exit CMD.EXE
            sIn.WriteLine("EXIT");
            // Close the process
            proc.Close();
            // Read the sOut to a string.
            string results = sOut.ReadToEnd().Trim();
            // Close the io Streams;
            sIn.Close();
            sOut.Close();
            ret = true;
        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }

    private static bool EditXML(string basePath, string XMLConfigName, string name, string accountNumber, bool writeOPC, string ihPort = null)
    {
        bool ret = false;
        try
        {
            Dictionary<string, string> DefaultConfigurationValuesDictionary = DAL.GetDefaultConfigurationValuesForSetup(accountNumber);
            XDocument xdoc = XDocument.Load(basePath + XMLConfigName);

            foreach (XElement elem in xdoc.Descendants("Name"))
            {
                elem.Value = name;
            }
            foreach (XElement elem in xdoc.Descendants("IHServerHost"))
            {
                elem.Value = DefaultConfigurationValuesDictionary["DefaultIHServerHost"];
            }
            foreach (XElement elem in xdoc.Descendants("IHServerPort"))
            {
                elem.Value = (ihPort != null) ? ihPort : DefaultConfigurationValuesDictionary["DefaultIHServerPort"];
            }
            if (writeOPC)
            {
                foreach (XElement elem in xdoc.Descendants("Address"))
                {
                    elem.Value = DefaultConfigurationValuesDictionary["DefaultOPCServer"];
                }
            }

            foreach (XElement elem in xdoc.Descendants("Account"))
            {
                elem.Value = Convert.ToString(accountNumber);
            }

            xdoc.Save(basePath + XMLConfigName);
            ret = true;

        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }

    private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
    {
        // Get the subdirectories for the specified directory.
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);
        DirectoryInfo[] dirs = dir.GetDirectories();

        if (!dir.Exists)
        {
            throw new DirectoryNotFoundException(
                "Source directory does not exist or could not be found: "
                + sourceDirName);
        }

        if (Directory.Exists(destDirName))
        {
            throw new Exception("DIRECTORYALREADYEXISTS");
        }

        Directory.CreateDirectory(destDirName);

        // Get the files in the directory and copy them to the new location.
        FileInfo[] files = dir.GetFiles();
        foreach (FileInfo file in files)
        {
            string temppath = Path.Combine(destDirName, file.Name);
            file.CopyTo(temppath, true);
        }

        // If copying subdirectories, copy them and their contents to new location. 
        if (copySubDirs)
        {
            foreach (DirectoryInfo subdir in dirs)
            {
                string temppath = Path.Combine(destDirName, subdir.Name);
                DirectoryCopy(subdir.FullName, temppath, copySubDirs);
            }
        }
    }

    //private static Response ValidateWifiConfiguration(WifiNetworkInterfaceInfo wifiConfig)
    //{
    //    Response response;

    //    if (string.IsNullOrWhiteSpace(wifiConfig.SSID) == true)
    //    {
    //        response = new Response
    //        {
    //            Success = false,
    //            Message = "Wifi ssid must be specified.",
    //        };
    //    }
    //    else if (string.IsNullOrWhiteSpace(wifiConfig.Password) == true)
    //    {
    //        response = new Response
    //        {
    //            Success = false,
    //            Message = "Wifi password must be specified.",
    //        };
    //    }
    //    else
    //    {
    //        response = new Response();
    //    }

    //    return response;
    //}
}