package net.minecraft.world.level.block.piston;

import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.properties.PistonType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.item.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.DirectionalBlock;

public class PistonBaseBlock extends DirectionalBlock {
    public static final BooleanProperty EXTENDED;
    protected static final VoxelShape EAST_AABB;
    protected static final VoxelShape WEST_AABB;
    protected static final VoxelShape SOUTH_AABB;
    protected static final VoxelShape NORTH_AABB;
    protected static final VoxelShape UP_AABB;
    protected static final VoxelShape DOWN_AABB;
    private final boolean isSticky;
    
    public PistonBaseBlock(final boolean boolean1, final Properties c) {
        super(c);
        this.registerDefaultState((((StateHolder<O, BlockState>)this.stateDefinition.any()).setValue((Property<Comparable>)PistonBaseBlock.FACING, Direction.NORTH)).<Comparable, Boolean>setValue((Property<Comparable>)PistonBaseBlock.EXTENDED, false));
        this.isSticky = boolean1;
    }
    
    @Override
    public VoxelShape getShape(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final CollisionContext der) {
        if (!cfj.<Boolean>getValue((Property<Boolean>)PistonBaseBlock.EXTENDED)) {
            return Shapes.block();
        }
        switch (cfj.<Direction>getValue((Property<Direction>)PistonBaseBlock.FACING)) {
            case DOWN: {
                return PistonBaseBlock.DOWN_AABB;
            }
            default: {
                return PistonBaseBlock.UP_AABB;
            }
            case NORTH: {
                return PistonBaseBlock.NORTH_AABB;
            }
            case SOUTH: {
                return PistonBaseBlock.SOUTH_AABB;
            }
            case WEST: {
                return PistonBaseBlock.WEST_AABB;
            }
            case EAST: {
                return PistonBaseBlock.EAST_AABB;
            }
        }
    }
    
    @Override
    public void setPlacedBy(final Level bqb, final BlockPos fu, final BlockState cfj, final LivingEntity aoy, final ItemStack bki) {
        if (!bqb.isClientSide) {
            this.checkIfExtend(bqb, fu, cfj);
        }
    }
    
    @Override
    public void neighborChanged(final BlockState cfj, final Level bqb, final BlockPos fu3, final Block bvr, final BlockPos fu5, final boolean boolean6) {
        if (!bqb.isClientSide) {
            this.checkIfExtend(bqb, fu3, cfj);
        }
    }
    
    @Override
    public void onPlace(final BlockState cfj1, final Level bqb, final BlockPos fu, final BlockState cfj4, final boolean boolean5) {
        if (cfj4.is(cfj1.getBlock())) {
            return;
        }
        if (!bqb.isClientSide && bqb.getBlockEntity(fu) == null) {
            this.checkIfExtend(bqb, fu, cfj1);
        }
    }
    
    @Override
    public BlockState getStateForPlacement(final BlockPlaceContext bin) {
        return (((StateHolder<O, BlockState>)this.defaultBlockState()).setValue((Property<Comparable>)PistonBaseBlock.FACING, bin.getNearestLookingDirection().getOpposite())).<Comparable, Boolean>setValue((Property<Comparable>)PistonBaseBlock.EXTENDED, false);
    }
    
    private void checkIfExtend(final Level bqb, final BlockPos fu, final BlockState cfj) {
        final Direction fz5 = cfj.<Direction>getValue((Property<Direction>)PistonBaseBlock.FACING);
        final boolean boolean6 = this.getNeighborSignal(bqb, fu, fz5);
        if (boolean6 && !cfj.<Boolean>getValue((Property<Boolean>)PistonBaseBlock.EXTENDED)) {
            if (new PistonStructureResolver(bqb, fu, fz5, true).resolve()) {
                bqb.blockEvent(fu, this, 0, fz5.get3DDataValue());
            }
        }
        else if (!boolean6 && cfj.<Boolean>getValue((Property<Boolean>)PistonBaseBlock.EXTENDED)) {
            final BlockPos fu2 = fu.relative(fz5, 2);
            final BlockState cfj2 = bqb.getBlockState(fu2);
            int integer9 = 1;
            if (cfj2.is(Blocks.MOVING_PISTON) && cfj2.<Comparable>getValue((Property<Comparable>)PistonBaseBlock.FACING) == fz5) {
                final BlockEntity cdl10 = bqb.getBlockEntity(fu2);
                if (cdl10 instanceof PistonMovingBlockEntity) {
                    final PistonMovingBlockEntity cff11 = (PistonMovingBlockEntity)cdl10;
                    if (cff11.isExtending() && (cff11.getProgress(0.0f) < 0.5f || bqb.getGameTime() == cff11.getLastTicked() || ((ServerLevel)bqb).isHandlingTick())) {
                        integer9 = 2;
                    }
                }
            }
            bqb.blockEvent(fu, this, integer9, fz5.get3DDataValue());
        }
    }
    
