using System;
using System.Threading;
using System.Net;
using System.Text;
using System.Net.Sockets;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware; //need for Utility class
using GHI.Premium.Net;

namespace WIFI
{
    public partial class Program
    {
        //Your choice...
        private static WiFiRS9110 wifi;
        private static bool useDebug = true;

        public static void Main()
        {
            wifi = new WiFiRS9110(SPI.SPI_module.SPI2, (Cpu.Pin)10, (Cpu.Pin)18, (Cpu.Pin)20);// FEZ Spider Socket 6

            if (!wifi.IsOpen)
                wifi.Open();

            wifi.NetworkInterface.EnableStaticIP("134.89.8.58", "255.255.254.0", "134.89.8.1");

            wifi.NetworkAddressChanged += new NetworkInterfaceExtension.NetworkAddressChangedEventHandler(wifi_NetworkAddressChanged);
            wifi.WirelessConnectivityChanged += new WiFiRS9110.WirelessConnectivityChangedEventHandler(wifi_WirelessConnectivityChanged);

            NetworkInterfaceExtension.AssignNetworkingStackTo(wifi);
            JoinNetwork();
        }

        // Your router SSID and PassKey neede to be set in here
        static void JoinNetwork()
        {
            try
            {
                // Your router SSID needed here
                WiFiNetworkInfo[] ScanResp = wifi.Scan("MBARI WiFi"); //< Needs to be changed to SSID you are looking for
                if (ScanResp != null && ScanResp.Length > 0)
                {
                    //Your passkey needed here
                    wifi.Join(ScanResp[0], ""); //< needs to be changed to your Key
                    if (useDebug) { Debug.Print("***Joined to MBARI WiFi..."); }
                }
                else
                {
                    if (useDebug) { Debug.Print("***MBARI WiFi was not found"); }
                }
            }
            catch (Exception e)
            {
                if (useDebug) { Debug.Print("!!! Exception : " + e.Message); }
            }
        }

        static void wifi_NetworkAddressChanged(object sender, EventArgs e)
        {
            Debug.Print("***Network Address Changed , IP Address : " + wifi.NetworkInterface.IPAddress);
            // NTPTime("time.windows.com", (-(60 * 7)));
            // if (useDebug) { Debug.Print("### Time Server : " + DateTime.Now.ToString()); }
            RunServer();
        }

        static void wifi_WirelessConnectivityChanged(object sender, WiFiRS9110.WirelessConnectivityEventArgs e)
        {
            if (useDebug)
            {
                Debug.Print("***Wireless Connectivity Changed");
                Debug.Print("***RSSI : " + e.NetworkInformation.RSSI.ToString());
                Debug.Print("***IP Address : " + wifi.NetworkInterface.IPAddress);
            }

            if (e.IsConnected)
            {
                // Add the time zone offset to the retrieved UTC Time
                // (in this example, it assumes that the time zone is GMT-6).
                // You will need to adjust TimeService.SetTimeZoneOffset value for your time zone

                //UTC -6 hours for Central Standard Time. Use -(60 * 5) for Daylight savings time.
                //You will need to change NTPTime to your Time Zone
            }
        }

        public static bool NTPTime(string TimeServer, int GmtOffset = 0)
        {
            Socket s = null;
            try
            {
                EndPoint rep = new IPEndPoint(Dns.GetHostEntry(TimeServer).AddressList[0], 123);
                s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                byte[] ntpData = new byte[48];
                Array.Clear(ntpData, 0, 48);
                ntpData[0] = 0x1B; // Set protocol version
                s.SendTo(ntpData, rep); // Send Request   
                if (s.Poll(30 * 1000 * 1000, SelectMode.SelectRead)) // Waiting an answer for 30s, if nothing: timeout
                {
                    s.ReceiveFrom(ntpData, ref rep); // Receive Time
                    byte offsetTransmitTime = 40;
                    ulong intpart = 0;
                    ulong fractpart = 0;
                    for (int i = 0; i <= 3; i++) intpart = (intpart << 8) | ntpData[offsetTransmitTime + i];
                    for (int i = 4; i <= 7; i++) fractpart = (fractpart << 8) | ntpData[offsetTransmitTime + i];
                    ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);
                    s.Close();
                    DateTime dateTime = new DateTime(1900, 1, 1) +
                                        TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);
                    Utility.SetLocalTime(dateTime.AddMinutes(GmtOffset));
                    return true;
                }
                s.Close();
            }
            catch
            {
                try
                {
                    s.Close();
                }
                catch
                {
                }
            }
            return false;
        }

        private static void RunServer()
        {
            // Initiates a new shell on port 23
            WIFI.ShellCore Shell = new WIFI.ShellCore(new IntegratedSocket("", 23));
            // When disconnected, we want to start listening again
            Shell.OnDisconnected += new WIFI.ShellCore.ConnectionStateChange(Shell_OnDisconnected);

            // Lets bind to the authorization provider (optional, but useful ;-))
            WIFI.Auth LoginModule = new WIFI.Auth(Shell);
            LoginModule.OnAuthorize += new WIFI.Auth.IsAuthorized(Auth_OnAuthorize);

            // Lets bind some more apps
            WIFI.ShellCommands.Bind(Shell); // Some basic shell commands like MOTD, CLS, etc.

            // We start the shell
            Shell.Start();
        }

        // Triggered when the connection has been lost
        static void Shell_OnDisconnected(WIFI.ShellCore Shell, string RemoteAddress, DateTime Time)
        {
            Thread.Sleep(1000);
            // Starts to listen again
            Shell.Start();
        }

        // Asks if a user is authorized
        static bool Auth_OnAuthorize(WIFI.ShellCore Shell, string Username, string Password, string RemoteAddress)
        {
            if (Username == "gene" && Password == "LeGrandFromage")
                return true;
            if (Username == "wayne" && Password == "WorkerBee")
                return true;

            Shell.TelnetServer.Print("Answer correctly or be assimilated! :-)");
            return false;
        }

    }
}