using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace TELTest {
    class Program {
        
        static void Main(string[] args) {
            Environment.CurrentDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            Task.Run(async () => {
                var ipEndPoint = new IPEndPoint(IPAddress.Any, 1553);
                
                TcpListener listener = new TcpListener(ipEndPoint);
                WriteWithTime("Listening on " + ipEndPoint);
                try {
                    listener.Start();
                    while (true) {
                        TcpClient tc = await listener.AcceptTcpClientAsync();
                        AcceptConnection(tc);
                    }
                } finally {
                    listener.Stop();
                }
            }).Wait();
        }
        static async void AcceptConnection(TcpClient handler) {
            var endpoint = handler.Client.RemoteEndPoint;
            handler.Client.SetSocketKeepAliveValues(2000, 1000);
            WriteWithTime("Incoming connection from " + endpoint);
            ConnectionHandler ch = new NormalConnectionHandler();
            try {
                using (handler) {
                    using (NetworkStream stream = handler.GetStream()) {
                        
                        WriteWithTime(ConnectionHandler.AllHandlers.Count + " concurrent connections right now.");
                        if (Config.MaxConnections < ConnectionHandler.AllHandlers.Count) {
                            await ch.WriteASCII(stream, "Sorry, the server is full (" + (ConnectionHandler.AllHandlers.Count - 1) + "/" + Config.MaxConnections + ")");
                            WriteWithTime(handler.Client.RemoteEndPoint + " exceeds server capacity, disconnecting.");
                        } else {
                            await ch.Handle(stream);
                        }
                        WriteWithTime(handler.Client.RemoteEndPoint + " disconnected.");
                    }
                }
            } catch (System.IO.IOException x) {
                ConnectionHandler.AllHandlers.Remove(ch);
                WriteWithTime("Endpoint " + endpoint + " unexpectedly disconnected. ({0})", x.Message + ", " + x.InnerException);
            } catch (ArgumentOutOfRangeException x) {
                ConnectionHandler.AllHandlers.Remove(ch);
                WriteWithTime("Endpoint " + endpoint + " unexpectedly disconnected. ({0})", x.Message + ", " + x.InnerException);
            } catch (Exception x) {
                ConnectionHandler.AllHandlers.Remove(ch);
                var lc = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                WriteWithTime("GENERAL EXCEPTION:\r\n{0}", x);
                Console.ForegroundColor = lc;
            }

        }
        public static void WriteWithTime(string format, params object[] arg) {
            Console.WriteLine("[" + DateTime.Now + "] " + format, arg);
        }
    }
}
