package net.minecraft.world.entity.decoration;

import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import org.apache.logging.log4j.LogManager;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.InteractionHand;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import net.minecraft.world.item.MapItem;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.Items;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameRules;
import javax.annotation.Nullable;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.level.block.state.BlockState;
import java.util.function.Predicate;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.AABB;
import org.apache.commons.lang3.Validate;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.network.syncher.EntityDataAccessor;
import org.apache.logging.log4j.Logger;

public class ItemFrame extends HangingEntity {
    private static final Logger LOGGER;
    private static final EntityDataAccessor<ItemStack> DATA_ITEM;
    private static final EntityDataAccessor<Integer> DATA_ROTATION;
    private float dropChance;
    
    public ItemFrame(final EntityType<? extends ItemFrame> aku, final Level bjw) {
        super(aku, bjw);
        this.dropChance = 1.0f;
    }
    
    public ItemFrame(final Level bjw, final BlockPos fk, final Direction fp) {
        super(EntityType.ITEM_FRAME, bjw, fk);
        this.dropChance = 1.0f;
        this.setDirection(fp);
    }
    
    @Override
    protected float getEyeHeight(final Pose alj, final EntityDimensions akr) {
        return 0.0f;
    }
    
    @Override
    protected void defineSynchedData() {
        this.getEntityData().<ItemStack>define(ItemFrame.DATA_ITEM, ItemStack.EMPTY);
        this.getEntityData().<Integer>define(ItemFrame.DATA_ROTATION, 0);
    }
    
    @Override
    protected void setDirection(final Direction fp) {
        Validate.notNull(fp);
        this.direction = fp;
        if (fp.getAxis().isHorizontal()) {
            this.xRot = 0.0f;
            this.yRot = (float)(this.direction.get2DDataValue() * 90);
        }
        else {
            this.xRot = (float)(-90 * fp.getAxisDirection().getStep());
            this.yRot = 0.0f;
        }
        this.xRotO = this.xRot;
        this.yRotO = this.yRot;
        this.recalculateBoundingBox();
    }
    
    @Override
    protected void recalculateBoundingBox() {
        if (this.direction == null) {
            return;
        }
        final double double2 = 0.46875;
        final double double3 = this.pos.getX() + 0.5 - this.direction.getStepX() * 0.46875;
        final double double4 = this.pos.getY() + 0.5 - this.direction.getStepY() * 0.46875;
        final double double5 = this.pos.getZ() + 0.5 - this.direction.getStepZ() * 0.46875;
        this.setPosRaw(double3, double4, double5);
        double double6 = this.getWidth();
        double double7 = this.getHeight();
        double double8 = this.getWidth();
        final Direction.Axis a16 = this.direction.getAxis();
        switch (a16) {
            case X: {
                double6 = 1.0;
                break;
            }
            case Y: {
                double7 = 1.0;
                break;
            }
            case Z: {
                double8 = 1.0;
                break;
            }
        }
        double6 /= 32.0;
        double7 /= 32.0;
        double8 /= 32.0;
        this.setBoundingBox(new AABB(double3 - double6, double4 - double7, double5 - double8, double3 + double6, double4 + double7, double5 + double8));
    }
    
    @Override
    public boolean survives() {
        if (!this.level.noCollision(this)) {
            return false;
        }
        final BlockState byj2 = this.level.getBlockState(this.pos.relative(this.direction.getOpposite()));
        return (byj2.getMaterial().isSolid() || (this.direction.getAxis().isHorizontal() && DiodeBlock.isDiode(byj2))) && this.level.getEntities(this, this.getBoundingBox(), ItemFrame.HANGING_ENTITY).isEmpty();
    }
    
    @Override
    public float getPickRadius() {
        return 0.0f;
    }
    
    @Override
    public void kill() {
        this.removeFramedMap(this.getItem());
        super.kill();
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        if (!ajz.isExplosion() && !this.getItem().isEmpty()) {
            if (!this.level.isClientSide) {
                this.dropItem(ajz.getEntity(), false);
                this.playSound(SoundEvents.ITEM_FRAME_REMOVE_ITEM, 1.0f, 1.0f);
            }
            return true;
        }
        return super.hurt(ajz, float2);
    }
    
    @Override
    public int getWidth() {
        return 12;
    }
    
    @Override
    public int getHeight() {
        return 12;
    }
    
    @Override
    public boolean shouldRenderAtSqrDistance(final double double1) {
        double double2 = 16.0;
        double2 *= 64.0 * getViewScale();
        return double1 < double2 * double2;
    }
    
    @Override
    public void dropItem(@Nullable final Entity akq) {
        this.playSound(SoundEvents.ITEM_FRAME_BREAK, 1.0f, 1.0f);
        this.dropItem(akq, true);
    }
    
    @Override
    public void playPlacementSound() {
        this.playSound(SoundEvents.ITEM_FRAME_PLACE, 1.0f, 1.0f);
    }
    
