using Helpers.Log;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Web.UI;
using System.Linq;
using System.Net.NetworkInformation;
using System.Management; 

public partial class app_Configuration_DashWifiConfiguration : Page
{
    private ILog logger = Logger.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);

    /// <summary>
    /// I use two classes DashWifiConfig and DashWifiFile, because I allow that the submit data don't match with the
    /// expected one, while you use a dictionary everything will go right.
    /// </summary>
    private String PathWifi = "";
    private class DashWifiConfig
    {
        public Dictionary<String,Object> Values { get; set; }
    }
    private class DashWifiFile
    {
        public Int32 AgentID { get; set; }
        public String Ssid { get; set; }
        public Int32 NetworkType { get; set; }
        public Int32 IpAddressMode { get; set; }
        public Int32 IpProtocol { get; set; }
        public Int32 TcpTimeout { get; set; }
        public Int32 EncryptionEnable { get; set; }
        public String SecurityKey { get; set; }
        public String ServerHostName {get;set;}
        public String AccountNumber { get; set; }
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
        TransactionLogger tranLog = new TransactionLogger(logger, MethodBase.GetCurrentMethod().Name);
        tranLog.Log("Generating wifi.dat file");        
        try
        {         
            System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();            
            System.IO.StreamReader sr = new System.IO.StreamReader(Page.Request.InputStream);
            String str = System.Web.HttpUtility.UrlDecode(sr.ReadToEnd().Split('=')[1]);
            tranLog.Log("     - Deserializing Config.");
            DashWifiConfig dwc = jss.Deserialize<DashWifiConfig>(str);
            tranLog.Log("     - Deserialized Complete.");
            Byte[] buffer = SaveDefaultWifiConfig(dwc.Values);
            tranLog.Log("     - Generating Buffer.");           
            Response.Clear();
            Response.Buffer = true;
            tranLog.Log("     - Adding Headers.");
            //Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", Path.GetFileName(PathWifi)));
            Response.AddHeader("content-disposition", String.Format("attachment;filename=\"wifi.dat\"", Path.GetFileName(PathWifi)));
            tranLog.Log("     - Adding ContentType.");
            Response.ContentType = "application/" + Path.GetExtension(PathWifi).Substring(1);
            tranLog.Log("     - Writting Buffer.");
            Response.BinaryWrite(buffer);
            Response.Flush();           
        }
        catch (Exception ex)
        {
            tranLog.Log("     - Failed. " + ex.Message);
            tranLog.Log(ex, "     - Failed. ");
            Response.Write(ex.Message.ToString());           
        }
        Response.Close();
        Response.End();
    }
    
    private Byte[] SaveDefaultWifiConfig(Dictionary<String, Object> dwc)
    {
        TransactionLogger tranLog = new TransactionLogger(logger, MethodBase.GetCurrentMethod().Name);              
        FileStream fs=null;
        Byte[] buf=null;
        try
        {           
            //StreamWriter sw;                       
            DashWifiFile wc = new DashWifiFile();
            wc.AgentID =  Convert.ToInt32(dwc["AGENTID"]);
            wc.AccountNumber = Convert.ToString(dwc["ACCOUNTNUMBER"]);
            wc.Ssid = Convert.ToString(dwc["SSID"]);
            wc.NetworkType = Convert.ToInt32(dwc["NETWORKTYPE"]);
            wc.IpProtocol = Convert.ToInt32(dwc["IPPROTOCOLMODE"]);
            wc.IpAddressMode = Convert.ToInt32(dwc["IPADDRESSMODE"]);
            wc.TcpTimeout = Convert.ToInt32(dwc["TCPTIMEOUT"]);
            wc.EncryptionEnable = Convert.ToInt32(dwc["ENCRYPTIONTYPE"]);
            wc.SecurityKey = Convert.ToString(dwc["SECURITYKEY"]);
            wc.ServerHostName = Convert.ToString(dwc["SERVERHOSTNAME"]);
            tranLog.Log("     - Reading Strem Options.");
            PathWifi = Path.GetTempPath() + "\\wifi" + wc.AccountNumber.Trim() + ".dat";
            
            tranLog.Log("     - Temp File:" + PathWifi);
            
            //Resolve HostName
            IPAddress found = null;
            String IpAddressServer = "";
            
            ////CODE TO USE WITH CLOUD INSTALLATIONS OF IHBOX, this code uses the serverhostname to find the correspondent
            ////public IP address.
            //IPAddress[] addresslist = Dns.GetHostAddresses(wc.ServerHostName);
            //foreach (IPAddress ip in addresslist)
            //{
            //    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork &&
            //        !ip.IsIPv6LinkLocal && !ip.IsIPv6Multicast && !ip.IsIPv6SiteLocal && !ip.IsIPv6Teredo)
            //    {
            //        found = ip;
            //        break; 
            //    }
            //}

            ////CODE REBUMPED TO BE USED ON LOCAL INSTALLATIONS OF IHBOX, the ipaddress is being looked up using the
            ///local wifi network card.
            ///

            //foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
            //{
            //    logger.Debug("network interface: " + ni.Name); 
            //}

            //foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces().Where(ni => ni.NetworkInterfaceType == System.Net.NetworkInformation.NetworkInterfaceType.Wireless80211))
            //{
            //    logger.Debug("network interface wi fi name: " + ni.Name);
            //    logger.Debug("network interface wi fi Description: " + ni.Description);
            //    logger.Debug("network interface wi fi IsReceiveOnly: " + ni.IsReceiveOnly);
            //    logger.Debug("network interface wi fi NetworkInterfaceType: " + ni.NetworkInterfaceType);
            //    logger.Debug("network interface wi fi OperationalStatus: " + ni.OperationalStatus);
            //    logger.Debug("network interface wi fi Speed: " + ni.Speed);
            //    logger.Debug("network interface wi fi GetPhysicalAddress: " + ni.GetPhysicalAddress().ToString());
            //    logger.Debug("network interface wi fi SupportsMulticast: " + ni.SupportsMulticast)                
            //}

            List<string> nicIds = new List<string>(); 
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapter");
            ManagementObjectCollection moc = mc.GetInstances();

            tranLog.Log("Searching for network adapters with PNPDeviceId starting with PCI..."); 
            foreach (ManagementObject mo in moc)
            {
                string pnpDeviceId = (string)mo["PNPDeviceId"];

                if ((string.IsNullOrWhiteSpace(pnpDeviceId) == false) && (pnpDeviceId.StartsWith("PCI") == true))
                {
                    nicIds.Add((string)mo["GUID"]);
                }
            }

            tranLog.Log("Searching for Wi-Fi network interface ..."); 
            
            //NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(
            //    ni => ni.NetworkInterfaceType == System.Net.NetworkInformation.NetworkInterfaceType.Wireless80211 && nicIds.Contains(ni.Id)
            //);

            List<NetworkInterface> networkInterfaces = NetworkInterface.GetAllNetworkInterfaces().Where(
                ni => nicIds.Contains(ni.Id)
            ).ToList();

            foreach (NetworkInterface ni in networkInterfaces)
            {
                foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
                {
                    IPAddress ipaddress = ip.Address;
                    if (ipaddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork &&
                        !ipaddress.IsIPv6LinkLocal && !ipaddress.IsIPv6Multicast && !ipaddress.IsIPv6SiteLocal && !ipaddress.IsIPv6Teredo)
                    {
                        tranLog.Log("NetworkInterface: " + ni.Name.ToString() + " || IP Address: " + ipaddress.ToString());
                        if (!ipaddress.ToString().StartsWith("169"))
                        {
                            found = ipaddress;
                            break; 
                        }
                    }
                }
            }

            //if (networkInterface != null)
            //{
            //    tranLog.Log("Network Interface Wireless and Speed > 0 found [Name: " + networkInterface.Name + "].");
            //    tranLog.Log("Searching for IP Address...");
            //    foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
            //    {
            //        IPAddress ipaddress = ip.Address;
            //        if (ipaddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork &&
            //            !ipaddress.IsIPv6LinkLocal && !ipaddress.IsIPv6Multicast && !ipaddress.IsIPv6SiteLocal && !ipaddress.IsIPv6Teredo)
            //        {
            //            found = ipaddress;
            //            break; 
            //        }
            //    }
            //}
            //else
            //{
            //    tranLog.Log("Wireless Network Interface was not found that satisfies conditions Speed > 0"); 
            //}

            if (found != null)
            {
                tranLog.Log("IPAddress found: " + ((IPAddress)found).ToString());
                IpAddressServer = ((IPAddress)found).ToString();
            }
            else
            {
                IPAddress ipaddr = null;
                IPAddress.TryParse(wc.ServerHostName, out ipaddr);
                if (ipaddr != null) IpAddressServer = (ipaddr).ToString(); 
            }

            tranLog.Log("     - Resolve HostName: " + IpAddressServer);                     
            // Delete the file if it exists.             
            if (File.Exists(PathWifi))
            {
                tranLog.Log("     - Deleting Wifi.Dat File.");
                File.Delete(PathWifi);
            }
            tranLog.Log("     - Writting Wifi.Dat File.");
            using (fs = File.Open(PathWifi, FileMode.Create, FileAccess.Write, FileShare.None))
            {                
                Write(fs, IpAddressServer);
                Write(fs, wc.Ssid);
                Write(fs, wc.NetworkType);
                Write(fs, wc.IpProtocol);
                Write(fs, wc.IpAddressMode);
                Write(fs, wc.TcpTimeout);
                Write(fs, wc.EncryptionEnable);
                if (wc.EncryptionEnable != 0)
                {
                    Write(fs, wc.SecurityKey);
                }               
            }            
            tranLog.Log("     - Reading Wifi.Dat File.");
            using (fs = File.OpenRead(PathWifi))
            {
                int length = (int)fs.Length;
                using (BinaryReader br = new BinaryReader(fs))
                {
                    buf = br.ReadBytes(length);
                }
            }
        }
        catch (Exception ex)
        {
            tranLog.Log("     - Failed. " + ex.Message);
            tranLog.Log(ex, "     - Failed. ");
            Debug.Print(ex.Message);            
        }      
        return buf;
    }


    /// <summary>
    /// Writes a long to the config file at current position
    /// </summary>
    /// <param name="value"></param>
    private void Write(FileStream file, long value)
    {
        byte[] buf = BitConverter.GetBytes(value);
        file.Write(buf, 0, buf.Length);
    }

    /// <summary>
    /// Writes an int to the config file at current position
    /// </summary>
    /// <param name="value"></param>
    private void Write(FileStream file, int value)
    {
        byte[] buf = BitConverter.GetBytes(value);
        file.Write(buf, 0, buf.Length);
    }

    /// <summary>
    /// Writes a string to the config file at current position
    /// </summary>
    /// <param name="value">String to write</param>
    /// <exception cref="System.IO.IOException"></exception>
    private void Write(FileStream file, string value)
    {
        Write(file, value.Length);
        file.Write(System.Text.UTF8Encoding.UTF8.GetBytes(value), 0, value.Length);
    }

    /// <summary>
    /// Writes a string to the config file at current position
    /// </summary>
    /// <param name="value">String to write</param>
    /// <exception cref="System.IO.IOException"></exception>
    private void Write(FileStream file, bool value)
    {
        file.Write(value == true ? new[] { (byte)1 } : new[] { (byte)0 }, 0, 1);
    }
}