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

namespace ParticleFramework.Communication
{
    class TcpListener
    {

        #region Do not edit
            public int port, maxConnections;
            public Boolean acceptConnections;
            public Socket socketHandler;
            public HashSet<TcpClient> clients;
        #endregion

        public Boolean Init(string _port, string _maxConnections)
        {
            try
            {
                port = Convert.ToInt32(_port);
                maxConnections = Convert.ToInt32(_maxConnections);

                if (port <= 0 && maxConnections <= 0)
                {
                    Log.Error("Server port or max connections settings are invalid!");
                    return false;
                }

                //setup some variables
                clients = new HashSet<TcpClient>();
                acceptConnections = true;

                //bind and listen
                socketHandler = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socketHandler.Bind(new IPEndPoint(IPAddress.Any, port));
                socketHandler.Listen(maxConnections);
                socketHandler.BeginAccept(new AsyncCallback(newConnection), socketHandler);

                //output success
                Console.WriteLine("Server is listening on port " + port + " for " + maxConnections + " connections.");

                return true;
            }
            catch(Exception exception)
            {
                Log.Error("Setting up socket: " + exception.ToString());
                return false;
            }
        }

        public void removeClient(TcpClient client)
        {
            clients.Remove(client);
        }

        public void removeClient(int i)
        {
            int index = 0;
            foreach (TcpClient client in clients)
            {
                if (index == i)
                {
                    clients.Remove(client);
                    return;
                }
                index++;
            }
        }

        internal int clientCount
        {
            get
            {
                return clients.Count;
            }
        }

        public TcpClient getClient(int i)
        {
            int index = 0;
            foreach (TcpClient client in clients)
            {
                if (index == i)
                {
                    return client;
                }
                index++;
            }

            return null;
        }

        private void newConnection(IAsyncResult iAr)
        {
            try
            {
                Socket socket = ((Socket)iAr.AsyncState).EndAccept(iAr);
                string iP = socket.RemoteEndPoint.ToString().Split(new char[] { ':' })[0];

                Console.WriteLine("New connection from " + iP);
                Log.Info(iP + " connected. Full: " + socket.RemoteEndPoint.ToString());

                clients.Add(new TcpClient(socket, clients.Count));

            }
            catch(Exception exception)
            {
                Log.Error("New connection: " + exception.ToString());
            }
            socketHandler.BeginAccept(new AsyncCallback(newConnection), socketHandler);
        }

    }
}
