using System;
using System.Collections.Generic;

using FilterAPI.Networking;

using FilterLogin.LoginNetworking;

namespace FilterLogin.LoginHandlers
{
    internal class Login3Handle
    {
        [LoginPacketHandler(3, 1)]
        public static void HandleVersion(LoginClient ClientSocket, Packet ClientPacket)
        {
            UInt16 Year = UInt16.MaxValue;
            UInt16 Version = UInt16.MaxValue;

            if (((Year = ClientPacket.PacketReader.ReadUInt16()) != UInt16.MaxValue) && ((Version = ClientPacket.PacketReader.ReadUInt16()) != UInt16.MaxValue))
            {
                if (Year != Convert.ToInt32(Program.Auth.ConfigValues["LoginYear"])) { ClientSocket.Dispose(); }
                else if (Version != Convert.ToInt32(Program.Auth.ConfigValues["LoginVersion"])) { ClientSocket.Dispose(); }
                else { ClientSocket.SendPacketServer(ClientPacket); }
            }
            else { ClientSocket.Dispose(); }
        }

        [LoginPacketHandler(3, 4)]
        public static void HandleHash(LoginClient ClientSocket, Packet ClientPacket)
        {
            String Hash = String.Empty;

            ClientPacket.PacketReader.ReadByte();

            if ((Hash = ClientPacket.ReadString(28)) != String.Empty)
            {
                if (Hash.Length != 28) { ClientSocket.Dispose(); }
                else { ClientSocket.SendPacketServer(ClientPacket); }
            }
            else { ClientSocket.Dispose(); }
        }

        [LoginPacketHandler(3, 11)]
        public static void HandleWorldSelect(LoginClient ClientSocket, Packet ClientPacket)
        {
            Byte WorldID = Byte.MaxValue;

            if ((WorldID = ClientPacket.PacketReader.ReadByte()) != Byte.MaxValue)
            {
                if (Program.SQL.GettWorldBan(WorldID, Program.SQL.GetsUsernameFromnEMID(ClientSocket.nUserNo)))
                {
                    using (var ServerPacket = new Packet(3, 9))
                    {
                        ServerPacket.PacketWriter.Write((Byte)71);

                        ClientSocket.SendPacketClient(ServerPacket);
                    }

                    ClientSocket.Dispose();
                }
                else { ClientSocket.SendPacketServer(ClientPacket); }
            }
        }

        [LoginPacketHandler(3, 12)]
        public static void HandleTransferKey(LoginClient ClientSocket, Packet ServerPacket)
        {
            Byte WorldStatus = ServerPacket.PacketReader.ReadByte();
            String IPAddress = ServerPacket.ReadString(16);
            UInt16 Port = ServerPacket.PacketReader.ReadUInt16();
            String TransferKey = ServerPacket.ReadString(64);

            using (var LocalPacket = new Packet(3, 3))
            {
                LocalPacket.PacketWriter.Write(ClientSocket.nUserNo);
                LocalPacket.PacketWriter.Write(TransferKey);

                Program.LocalClient.SendPacket(LocalPacket);
            }

            using (var ServerPacketRewrite = new Packet(3, 12))
            {
                ServerPacketRewrite.PacketWriter.Write(WorldStatus);

                if (!Program.SQL.GettSendLocal(ClientSocket.nUserNo)) { ServerPacketRewrite.WriteString(Program.Auth.ConfigValues["LoginTransferIP"], 16); }
                else { ServerPacketRewrite.WriteString("127.0.0.1", 16); }

                ServerPacketRewrite.PacketWriter.Write(Port);
                ServerPacketRewrite.WriteString(TransferKey);

                ClientSocket.SendPacketClient(ServerPacketRewrite);
            }
        }

        [LoginPacketHandler(3, 32)]
        public static void HandleToken(LoginClient ClientSocket, Packet ClientPacket)
        {
            String Token = String.Empty;
            Int32 nUserNo = -1;

            if ((Token = ClientPacket.ReadString(Convert.ToByte(Program.Auth.ConfigValues["LoginTokenLength"]))) != String.Empty)
            {
                if (Token.Length != Convert.ToByte(Program.Auth.ConfigValues["LoginTokenLength"])) { ClientSocket.Dispose(); }
                else if (!Program.SQL.GetnEMIDFromsToken(Token, out nUserNo)) { ClientSocket.Dispose(); }
                else
                {
                    ClientSocket.SendPacketServer(ClientPacket);

                    Byte nAuthID = Program.SQL.GetnAuthIDFromnEMID(nUserNo);
                    Boolean nLoginable;
                    Byte nTypeID = Program.SQL.GetnTypeIDfromnAuthID(nAuthID, out nLoginable);

                    if (!nLoginable)
                    {
                        using (var ServerPacket = new Packet(3, 9))
                        {
                            ServerPacket.PacketWriter.Write((Byte)nTypeID);

                            ClientSocket.SendPacketClient(ServerPacket);
                        }

                        ClientSocket.Dispose();
                    }
                    else
                    {
                        using (var LocalPacket = new Packet(3, 1))
                        {
                            LocalPacket.PacketWriter.Write(Convert.ToString(ClientSocket.ClientGUID));
                            LocalPacket.PacketWriter.Write(nUserNo);

                            Program.LocalClient.SendPacket(LocalPacket);
                        }

                        ClientSocket.nUserNo = nUserNo;

                        List<String> sIDs = Program.SQL.GetsIDsFornUserNo(ClientSocket.nUserNo);

                        foreach (String sID in sIDs)
                        {
                            using (var LocalPacket = new Packet(4, 7))
                            {
                                LocalPacket.PacketWriter.Write(sID);
                                LocalPacket.PacketWriter.Write(true);
                                LocalPacket.PacketWriter.Write("Server");
                                LocalPacket.PacketWriter.Write("Multiple logins detected. You have been kicked from the server.");

                                Program.LocalClient.SendPacket(LocalPacket);
                            }
                        }

                        Program.SQL.InserttUserIP(nUserNo, Convert.ToString(ClientSocket.ClientEndPoint.Address));

                        foreach (String sQuery in Program.SQL.GetLoginQueries(nUserNo)) { Program.SQL.ExecutesQuery(sQuery); }

                        Program.SQL.DeletetLoginQueries(nUserNo);
                    }
                }
            }
            else {
				ClientSocket.Dispose(); }
        }
    }
}
