using System;
using System.Collections.Generic;
using System.Net;
using System.Timers;
using System.IO;
using System.Reflection;
using System.Net.Sockets;

using FiestaBot;

using FiestaBot.Instances.Networking;
using FiestaBot.Manager.Networking;
using FiestaBot.Utilities;
using FiestaBot.Zone.Game;

namespace FiestaBot.Zone.Networking
{
    internal class ZoneClient : Client
    {
        public byte ZoneID;

        public FiestaCrypto Crypto;

        public ManagerClient Manager;

        public bool InNPC;

        public bool InTrade;

        public int SlotID;
        
        public int PosX = 0;
        public int PosY = 0;

        public bool FollowMode = false;
        public ushort FollowUser = 0;

        public List<MapObject> ObjectList = new List<MapObject>();
        
        public ZoneClient(IPAddress ConnectIP, int Port) : base(ConnectIP, Port)
        {
            Program.ZoneClient = this;
            Manager = Program.ManagerClient;
        }

        public void SendPacket(Packet ServerPacket)
        {
            if (IsConnected != 0) { return; }

            ServerPacket.ToArray(Crypto, out byte[] PacketBuffer);
            ServerPacket.Dispose();

            Send(PacketBuffer);
        }

        public override void Connected()
        {
            Receive();
            Logger.Log(LogType.Socket, "Succesfully connected to zone");
        }

        public override void ConnectFailed(SocketException Exception) { }

        public override void Received(byte[] Buffer)
        {
            Packet ClientPacket = new Packet(Buffer);

            if(!ClientPacket.SetHeaderAndType()) { Logger.Log(LogType.Zone, "Unable to read packet header/type"); }
            else if (Program.ZoneHandlers.HasHandler(ClientPacket.Header, ClientPacket.Type))
            {
                try
                {
                    MethodInfo PacketMethod = Program.ZoneHandlers.GetHandler(ClientPacket.Header, ClientPacket.Type);

                    Action PacketAction = Program.ZoneHandlers.GetAction(PacketMethod, this, ClientPacket);
                    try { PacketAction(); } catch { }
                }
                catch { Logger.Log(LogType.Zone, "Unknown packet: {0}:{1}", ClientPacket.Header, ClientPacket.Type); }
            }
            else { Logger.Log(LogType.Zone, "Unknown packet: {0}:{1}", ClientPacket.Header, ClientPacket.Type); }
        }

        public override void Disconnected()
        {
            Logger.Log(LogType.Socket, "Disconnected from zone {0}", ZoneID);
        }
    }
}
