using System;
using System.Net;
using System.Net.Sockets;

namespace Zone_Fix.Networking
{
    class HandleServer
    {
        public Boolean IsConnected = true;

        private String Name;
        private Int32 ConnectPort;

        private Socket ServerSocket;
        private Byte[] ServerBuffer;

        private IPEndPoint ClientEndPoint;
        private HandleClient ClientSocket;

        public HandleServer(String HandleName, Int32 HandleConnectPort, IPEndPoint HandleEndPoint, HandleClient HandleSocket)
        {
            Name = HandleName;
            ConnectPort = HandleConnectPort;

            ClientEndPoint = HandleEndPoint;
            ClientSocket = HandleSocket;

            Connect();
        }

        private void Connect()
        {
            try
            {
                IPAddress ConnectIP = IPAddress.Parse(Program.ConnectIP);
                IPEndPoint ConnectEndPoint = new IPEndPoint(ConnectIP, ConnectPort);

                ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ServerSocket.BeginConnect(ConnectEndPoint, new AsyncCallback(Connected), ServerSocket);
            }
            catch (Exception Error) { DisconnectWithException(Error.Message); }
        }

        private void Connected(IAsyncResult Result)
        {
            try
            {
                ServerSocket.EndConnect(Result);

                Receive();
            }
            catch (Exception Error) { DisconnectWithException(Error.Message); }
        }

        private void Receive()
        {
            try
            {
                ServerBuffer = new Byte[Program.Byte_Size];

                ServerSocket.BeginReceive(ServerBuffer, 0, ServerBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), ServerSocket);
            }
            catch (Exception Error) { DisconnectWithException(Error.Message); }
        }

        private void ReceiveMessage(IAsyncResult Result)
        {
            try
            {
                Int32 ReceiveLength = ServerSocket.EndReceive(Result);

                Array.Resize(ref ServerBuffer, ReceiveLength);

                if (ReceiveLength != 0 && ClientSocket.IsConnected && Program.Analyse.CheckServer(Program.BytesToHex(ServerBuffer), ReceiveLength))
                {
                    ClientSocket.Send(ServerBuffer, ReceiveLength);

                    Receive();
                }
                else
                {
                    IsConnected = false;

                    Program.Writer.WriteBlank(true, "({0}) Has Disconnected -> {1}", Name, ClientEndPoint.Address);

                    ClientSocket.Close();
                    Close();

                    return;
                }
            }
            catch (Exception Error) { DisconnectWithException(Error.Message); }
        }

        private void Close()
        {
            try
            {
                ServerSocket.Disconnect(false);
                ServerSocket.Close();

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

        private void DisconnectWithException(String Exception)
        {
            IsConnected = false;

            //Program.Writer.WriteBlank(true, "({0}) Has Disconnected -> {1}, Exception -> {2}", Name, ClientEndPoint.Address, Exception);

            Close();

            return;
        }

        public void Send(Byte[] Buffer, Int32 Length)
        {
            try
            {
                //Program.Writer.WriteBlank(true, "({0}) Sent Message -> {1}, Length -> {2}", ClientEndPoint.Address, Name, Length);

                ServerSocket.Send(Buffer);
            }
            catch (Exception Error) { DisconnectWithException(Error.Message); }
        }
    }
}