    private boolean getNeighborSignal(final Level bqb, final BlockPos fu, final Direction fz) {
        for (final Direction fz2 : Direction.values()) {
            if (fz2 != fz && bqb.hasSignal(fu.relative(fz2), fz2)) {
                return true;
            }
        }
        if (bqb.hasSignal(fu, Direction.DOWN)) {
            return true;
        }
        final BlockPos fu2 = fu.above();
        for (final Direction fz3 : Direction.values()) {
            if (fz3 != Direction.DOWN && bqb.hasSignal(fu2.relative(fz3), fz3)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean triggerEvent(final BlockState cfj, final Level bqb, final BlockPos fu, final int integer4, final int integer5) {
        final Direction fz7 = cfj.<Direction>getValue((Property<Direction>)PistonBaseBlock.FACING);
        if (!bqb.isClientSide) {
            final boolean boolean8 = this.getNeighborSignal(bqb, fu, fz7);
            if (boolean8 && (integer4 == 1 || integer4 == 2)) {
                bqb.setBlock(fu, ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)PistonBaseBlock.EXTENDED, true), 2);
                return false;
            }
            if (!boolean8 && integer4 == 0) {
                return false;
            }
        }
        if (integer4 == 0) {
            if (!this.moveBlocks(bqb, fu, fz7, true)) {
                return false;
            }
            bqb.setBlock(fu, ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)PistonBaseBlock.EXTENDED, true), 67);
            bqb.playSound(null, fu, SoundEvents.PISTON_EXTEND, SoundSource.BLOCKS, 0.5f, bqb.random.nextFloat() * 0.25f + 0.6f);
        }
        else if (integer4 == 1 || integer4 == 2) {
            final BlockEntity cdl8 = bqb.getBlockEntity(fu.relative(fz7));
            if (cdl8 instanceof PistonMovingBlockEntity) {
                ((PistonMovingBlockEntity)cdl8).finalTick();
            }
            final BlockState cfj2 = (((StateHolder<O, BlockState>)Blocks.MOVING_PISTON.defaultBlockState()).setValue((Property<Comparable>)MovingPistonBlock.FACING, fz7)).<PistonType, PistonType>setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
            bqb.setBlock(fu, cfj2, 20);
            bqb.setBlockEntity(fu, MovingPistonBlock.newMovingBlockEntity(((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Direction>setValue((Property<Comparable>)PistonBaseBlock.FACING, Direction.from3DDataValue(integer5 & 0x7)), fz7, false, true));
            bqb.blockUpdated(fu, cfj2.getBlock());
            cfj2.updateNeighbourShapes(bqb, fu, 2);
            if (this.isSticky) {
                final BlockPos fu2 = fu.offset(fz7.getStepX() * 2, fz7.getStepY() * 2, fz7.getStepZ() * 2);
                final BlockState cfj3 = bqb.getBlockState(fu2);
                boolean boolean9 = false;
                if (cfj3.is(Blocks.MOVING_PISTON)) {
                    final BlockEntity cdl9 = bqb.getBlockEntity(fu2);
                    if (cdl9 instanceof PistonMovingBlockEntity) {
                        final PistonMovingBlockEntity cff14 = (PistonMovingBlockEntity)cdl9;
                        if (cff14.getDirection() == fz7 && cff14.isExtending()) {
                            cff14.finalTick();
                            boolean9 = true;
                        }
                    }
                }
                if (!boolean9) {
                    if (integer4 == 1 && !cfj3.isAir() && isPushable(cfj3, bqb, fu2, fz7.getOpposite(), false, fz7) && (cfj3.getPistonPushReaction() == PushReaction.NORMAL || cfj3.is(Blocks.PISTON) || cfj3.is(Blocks.STICKY_PISTON))) {
                        this.moveBlocks(bqb, fu, fz7, false);
                    }
                    else {
                        bqb.removeBlock(fu.relative(fz7), false);
                    }
                }
            }
            else {
                bqb.removeBlock(fu.relative(fz7), false);
            }
            bqb.playSound(null, fu, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5f, bqb.random.nextFloat() * 0.15f + 0.6f);
        }
        return true;
    }
    
    public static boolean isPushable(final BlockState cfj, final Level bqb, final BlockPos fu, final Direction fz4, final boolean boolean5, final Direction fz6) {
        if (cfj.is(Blocks.OBSIDIAN) || cfj.is(Blocks.CRYING_OBSIDIAN) || cfj.is(Blocks.RESPAWN_ANCHOR)) {
            return false;
        }
        if (!bqb.getWorldBorder().isWithinBounds(fu)) {
            return false;
        }
        if (fu.getY() < 0 || (fz4 == Direction.DOWN && fu.getY() == 0)) {
            return false;
        }
        if (fu.getY() > bqb.getMaxBuildHeight() - 1 || (fz4 == Direction.UP && fu.getY() == bqb.getMaxBuildHeight() - 1)) {
            return false;
        }
        if (cfj.is(Blocks.PISTON) || cfj.is(Blocks.STICKY_PISTON)) {
            if (cfj.<Boolean>getValue((Property<Boolean>)PistonBaseBlock.EXTENDED)) {
                return false;
            }
        }
        else {
            if (cfj.getDestroySpeed(bqb, fu) == -1.0f) {
                return false;
            }
            switch (cfj.getPistonPushReaction()) {
                case BLOCK: {
                    return false;
                }
                case DESTROY: {
                    return boolean5;
                }
                case PUSH_ONLY: {
                    return fz4 == fz6;
                }
            }
        }
        return !cfj.getBlock().isEntityBlock();
    }
    
    private boolean moveBlocks(final Level bqb, final BlockPos fu, final Direction fz, final boolean boolean4) {
        final BlockPos fu2 = fu.relative(fz);
        if (!boolean4 && bqb.getBlockState(fu2).is(Blocks.PISTON_HEAD)) {
            bqb.setBlock(fu2, Blocks.AIR.defaultBlockState(), 20);
        }
        final PistonStructureResolver cfg7 = new PistonStructureResolver(bqb, fu, fz, boolean4);
        if (!cfg7.resolve()) {
            return false;
        }
        final Map<BlockPos, BlockState> map8 = Maps.newHashMap();
        final List<BlockPos> list9 = cfg7.getToPush();
        final List<BlockState> list10 = Lists.newArrayList();
        for (int integer11 = 0; integer11 < list9.size(); ++integer11) {
            final BlockPos fu3 = list9.get(integer11);
            final BlockState cfj13 = bqb.getBlockState(fu3);
            list10.add(cfj13);
            map8.put(fu3, cfj13);
        }
        final List<BlockPos> list11 = cfg7.getToDestroy();
        final BlockState[] arr12 = new BlockState[list9.size() + list11.size()];
        final Direction fz2 = boolean4 ? fz : fz.getOpposite();
        int integer12 = 0;
        for (int integer13 = list11.size() - 1; integer13 >= 0; --integer13) {
            final BlockPos fu4 = list11.get(integer13);
            final BlockState cfj14 = bqb.getBlockState(fu4);
            final BlockEntity cdl18 = cfj14.getBlock().isEntityBlock() ? bqb.getBlockEntity(fu4) : null;
            Block.dropResources(cfj14, bqb, fu4, cdl18);
            bqb.setBlock(fu4, Blocks.AIR.defaultBlockState(), 18);
            arr12[integer12++] = cfj14;
        }
        for (int integer13 = list9.size() - 1; integer13 >= 0; --integer13) {
            BlockPos fu4 = list9.get(integer13);
            final BlockState cfj14 = bqb.getBlockState(fu4);
            fu4 = fu4.relative(fz2);
            map8.remove(fu4);
            bqb.setBlock(fu4, ((StateHolder<O, BlockState>)Blocks.MOVING_PISTON.defaultBlockState()).<Comparable, Direction>setValue((Property<Comparable>)PistonBaseBlock.FACING, fz), 68);
            bqb.setBlockEntity(fu4, MovingPistonBlock.newMovingBlockEntity(list10.get(integer13), fz, boolean4, false));
            arr12[integer12++] = cfj14;
        }
        if (boolean4) {
            final PistonType cgk15 = this.isSticky ? PistonType.STICKY : PistonType.DEFAULT;
            final BlockState cfj15 = (((StateHolder<O, BlockState>)Blocks.PISTON_HEAD.defaultBlockState()).setValue((Property<Comparable>)PistonHeadBlock.FACING, fz)).<PistonType, PistonType>setValue(PistonHeadBlock.TYPE, cgk15);
            final BlockState cfj14 = (((StateHolder<O, BlockState>)Blocks.MOVING_PISTON.defaultBlockState()).setValue((Property<Comparable>)MovingPistonBlock.FACING, fz)).<PistonType, PistonType>setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
            map8.remove(fu2);
            bqb.setBlock(fu2, cfj14, 68);
            bqb.setBlockEntity(fu2, MovingPistonBlock.newMovingBlockEntity(cfj15, fz, true, true));
        }
        final BlockState cfj16 = Blocks.AIR.defaultBlockState();
        for (final BlockPos fu5 : map8.keySet()) {
            bqb.setBlock(fu5, cfj16, 82);
        }
        for (final Map.Entry<BlockPos, BlockState> entry17 : map8.entrySet()) {
            final BlockPos fu6 = entry17.getKey();
            final BlockState cfj17 = entry17.getValue();
            cfj17.updateIndirectNeighbourShapes(bqb, fu6, 2);
            cfj16.updateNeighbourShapes(bqb, fu6, 2);
            cfj16.updateIndirectNeighbourShapes(bqb, fu6, 2);
        }
        integer12 = 0;
        for (int integer14 = list11.size() - 1; integer14 >= 0; --integer14) {
            final BlockState cfj14 = arr12[integer12++];
            final BlockPos fu6 = list11.get(integer14);
            cfj14.updateIndirectNeighbourShapes(bqb, fu6, 2);
            bqb.updateNeighborsAt(fu6, cfj14.getBlock());
        }
        for (int integer14 = list9.size() - 1; integer14 >= 0; --integer14) {
            bqb.updateNeighborsAt(list9.get(integer14), arr12[integer12++].getBlock());
        }
        if (boolean4) {
            bqb.updateNeighborsAt(fu2, Blocks.PISTON_HEAD);
        }
        return true;
    }
    
    @Override
    public BlockState rotate(final BlockState cfj, final Rotation cap) {
        return ((StateHolder<O, BlockState>)cfj).<Comparable, Direction>setValue((Property<Comparable>)PistonBaseBlock.FACING, cap.rotate(cfj.<Direction>getValue((Property<Direction>)PistonBaseBlock.FACING)));
    }
    
    @Override
    public BlockState mirror(final BlockState cfj, final Mirror bzj) {
        return cfj.rotate(bzj.getRotation(cfj.<Direction>getValue((Property<Direction>)PistonBaseBlock.FACING)));
    }
    
    @Override
    protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> a) {
        a.add(PistonBaseBlock.FACING, PistonBaseBlock.EXTENDED);
    }
    
    @Override
    public boolean useShapeForLightOcclusion(final BlockState cfj) {
        return cfj.<Boolean>getValue((Property<Boolean>)PistonBaseBlock.EXTENDED);
    }
    
    @Override
    public boolean isPathfindable(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final PathComputationType czg) {
        return false;
    }
    
    static {
        EXTENDED = BlockStateProperties.EXTENDED;
        EAST_AABB = Block.box(0.0, 0.0, 0.0, 12.0, 16.0, 16.0);
        WEST_AABB = Block.box(4.0, 0.0, 0.0, 16.0, 16.0, 16.0);
        SOUTH_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 16.0, 12.0);
        NORTH_AABB = Block.box(0.0, 0.0, 4.0, 16.0, 16.0, 16.0);
        UP_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 12.0, 16.0);
        DOWN_AABB = Block.box(0.0, 4.0, 0.0, 16.0, 16.0, 16.0);
    }
}
