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.InteractionResult;
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.phys.Vec3;
import net.minecraft.world.entity.MoverType;
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;
    private boolean fixed;
    
    public ItemFrame(final EntityType<? extends ItemFrame> aoq, final Level bqb) {
        super(aoq, bqb);
        this.dropChance = 1.0f;
    }
    
    public ItemFrame(final Level bqb, final BlockPos fu, final Direction fz) {
        super(EntityType.ITEM_FRAME, bqb, fu);
        this.dropChance = 1.0f;
        this.setDirection(fz);
    }
    
    @Override
    protected float getEyeHeight(final Pose apj, final EntityDimensions aon) {
        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 fz) {
        Validate.notNull(fz);
        this.direction = fz;
        if (fz.getAxis().isHorizontal()) {
            this.xRot = 0.0f;
            this.yRot = (float)(this.direction.get2DDataValue() * 90);
        }
        else {
            this.xRot = (float)(-90 * fz.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.fixed) {
            return true;
        }
        if (!this.level.noCollision(this)) {
            return false;
        }
        final BlockState cfj2 = this.level.getBlockState(this.pos.relative(this.direction.getOpposite()));
        return (cfj2.getMaterial().isSolid() || (this.direction.getAxis().isHorizontal() && DiodeBlock.isDiode(cfj2))) && this.level.getEntities(this, this.getBoundingBox(), ItemFrame.HANGING_ENTITY).isEmpty();
    }
    
    @Override
    public void move(final MoverType apd, final Vec3 dem) {
        if (!this.fixed) {
            super.move(apd, dem);
        }
    }
    
    @Override
    public void push(final double double1, final double double2, final double double3) {
        if (!this.fixed) {
            super.push(double1, double2, double3);
        }
    }
    
    @Override
    public float getPickRadius() {
        return 0.0f;
    }
    
    @Override
    public void kill() {
        this.removeFramedMap(this.getItem());
        super.kill();
    }
    
    @Override
    public boolean hurt(final DamageSource anw, final float float2) {
        if (this.fixed) {
            return (anw == DamageSource.OUT_OF_WORLD || anw.isCreativePlayer()) && super.hurt(anw, float2);
        }
        if (this.isInvulnerableTo(anw)) {
            return false;
        }
        if (!anw.isExplosion() && !this.getItem().isEmpty()) {
            if (!this.level.isClientSide) {
                this.dropItem(anw.getEntity(), false);
                this.playSound(SoundEvents.ITEM_FRAME_REMOVE_ITEM, 1.0f, 1.0f);
            }
            return true;
        }
        return super.hurt(anw, 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 aom) {
        this.playSound(SoundEvents.ITEM_FRAME_BREAK, 1.0f, 1.0f);
        this.dropItem(aom, true);
    }
    
    @Override
    public void playPlacementSound() {
        this.playSound(SoundEvents.ITEM_FRAME_PLACE, 1.0f, 1.0f);
    }
    
    private void dropItem(@Nullable final Entity aom, final boolean boolean2) {
        if (this.fixed) {
            return;
        }
        if (!this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
            if (aom == null) {
                this.removeFramedMap(this.getItem());
            }
            return;
        }
        ItemStack bki4 = this.getItem();
        this.setItem(ItemStack.EMPTY);
        if (aom instanceof Player) {
            final Player bec5 = (Player)aom;
            if (bec5.abilities.instabuild) {
                this.removeFramedMap(bki4);
                return;
            }
        }
        if (boolean2) {
            this.spawnAtLocation(Items.ITEM_FRAME);
        }
        if (!bki4.isEmpty()) {
            bki4 = bki4.copy();
            this.removeFramedMap(bki4);
            if (this.random.nextFloat() < this.dropChance) {
                this.spawnAtLocation(bki4);
            }
        }
    }
    
    private void removeFramedMap(final ItemStack bki) {
        if (bki.getItem() == Items.FILLED_MAP) {
            final MapItemSavedData czv3 = MapItem.getOrCreateSavedData(bki, this.level);
            czv3.removedFromFrame(this.pos, this.getId());
            czv3.setDirty(true);
        }
        bki.setEntityRepresentation(null);
    }
    
    public ItemStack getItem() {
        return this.getEntityData().<ItemStack>get(ItemFrame.DATA_ITEM);
    }
    
    public void setItem(final ItemStack bki) {
        this.setItem(bki, true);
    }
    
    public void setItem(ItemStack bki, final boolean boolean2) {
        if (!bki.isEmpty()) {
            bki = bki.copy();
            bki.setCount(1);
            bki.setEntityRepresentation(this);
        }
        this.getEntityData().<ItemStack>set(ItemFrame.DATA_ITEM, bki);
        if (!bki.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 bki) {
        if (integer == 0) {
            this.setItem(bki);
            return true;
        }
        return false;
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> tq) {
        if (tq.equals(ItemFrame.DATA_ITEM)) {
            final ItemStack bki3 = this.getItem();
            if (!bki3.isEmpty() && bki3.getFrame() != this) {
                bki3.setEntityRepresentation(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 le) {
        super.addAdditionalSaveData(le);
        if (!this.getItem().isEmpty()) {
            le.put("Item", this.getItem().save(new CompoundTag()));
            le.putByte("ItemRotation", (byte)this.getRotation());
            le.putFloat("ItemDropChance", this.dropChance);
        }
        le.putByte("Facing", (byte)this.direction.get3DDataValue());
        le.putBoolean("Invisible", this.isInvisible());
        le.putBoolean("Fixed", this.fixed);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        final CompoundTag le2 = le.getCompound("Item");
        if (le2 != null && !le2.isEmpty()) {
            final ItemStack bki4 = ItemStack.of(le2);
            if (bki4.isEmpty()) {
                ItemFrame.LOGGER.warn("Unable to load item from: {}", le2);
            }
            final ItemStack bki5 = this.getItem();
            if (!bki5.isEmpty() && !ItemStack.matches(bki4, bki5)) {
                this.removeFramedMap(bki5);
            }
            this.setItem(bki4, false);
            this.setRotation(le.getByte("ItemRotation"), false);
            if (le.contains("ItemDropChance", 99)) {
                this.dropChance = le.getFloat("ItemDropChance");
            }
        }
        this.setDirection(Direction.from3DDataValue(le.getByte("Facing")));
        this.setInvisible(le.getBoolean("Invisible"));
        this.fixed = le.getBoolean("Fixed");
    }
    
    @Override
    public InteractionResult interact(final Player bec, final InteractionHand anf) {
        final ItemStack bki4 = bec.getItemInHand(anf);
        final boolean boolean5 = !this.getItem().isEmpty();
        final boolean boolean6 = !bki4.isEmpty();
        if (this.fixed) {
            return InteractionResult.PASS;
        }
        if (this.level.isClientSide) {
            return (boolean5 || boolean6) ? InteractionResult.SUCCESS : InteractionResult.PASS;
        }
        if (!boolean5) {
            if (boolean6 && !this.removed) {
                this.setItem(bki4);
                if (!bec.abilities.instabuild) {
                    bki4.shrink(1);
                }
            }
        }
        else {
            this.playSound(SoundEvents.ITEM_FRAME_ROTATE_ITEM, 1.0f, 1.0f);
            this.setRotation(this.getRotation() + 1);
        }
        return InteractionResult.CONSUME;
    }
    
    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);
    }
}
