package net.minecraft.world.entity.decoration;

import net.minecraft.core.BlockPosition;
import net.minecraft.core.EnumDirection;
import net.minecraft.core.Vector3f;
import net.minecraft.network.syncher.DataWatcherObject;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityLiving;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ItemWorldMap;

import com.bergerkiller.bukkit.common.bases.IntVector3;
import com.bergerkiller.bukkit.common.wrappers.DataWatcher;
import com.bergerkiller.bukkit.common.wrappers.DataWatcher.Key;

import com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle;

class EntityArmorStand extends EntityLiving {
#if version >= 1.17
    public static optional final (DataWatcher.Key<Byte>) DataWatcherObject<Byte> DATA_ARMORSTAND_FLAGS:DATA_CLIENT_FLAGS;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_HEAD:DATA_HEAD_POSE;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_BODY:DATA_BODY_POSE;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_LEFT:DATA_LEFT_ARM_POSE;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_RIGHT:DATA_RIGHT_ARM_POSE;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_LEFT:DATA_LEFT_LEG_POSE;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:DATA_RIGHT_LEG_POSE;
#elseif version >= 1.14
    public static optional final (DataWatcher.Key<Byte>) DataWatcherObject<Byte> DATA_ARMORSTAND_FLAGS:b;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_HEAD:c;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_BODY:d;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_LEFT:e;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_RIGHT:f;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_LEFT:g;
  #if version >= 1.16.2
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:bh;
  #elseif version >= 1.16
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:bo;
  #elseif version >= 1.15
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:bp;
  #else
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:bs;
  #endif
#elseif version >= 1.9
    public static optional final (DataWatcher.Key<Byte>) DataWatcherObject<Byte> DATA_ARMORSTAND_FLAGS:a;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_HEAD:b;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_BODY:c;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_LEFT:d;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_RIGHT:e;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_LEFT:f;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:g;
#else
    public static optional final (DataWatcher.Key<Byte>) DataWatcherObject<Byte> DATA_ARMORSTAND_FLAGS:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_HEAD:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_BODY:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_LEFT:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_ARM_RIGHT:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_LEFT:###;
    public static optional final (DataWatcher.Key<org.bukkit.util.Vector>) DataWatcherObject<Vector3f> DATA_POSE_LEG_RIGHT:###;
#endif

    <code>
    public static final Key<Byte> DATA_ARMORSTAND_FLAGS = Key.Type.BYTE.createKey(T.DATA_ARMORSTAND_FLAGS, 10);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_HEAD = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_HEAD, 11);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_BODY = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_BODY, 12);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_ARM_LEFT = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_ARM_LEFT, 13);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_ARM_RIGHT = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_ARM_RIGHT, 14);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_LEG_LEFT = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_LEG_LEFT, 15);
    public static final Key<org.bukkit.util.Vector> DATA_POSE_LEG_RIGHT = Key.Type.ROTATION_VECTOR.createKey(T.DATA_POSE_LEG_RIGHT, 16);

    public static final int DATA_FLAG_IS_SMALL = (1 << 0);
    public static final int DATA_FLAG_HAS_ARMS = (1 << 2);
    public static final int DATA_FLAG_NO_BASEPLATE = (1 << 3);
    public static final int DATA_FLAG_SET_MARKER = (1 << 4);
    </code>
}


class EntityItemFrame extends EntityHanging {
#if version >= 1.17
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<ItemStack> DATA_ITEM;
#elseif version >= 1.14
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<ItemStack> DATA_ITEM:ITEM;
#elseif version >= 1.13
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<ItemStack> DATA_ITEM:e;
#elseif version >= 1.11
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<ItemStack> DATA_ITEM:c;
#elseif version >= 1.9
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<com.google.common.base.Optional<ItemStack>> DATA_ITEM:c;
#else
    private static optional final (DataWatcher.Key<Object>) DataWatcherObject<ItemStack> DATA_ITEM:###;
#endif

    <code>
    public static final Key<org.bukkit.inventory.ItemStack> DATA_ITEM = Key.Type.ITEMSTACK.createKey(T.DATA_ITEM, 8);
    </code>

    public boolean getItemIsMap() {
        ItemStack item = instance.getItem();
        return item != null && item.getItem() instanceof ItemWorldMap;
    }

    public java.util.UUID getItemMapDisplayDynamicOnlyUUID() {
        ItemStack item = instance.getItem();
        if (item == null || !(item.getItem() instanceof ItemWorldMap)) {
            return null;
        }
        return item#getItemStackMapDisplayUUID();
    }

    public java.util.UUID getItemMapDisplayUUID() {
        ItemStack item = instance.getItem();
        if (item == null || !(item.getItem() instanceof ItemWorldMap)) {
            return null;
        }
        java.util.UUID mapDisplayUUID = item#getItemStackMapDisplayUUID();
        if (mapDisplayUUID != null) {
            return mapDisplayUUID;
        }
        int mapId = item#getItemStackMapId();
        if (mapId != -1) {
            return new java.util.UUID(0L, (long) mapId);
        }
        return null;
    }

    public (org.bukkit.inventory.ItemStack) ItemStack getItem();
    public void setItem((org.bukkit.inventory.ItemStack) ItemStack newItemStack);

    public void refreshItem() {
        // Paper added an API to update item without physics / sound. Use it if we can.
#if exists net.minecraft.world.entity.decoration.EntityItemFrame public void setItem(net.minecraft.world.item.ItemStack itemstack, boolean update, boolean playSound);
        instance.setItem(instance.getItem(), false, false);
#else
        instance.setItem(instance.getItem());
#endif
    }

    public int getRotationOrdinal:getRotation();

    <code>
    public static EntityItemFrameHandle fromBukkit(org.bukkit.entity.ItemFrame itemFrame) {
        return createHandle(com.bergerkiller.bukkit.common.conversion.type.HandleConversion.toEntityHandle(itemFrame));
    }
    </code>
}

class EntityHanging extends Entity {

    //TODO: Is this actually useful for anything at all?
    public void setBlockPositionField((IntVector3) BlockPosition blockPosition) {
#if version >= 1.21
        #require net.minecraft.world.entity.decoration.BlockAttachedEntity protected BlockPosition blockPositionField:pos;
#elseif version >= 1.17
        #require EntityHanging public BlockPosition blockPositionField:pos;
#else
        #require EntityHanging public BlockPosition blockPositionField:blockPosition;
#endif
        instance#blockPositionField = blockPosition;
    }

#if version >= 1.18
    public (IntVector3) BlockPosition getBlockPosition:getPos();
#else
    public (IntVector3) BlockPosition getBlockPosition();
#endif

#if forge_nms_obfuscated
    public (org.bukkit.block.BlockFace) EnumDirection getFacing:bt();
#else
    public (org.bukkit.block.BlockFace) EnumDirection getFacing:getDirection();
#endif
}