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

namespace ServerFix
{
    class SocketInformation
    {
        public Int64 UNID { get; set; }
        public Socket ClientSocket { get; set; }
        public IPEndPoint ClientEndPoint { get; set; }
        public Int16 ConnectCount { get; set; }
        public DateTime TimeLeft { get; set; }
    }

    class HandleListener
    {
        public List<SocketInformation> ConnectedClients;

        Socket ListenSocket;
        Int64 TotalConnections;
        public String Bind_IP;
        public Int16 Bind_Port;
        public String Connect_IP;
        public Int16 Connect_Port;

        public void Start()
        {
            try
            {
                ConnectedClients = new List<SocketInformation>();
                IPAddress BindIP = IPAddress.Parse(Bind_IP);
                IPEndPoint BindEndPoint = new IPEndPoint(BindIP, Bind_Port);

                ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ListenSocket.Bind(BindEndPoint);
                ListenSocket.Listen(10);
                ListenSocket.BeginAccept(new AsyncCallback(AcceptConnection), null);
            }
            catch (Exception Error) { Program.System.WriteError(Error.Message); }
        }

        private void AcceptConnection(IAsyncResult Result)
        {
            try
            {
                ListenSocket.BeginAccept(new AsyncCallback(AcceptConnection), null);

                TotalConnections++;

                Socket ClientSocket = ListenSocket.EndAccept(Result);
                ClientSocket.ReceiveTimeout = 10000;

                IPEndPoint ClientEndPoint = (IPEndPoint)ClientSocket.RemoteEndPoint;

                if (Program.System.BanList.Contains(Convert.ToString(ClientEndPoint.Address)))
                {
                    Shutdown(ClientSocket);

                    return;
                }

                SocketInformation ClientInformation;

                if (Program.Lock_Out)
                {
                    if ((ClientInformation = ConnectedClients.FirstOrDefault(Information => Information.ClientEndPoint.Address == ClientEndPoint.Address)) != null)
                    {
                        ClientInformation.ConnectCount = ClientInformation.ConnectCount++;

                        if (ClientInformation.ConnectCount > 40 && ClientInformation.TimeLeft > DateTime.Now)
                        {
                            Shutdown(ClientSocket);

                            return;
                        }
                        else if (ClientInformation.TimeLeft < DateTime.Now)
                        {
                            ConnectedClients.Remove(ClientInformation);

                            ConnectedClients.Add(new SocketInformation { UNID = TotalConnections, ClientSocket = ClientSocket, ClientEndPoint = ClientEndPoint, ConnectCount = 0, TimeLeft = DateTime.Now.AddMinutes(20) });

                            return;
                        }
                    }
                    else { ConnectedClients.Add(new SocketInformation { UNID = TotalConnections, ClientSocket = ClientSocket, ClientEndPoint = ClientEndPoint, ConnectCount = 0, TimeLeft = DateTime.Now.AddMinutes(20) }); }
                }

                HandleClient Handle = new HandleClient(ClientSocket, this);
            }
            catch (Exception Error) { Program.System.WriteError(Error.Message); }
        }

        private void Shutdown(Socket ClientSocket)
        {
            try
            {
                ClientSocket.Shutdown(SocketShutdown.Both);
                ClientSocket.Disconnect(false);
                ClientSocket.Close();

                if (ClientSocket != null) { ClientSocket.Dispose(); }
            }
            catch { }
        }
    }
}
