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

using FilterAPI.Networking;

namespace FilterManager.ManagerNetworking
{
    internal class ManagerClient : ClientMulti, IDisposable
    {
        public Guid ClientGUID = Guid.NewGuid();

        public FiestaCrypto CCrypto;
        public FiestaCrypto SCrypto;

        public Character NewCharacter;

        public Int32 nUserNo = -1;
        public Int32 nCharNo = -1;
        public String sID = String.Empty;
        public String PartyMaster = String.Empty;
        public List<String> PartyMembers = new List<String>();

        public ManagerClient(Socket AcceptedSocket, IPEndPoint AcceptedEndPoint)
            : base(AcceptedSocket, AcceptedEndPoint, IPAddress.Parse(Program.Auth.ConfigValues["ManagerConnectIP"]), Convert.ToInt32(Program.Auth.ConfigValues["ManagerConnectPort"]))
        {
            Program.ManagerClients.TryAdd(ClientGUID, this);

            if (Program.SQL.GetbBlockForsIP(Convert.ToString(ClientEndPoint.Address)) || Program.SQL.GetnAmountForsIP(Convert.ToString(ClientEndPoint.Address)) >= Convert.ToInt64(Program.Auth.ConfigValues["MaximumCPIP"]))
            {
                Dispose();

                return;
            }
            else { Program.SQL.AddnAmountForsIP(Convert.ToString(ClientEndPoint.Address)); }
        }

        public void SendCrypto()
        {
            CCrypto = new FiestaCrypto(Program.Auth, 2);

            using (var ServerPacket = new Packet(2, 7))
            {
                ServerPacket.PacketWriter.Write((UInt16)2);

                SendPacketClient(ServerPacket);
            }
        }

        public override void ReceivedClient(Byte[] Buffer)
        {
            if (CCrypto != null) { CCrypto.Crypt(Buffer, 0, Buffer.Length); }

            if (Buffer != null && Buffer.Length >= 2)
            {
                using (var ClientPacket = new Packet(Buffer))
                {
                    if (!ClientPacket.SetHeaderAndType()) { Dispose(); }
                    else if (nUserNo == -1 && (ClientPacket.Header != 3 || ClientPacket.Type != 15)) { Dispose(); }
                    else if (Program.ManagerHandlers.HasHandler(ClientPacket.Header, ClientPacket.Type))
                    {
                        try
                        {
                            MethodInfo PacketMethod = Program.ManagerHandlers.GetHandler(ClientPacket.Header, ClientPacket.Type);

                            Action PacketAction = Program.ManagerHandlers.GetAction(PacketMethod, this, ClientPacket);
                            PacketAction();
                        }
                        catch (Exception Error)
                        {
                            SendPacketServer(ClientPacket);

                            Program.SendConsoleText(ConsoleColor.Red, String.Format("Header: {0} || Type: {1}\n{2}", ClientPacket.Header, ClientPacket.Type, Error.ToString()));
                        }
                    }
                    else { SendPacketServer(ClientPacket); }
                }
            }
        }

        public void SendPacketClient(Packet ServerPacket)
        {
            Byte[] PacketBuffer;

            ServerPacket.ToArray(out PacketBuffer);

            SendClient(PacketBuffer);
        }

        public override void ReceivedServer(Byte[] Buffer)
        {
            if (Buffer != null && Buffer.Length >= 2)
            {
                using (var ServerPacket = new Packet(Buffer))
                {
                    if (!ServerPacket.SetHeaderAndType()) { Dispose(); }
                    else if (Program.ManagerHandlers.HasHandler(ServerPacket.Header, ServerPacket.Type))
                    {
                        try
                        {
                            MethodInfo PacketMethod = Program.ManagerHandlers.GetHandler(ServerPacket.Header, ServerPacket.Type);

                            Action PacketAction = Program.ManagerHandlers.GetAction(PacketMethod, this, ServerPacket);
                            PacketAction();
                        }
                        catch (Exception Error)
                        {
                            SendPacketClient(ServerPacket);

                            Program.SendConsoleText(ConsoleColor.Red, String.Format("Header: {0} || Type: {1}\n{2}", ServerPacket.Header, ServerPacket.Type, Error.ToString()));
                        }
                    }
                    else { SendPacketClient(ServerPacket); }
                }
            }
        }

        public void SendPacketServer(Packet ClientPacket)
        {
            Byte[] PacketBuffer;

            ClientPacket.ToArray(SCrypto, out PacketBuffer);

            SendServer(PacketBuffer);
        }

        public override void Disconnected()
        {
            ManagerClient MClient;

            Program.ManagerClients.TryRemove(ClientGUID, out MClient);

            Program.SQL.DeletetParties(nCharNo);
        }
    }
}