    private void dropItem(@Nullable final Entity akq, final boolean boolean2) {
        if (!this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
            if (akq == null) {
                this.removeFramedMap(this.getItem());
            }
            return;
        }
        ItemStack ben4 = this.getItem();
        this.setItem(ItemStack.EMPTY);
        if (akq instanceof Player) {
            final Player ayj5 = (Player)akq;
            if (ayj5.abilities.instabuild) {
                this.removeFramedMap(ben4);
                return;
            }
        }
        if (boolean2) {
            this.spawnAtLocation(Items.ITEM_FRAME);
        }
        if (!ben4.isEmpty()) {
            ben4 = ben4.copy();
            this.removeFramedMap(ben4);
            if (this.random.nextFloat() < this.dropChance) {
                this.spawnAtLocation(ben4);
            }
        }
    }
    
    private void removeFramedMap(final ItemStack ben) {
        if (ben.getItem() == Items.FILLED_MAP) {
            final MapItemSavedData crg3 = MapItem.getOrCreateSavedData(ben, this.level);
            crg3.removedFromFrame(this.pos, this.getId());
            crg3.setDirty(true);
        }
        ben.setFramed(null);
    }
    
    public ItemStack getItem() {
        return this.getEntityData().<ItemStack>get(ItemFrame.DATA_ITEM);
    }
    
    public void setItem(final ItemStack ben) {
        this.setItem(ben, true);
    }
    
    public void setItem(ItemStack ben, final boolean boolean2) {
        if (!ben.isEmpty()) {
            ben = ben.copy();
            ben.setCount(1);
            ben.setFramed(this);
        }
        this.getEntityData().<ItemStack>set(ItemFrame.DATA_ITEM, ben);
        if (!ben.isEmpty()) {
            this.playSound(SoundEvents.ITEM_FRAME_ADD_ITEM, 1.0f, 1.0f);
        }
        if (boolean2 && this.pos != null) {
            this.level.updateNeighbourForOutputSignal(this.pos, Blocks.AIR);
        }
    }
    
    @Override
    public boolean setSlot(final int integer, final ItemStack ben) {
        if (integer == 0) {
            this.setItem(ben);
            return true;
        }
        return false;
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> sb) {
        if (sb.equals(ItemFrame.DATA_ITEM)) {
            final ItemStack ben3 = this.getItem();
            if (!ben3.isEmpty() && ben3.getFrame() != this) {
                ben3.setFramed(this);
            }
        }
    }
    
    public int getRotation() {
        return this.getEntityData().<Integer>get(ItemFrame.DATA_ROTATION);
    }
    
    public void setRotation(final int integer) {
        this.setRotation(integer, true);
    }
    
    private void setRotation(final int integer, final boolean boolean2) {
        this.getEntityData().<Integer>set(ItemFrame.DATA_ROTATION, integer % 8);
        if (boolean2 && this.pos != null) {
            this.level.updateNeighbourForOutputSignal(this.pos, Blocks.AIR);
        }
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        if (!this.getItem().isEmpty()) {
            jt.put("Item", this.getItem().save(new CompoundTag()));
            jt.putByte("ItemRotation", (byte)this.getRotation());
            jt.putFloat("ItemDropChance", this.dropChance);
        }
        jt.putByte("Facing", (byte)this.direction.get3DDataValue());
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        final CompoundTag jt2 = jt.getCompound("Item");
        if (jt2 != null && !jt2.isEmpty()) {
            final ItemStack ben4 = ItemStack.of(jt2);
            if (ben4.isEmpty()) {
                ItemFrame.LOGGER.warn("Unable to load item from: {}", jt2);
            }
            final ItemStack ben5 = this.getItem();
            if (!ben5.isEmpty() && !ItemStack.matches(ben4, ben5)) {
                this.removeFramedMap(ben5);
            }
            this.setItem(ben4, false);
            this.setRotation(jt.getByte("ItemRotation"), false);
            if (jt.contains("ItemDropChance", 99)) {
                this.dropChance = jt.getFloat("ItemDropChance");
            }
        }
        this.setDirection(Direction.from3DDataValue(jt.getByte("Facing")));
    }
    
    @Override
    public boolean interact(final Player ayj, final InteractionHand ajk) {
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        final boolean boolean5 = !this.getItem().isEmpty();
        final boolean boolean6 = !ben4.isEmpty();
        if (this.level.isClientSide) {
            return boolean5 || boolean6;
        }
        if (!boolean5) {
            if (boolean6) {
                this.setItem(ben4);
                if (!ayj.abilities.instabuild) {
                    ben4.shrink(1);
                }
            }
        }
        else {
            this.playSound(SoundEvents.ITEM_FRAME_ROTATE_ITEM, 1.0f, 1.0f);
            this.setRotation(this.getRotation() + 1);
        }
        return true;
    }
    
    public int getAnalogOutput() {
        if (this.getItem().isEmpty()) {
            return 0;
        }
        return this.getRotation() % 8 + 1;
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this, this.getType(), this.direction.get3DDataValue(), this.getPos());
    }
    
    static {
        LOGGER = LogManager.getLogger();
        DATA_ITEM = SynchedEntityData.<ItemStack>defineId(ItemFrame.class, EntityDataSerializers.ITEM_STACK);
        DATA_ROTATION = SynchedEntityData.<Integer>defineId(ItemFrame.class, EntityDataSerializers.INT);
    }
}
