using System;
using System.Threading;
using Microsoft.SPOT;

namespace WIFI
{
    public class ShellCore
    {
        // Reference to the TelnetServer object
        public TelnetServer TelnetServer { get; protected set; }

        // Command line prompt prefix
        public string Prompt { get; set; }

        // The last enterred command line
        public string LastCommandline { get; protected set; }

        // When running in the background, this thread is used
        private Thread _BgThread;

        // Initializes a new Shell core
        public ShellCore(SimpleSocket Socket)
        {
            this.TelnetServer = new TelnetServer(Socket);
            this.Prompt = ">";
        }

        // Starts listening
        public void Start() 
        { 
            this.Start(false); 
        }

        // Starts listening
        public void Start(bool Background)
        {
            if (Background)
            {
                // Creates a background thread
                ThreadStart BgThread = new ThreadStart(this.Start);
                this._BgThread = new Thread(BgThread);
                this._BgThread.Start();
                return;
            }

            this.TelnetServer.Listen();
            if (this.OnConnected != null) 
                this.OnConnected(this, this.TelnetServer.RemoteAddress, DateTime.Now);

            while (this.TelnetServer.IsConnected)
            {
                this.TelnetServer.Color(TelnetServer.Colors.Yellow);
                this.TelnetServer.Print(this.Prompt + " ", true);
                this.TelnetServer.Color(TelnetServer.Colors.White);
                string Command = this.TelnetServer.Input();
                if (Command != "") this._ExecuteCommand(Command);
            }

            if (this.OnDisconnected != null) 
                this.OnDisconnected(this, this.TelnetServer.RemoteAddress, DateTime.Now);
        }

        // Executes a command
        private void _ExecuteCommand(string CommandLine)
        {
            this.LastCommandline = CommandLine;
            if (this.OnCommandReceived != null)
            {
                // Splits up the command line in arguments
                string[] Arguments = CommandLine.Split(new char[] { ' ' });
                // By default, we don't suspress the error "Command unknown"
                bool SuspressError = false;
                // Tries to execute the command
                try
                {
                    this.OnCommandReceived(this, Arguments, ref SuspressError, DateTime.Now);
                }
                // If we fail executing the command, an error message will show up
                catch (Exception Error)
                {
                    this._PrintError("An exception has been triggered: " + Error.Message);
                    SuspressError = true;
                }
                // If SuspressError hasn't been set to True, we show the error "Command unknown"
                if (!SuspressError)
                    this._PrintError("Command " + Arguments[0].ToUpper() + " unknown");
            }
        }

        // Prints out an error
        private void _PrintError(string Text)
        {
            this.TelnetServer.Color(TelnetServer.Colors.LightRed);
            this.TelnetServer.Print(Text);
            this.TelnetServer.Color(TelnetServer.Colors.White);
        }

        // Triggered when a command has been given
        public event CommandReceived OnCommandReceived;

        // Triggered when a command has been given
        public delegate void CommandReceived(ShellCore Shell, string[] Arguments, ref bool SuspressError, DateTime Time);

        // Triggered when the connection has been made
        public event ConnectionStateChange OnConnected;

        // Triggered when the connection has been lost
        public event ConnectionStateChange OnDisconnected;

        // Triggered when the connection state changes
        public delegate void ConnectionStateChange(ShellCore Shell, string RemoteAddress, DateTime Time);
    }
}
