﻿using System;
using System.Configuration;
using System.Threading;
using WorldBankBBS.Common;
using WorldBankBBS.Comms;
using WorldBankBBS.Logic;
using WorldBankBBS.Translators;

namespace WorldBankBBS.Input
{
    public class InputHandler
    {
        public event EventHandler<byte[]> TextEntered;
        public int Timeout { get; set; }

        public string OnTextInput(Session session, ITranslator translator, ICommunicator communicator, int length, bool mask)
        {
            communicator.Clear();
            if (Timeout == 0)
            {
                Timeout = Convert.ToInt32(ConfigurationManager.AppSettings["InactivityTimeoutSeconds"]);
            }
            else if (Timeout == -1)
            {
                Timeout = Int32.MaxValue;
            }

            var buffer = new byte[length + 1];

            var l = 0;

            while (buffer[l] != '\n' && buffer[l] != 13)
            {
                //Array.Clear(buffer, 0, buffer.Length);
                var start = DateTime.Now;
                while (!communicator.HasData && communicator.IsConnected && DateTime.Now - start < TimeSpan.FromSeconds(Timeout)) 
                    Thread.Sleep(25);

                if (!communicator.IsConnected || DateTime.Now - start >= new TimeSpan(0, 0, Timeout))
                {
                    throw new SessionAbortedException(session);
                }

                communicator.ReadData(buffer, l, 1);

                if (buffer[l] == 0)
                {
                    continue;
                }

                TextEntered?.Invoke(this, buffer);

                if (buffer[l] != '\n' && buffer[l] != 13)
                {
                    var c = buffer[l];
                    
                    switch (session.Encoding)
                    {
                        case "ASCII":
                        case "ANSI":
                            switch (c)
                            {
                                case 27:
                                    buffer[l] = 0;
                                    break;
                                case 8:
                                case 0x7f:
                                   if (l > 0)
                                    {
                                        communicator.SendData(new byte[] { 8, 32, 8 });
                                        buffer[l] = 0;
                                        buffer[--l] = 0;
                                    }
                                    break;

                                default:
                                    if (l == length) buffer[l] = 0;
                                    if (buffer[l] > 0)
                                    {
                                        if (!mask)
                                            communicator.SendData(buffer, l++, 1);
                                        else
                                        {
                                            communicator.SendData(new[] {(byte) '*'});
                                            ++l;
                                        }
                                    }
                                    break;
                            }
                            break;

                        case "PETSCII":
                            switch (c)
                            {
                                case 20:
                                case 127:
                                    if (l > 0)
                                    {
                                        communicator.SendData(new[] { c });
                                        buffer[l] = 0;
                                        buffer[--l] = 0;
                                    }
                                    break;

                                case 17:
                                case 29:
                                case 145:
                                case 157:
                                    buffer[l] = 0;
                                    break;

                                default:
                                    if (l == length) buffer[l] = 0;
                                    if (buffer[l] > 0)
                                    {
                                        if (!mask)
                                            communicator.SendData(buffer, l++, 1);
                                        else
                                        {
                                            communicator.SendData(new[] {(byte) '*'});
                                            ++l;
                                        }
                                    }
                                    break;
                            }
                            break;
                    }


                }
            }

            return translator.FromBytes(buffer, 0, l);
        }
    }
}
