using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
using System;
using System.Runtime.InteropServices;

namespace PSO2SERVER.Protocol.Handlers
{
    [PacketHandlerAttr(0x04, 0x07)]
    public class MovementHandler : PacketHandler
    {
        #region implemented abstract members of PacketHandler

        public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
        {
            PacketReader reader = new PacketReader(data);
            // This packet is "Compressed" basically.
            reader.ReadBytes(6); // Get past the junk
            // For simplicity's sake, read the 3 flag bytes into a big int
            byte[] flagBytes = reader.ReadBytes(3);
            uint dataFlags = flagBytes[0];
            dataFlags |= (uint)(flagBytes[1] << 8);
            dataFlags |= (uint)(flagBytes[2] << 16);

            PackedData theFlags = (PackedData)dataFlags;

            // Debug
            //Logger.WriteInternal("[移动] Movement 数据包来自 {0} 包含 {1} 数据.", context.Character.Name, theFlags);

            // TODO: Maybe do this better someday
            MovementPacket.FullMovementData dstData = new MovementPacket.FullMovementData();

            if (theFlags.HasFlag(PackedData.ENT1_ID))
            {
                dstData.entity1.ID = (uint)reader.ReadUInt64();
            }
            if (theFlags.HasFlag(PackedData.ENT1_TYPE))
            {
                dstData.entity1.ObjectType = (ObjectType)reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.ENT1_A))
            {
                dstData.entity1.MapID = reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.ENT2_ID))
            {
                dstData.entity1.ID = (uint)reader.ReadUInt64();
            }
            if (theFlags.HasFlag(PackedData.ENT2_TYPE))
            {
                dstData.entity1.ObjectType = (ObjectType)reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.ENT2_A))
            {
                dstData.entity1.MapID = reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.TIMESTAMP))
            {
                dstData.timestamp = reader.ReadUInt32();
                context.MovementTimestamp = dstData.timestamp;
            }
            if (theFlags.HasFlag(PackedData.ROT_X))
            {
                dstData.rotation.x = reader.ReadUInt16();
                context.CurrentLocation.RotX = Helper.FloatFromHalfPrecision(dstData.rotation.x);
            }
            if (theFlags.HasFlag(PackedData.ROT_Y))
            {
                dstData.rotation.y = reader.ReadUInt16();
                context.CurrentLocation.RotY = Helper.FloatFromHalfPrecision(dstData.rotation.y);
            }
            if (theFlags.HasFlag(PackedData.ROT_Z))
            {
                dstData.rotation.z = reader.ReadUInt16();
                context.CurrentLocation.RotZ = Helper.FloatFromHalfPrecision(dstData.rotation.z);
            }
            if (theFlags.HasFlag(PackedData.ROT_W))
            {
                dstData.rotation.w = reader.ReadUInt16();
                context.CurrentLocation.RotW = Helper.FloatFromHalfPrecision(dstData.rotation.w);
            }
            if (theFlags.HasFlag(PackedData.CUR_X))
            {
                dstData.currentPos.x = reader.ReadUInt16();
                context.CurrentLocation.PosX = Helper.FloatFromHalfPrecision(dstData.currentPos.x);
            }
            if (theFlags.HasFlag(PackedData.CUR_Y))
            {
                dstData.currentPos.y = reader.ReadUInt16();
                context.CurrentLocation.PosY = Helper.FloatFromHalfPrecision(dstData.currentPos.y);
            }
            if (theFlags.HasFlag(PackedData.CUR_Z))
            {
                dstData.currentPos.z = reader.ReadUInt16();
                context.CurrentLocation.PosZ = Helper.FloatFromHalfPrecision(dstData.currentPos.z);
            }
            if (theFlags.HasFlag(PackedData.UNKNOWN4))
            {
                dstData.Unknown2 = reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.UNK_X))
            {
                dstData.unknownPos.x = reader.ReadUInt16();
                context.LastLocation.PosX = Helper.FloatFromHalfPrecision(dstData.unknownPos.x);
            }
            if (theFlags.HasFlag(PackedData.UNK_Y))
            {
                dstData.unknownPos.y = reader.ReadUInt16();
                context.LastLocation.PosY = Helper.FloatFromHalfPrecision(dstData.unknownPos.y);
            }
            if (theFlags.HasFlag(PackedData.UNK_Z))
            {
                dstData.unknownPos.z = reader.ReadUInt16();
                context.LastLocation.PosZ = Helper.FloatFromHalfPrecision(dstData.unknownPos.z);
            }
            if (theFlags.HasFlag(PackedData.UNKNOWN5))
            {
                dstData.Unknown3 = reader.ReadUInt16();
            }
            if (theFlags.HasFlag(PackedData.UNKNOWN6))
            {
                if (theFlags.HasFlag(PackedData.UNKNOWN7))
                {
                    dstData.Unknown4 = reader.ReadByte();
                }
                else
                {
                    dstData.Unknown4 = reader.ReadUInt32();
                }
            }


            //Logger.WriteInternal("[移动] 玩家 {0} 移动中 (坐标: X{1}, Y{2}, Z{3})", context.Character.Name, context.CurrentLocation.PosX,
                //context.CurrentLocation.PosY, context.CurrentLocation.PosZ);

            foreach (var c in Server.Instance.Clients)
            {
                if (c.Character == null || c == context || c.CurrentZone != context.CurrentZone)
                    continue;

                //c.SendPacket(0x04, 0x07, flags, data);
                c.SendPacket(new MovementPacket(dstData));
            }
        }

        #endregion
    }

    [Flags]
    public enum PackedData : Int32
    {
        ENT1_ID = 1,
        ENT1_TYPE = 2,
        ENT1_A = 4,
        ENT2_ID = 8,
        ENT2_TYPE = 0x10,
        ENT2_A = 0x20,
        TIMESTAMP = 0x40,
        ROT_X = 0x80,
        ROT_Y = 0x100,
        ROT_Z = 0x200,
        ROT_W = 0x400,
        CUR_X = 0x800,
        CUR_Y = 0x1000,
        CUR_Z = 0x2000,
        UNKNOWN4 = 0x4000,
        UNK_X = 0x8000,
        UNK_Y = 0x10000,
        UNK_Z = 0x20000,
        UNKNOWN5 = 0x40000,
        UNKNOWN6 = 0x80000,
        UNKNOWN7 = 0x100000
    }


}