package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.StateHolder;
import java.util.stream.Collector;
import net.minecraft.Util;
import net.minecraft.world.level.block.state.StateDefinition;
import javax.annotation.Nullable;
import net.minecraft.world.item.BlockPlaceContext;
import java.util.Random;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
import java.util.Iterator;
import net.minecraft.world.level.LevelReader;
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.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.core.Direction;
import java.util.Map;
import net.minecraft.world.level.block.state.properties.BooleanProperty;

public class VineBlock extends Block {
    public static final BooleanProperty UP;
    public static final BooleanProperty NORTH;
    public static final BooleanProperty EAST;
    public static final BooleanProperty SOUTH;
    public static final BooleanProperty WEST;
    public static final Map<Direction, BooleanProperty> PROPERTY_BY_DIRECTION;
    protected static final VoxelShape UP_AABB;
    protected static final VoxelShape EAST_AABB;
    protected static final VoxelShape WEST_AABB;
    protected static final VoxelShape SOUTH_AABB;
    protected static final VoxelShape NORTH_AABB;
    
    public VineBlock(final Properties c) {
        super(c);
        this.registerDefaultState(((((((StateHolder<O, BlockState>)this.stateDefinition.any()).setValue((Property<Comparable>)VineBlock.UP, false)).setValue((Property<Comparable>)VineBlock.NORTH, false)).setValue((Property<Comparable>)VineBlock.EAST, false)).setValue((Property<Comparable>)VineBlock.SOUTH, false)).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.WEST, false));
    }
    
    @Override
    public VoxelShape getShape(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final CollisionContext der) {
        VoxelShape dfg6 = Shapes.empty();
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.UP)) {
            dfg6 = Shapes.or(dfg6, VineBlock.UP_AABB);
        }
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.NORTH)) {
            dfg6 = Shapes.or(dfg6, VineBlock.SOUTH_AABB);
        }
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.EAST)) {
            dfg6 = Shapes.or(dfg6, VineBlock.WEST_AABB);
        }
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.SOUTH)) {
            dfg6 = Shapes.or(dfg6, VineBlock.NORTH_AABB);
        }
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.WEST)) {
            dfg6 = Shapes.or(dfg6, VineBlock.EAST_AABB);
        }
        return dfg6;
    }
    
    @Override
    public boolean canSurvive(final BlockState cfj, final LevelReader bqd, final BlockPos fu) {
        return this.hasFaces(this.getUpdatedState(cfj, bqd, fu));
    }
    
    private boolean hasFaces(final BlockState cfj) {
        return this.countFaces(cfj) > 0;
    }
    
    private int countFaces(final BlockState cfj) {
        int integer3 = 0;
        for (final BooleanProperty cga5 : VineBlock.PROPERTY_BY_DIRECTION.values()) {
            if (cfj.<Boolean>getValue((Property<Boolean>)cga5)) {
                ++integer3;
            }
        }
        return integer3;
    }
    
    private boolean canSupportAtFace(final BlockGetter bpg, final BlockPos fu, final Direction fz) {
        if (fz == Direction.DOWN) {
            return false;
        }
        final BlockPos fu2 = fu.relative(fz);
        if (isAcceptableNeighbour(bpg, fu2, fz)) {
            return true;
        }
        if (fz.getAxis() != Direction.Axis.Y) {
            final BooleanProperty cga6 = VineBlock.PROPERTY_BY_DIRECTION.get(fz);
            final BlockState cfj7 = bpg.getBlockState(fu.above());
            return cfj7.is(this) && cfj7.<Boolean>getValue((Property<Boolean>)cga6);
        }
        return false;
    }
    
    public static boolean isAcceptableNeighbour(final BlockGetter bpg, final BlockPos fu, final Direction fz) {
        final BlockState cfj4 = bpg.getBlockState(fu);
        return Block.isFaceFull(cfj4.getCollisionShape(bpg, fu), fz.getOpposite());
    }
    
    private BlockState getUpdatedState(BlockState cfj, final BlockGetter bpg, final BlockPos fu) {
        final BlockPos fu2 = fu.above();
        if (cfj.<Boolean>getValue((Property<Boolean>)VineBlock.UP)) {
            cfj = ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, isAcceptableNeighbour(bpg, fu2, Direction.DOWN));
        }
        BlockState cfj2 = null;
        for (final Direction fz8 : Direction.Plane.HORIZONTAL) {
            final BooleanProperty cga9 = getPropertyForFace(fz8);
            if (cfj.<Boolean>getValue((Property<Boolean>)cga9)) {
                boolean boolean10 = this.canSupportAtFace(bpg, fu, fz8);
                if (!boolean10) {
                    if (cfj2 == null) {
                        cfj2 = bpg.getBlockState(fu2);
                    }
                    boolean10 = (cfj2.is(this) && cfj2.<Boolean>getValue((Property<Boolean>)cga9));
                }
                cfj = ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)cga9, boolean10);
            }
        }
        return cfj;
    }
    
    @Override
    public BlockState updateShape(final BlockState cfj1, final Direction fz, final BlockState cfj3, final LevelAccessor bqc, final BlockPos fu5, final BlockPos fu6) {
        if (fz == Direction.DOWN) {
            return super.updateShape(cfj1, fz, cfj3, bqc, fu5, fu6);
        }
        final BlockState cfj4 = this.getUpdatedState(cfj1, bqc, fu5);
        if (!this.hasFaces(cfj4)) {
            return Blocks.AIR.defaultBlockState();
        }
        return cfj4;
    }
    
    @Override
    public void randomTick(final BlockState cfj, final ServerLevel zd, final BlockPos fu, final Random random) {
        if (zd.random.nextInt(4) != 0) {
            return;
        }
        final Direction fz6 = Direction.getRandom(random);
        final BlockPos fu2 = fu.above();
        if (!fz6.getAxis().isHorizontal() || cfj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fz6))) {
            if (fz6 == Direction.UP && fu.getY() < 255) {
                if (this.canSupportAtFace(zd, fu, fz6)) {
                    zd.setBlock(fu, ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, true), 2);
                    return;
                }
                if (zd.isEmptyBlock(fu2)) {
                    if (!this.canSpread(zd, fu)) {
                        return;
                    }
                    BlockState cfj2 = cfj;
                    for (final Direction fz7 : Direction.Plane.HORIZONTAL) {
                        if (random.nextBoolean() || !isAcceptableNeighbour(zd, fu2.relative(fz7), Direction.UP)) {
                            cfj2 = ((StateHolder<O, BlockState>)cfj2).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz7), false);
                        }
                    }
                    if (this.hasHorizontalConnection(cfj2)) {
                        zd.setBlock(fu2, cfj2, 2);
                    }
                    return;
                }
            }
            if (fu.getY() > 0) {
                final BlockPos fu3 = fu.below();
                final BlockState cfj3 = zd.getBlockState(fu3);
                if (cfj3.isAir() || cfj3.is(this)) {
                    final BlockState cfj4 = cfj3.isAir() ? this.defaultBlockState() : cfj3;
                    final BlockState cfj5 = this.copyRandomFaces(cfj, cfj4, random);
                    if (cfj4 != cfj5 && this.hasHorizontalConnection(cfj5)) {
                        zd.setBlock(fu3, cfj5, 2);
                    }
                }
            }
            return;
        }
        if (!this.canSpread(zd, fu)) {
            return;
        }
        final BlockPos fu3 = fu.relative(fz6);
        final BlockState cfj3 = zd.getBlockState(fu3);
        if (cfj3.isAir()) {
            final Direction fz7 = fz6.getClockWise();
            final Direction fz8 = fz6.getCounterClockWise();
            final boolean boolean12 = cfj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fz7));
            final boolean boolean13 = cfj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fz8));
            final BlockPos fu4 = fu3.relative(fz7);
            final BlockPos fu5 = fu3.relative(fz8);
            if (boolean12 && isAcceptableNeighbour(zd, fu4, fz7)) {
                zd.setBlock(fu3, ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz7), true), 2);
            }
            else if (boolean13 && isAcceptableNeighbour(zd, fu5, fz8)) {
                zd.setBlock(fu3, ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz8), true), 2);
            }
            else {
                final Direction fz9 = fz6.getOpposite();
                if (boolean12 && zd.isEmptyBlock(fu4) && isAcceptableNeighbour(zd, fu.relative(fz7), fz9)) {
                    zd.setBlock(fu4, ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz9), true), 2);
                }
                else if (boolean13 && zd.isEmptyBlock(fu5) && isAcceptableNeighbour(zd, fu.relative(fz8), fz9)) {
                    zd.setBlock(fu5, ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz9), true), 2);
                }
                else if (zd.random.nextFloat() < 0.05 && isAcceptableNeighbour(zd, fu3.above(), Direction.UP)) {
                    zd.setBlock(fu3, ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, true), 2);
                }
            }
        }
        else if (isAcceptableNeighbour(zd, fu3, fz6)) {
            zd.setBlock(fu, ((StateHolder<O, BlockState>)cfj).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fz6), true), 2);
        }
    }
    
    private BlockState copyRandomFaces(final BlockState cfj1, BlockState cfj2, final Random random) {
        for (final Direction fz6 : Direction.Plane.HORIZONTAL) {
            if (random.nextBoolean()) {
                final BooleanProperty cga7 = getPropertyForFace(fz6);
                if (!cfj1.<Boolean>getValue((Property<Boolean>)cga7)) {
                    continue;
                }
                cfj2 = ((StateHolder<O, BlockState>)cfj2).<Comparable, Boolean>setValue((Property<Comparable>)cga7, true);
            }
        }
        return cfj2;
    }
    
    private boolean hasHorizontalConnection(final BlockState cfj) {
        return cfj.<Boolean>getValue((Property<Boolean>)VineBlock.NORTH) || cfj.<Boolean>getValue((Property<Boolean>)VineBlock.EAST) || cfj.<Boolean>getValue((Property<Boolean>)VineBlock.SOUTH) || cfj.<Boolean>getValue((Property<Boolean>)VineBlock.WEST);
    }
    
    private boolean canSpread(final BlockGetter bpg, final BlockPos fu) {
        final int integer4 = 4;
        final Iterable<BlockPos> iterable5 = BlockPos.betweenClosed(fu.getX() - 4, fu.getY() - 1, fu.getZ() - 4, fu.getX() + 4, fu.getY() + 1, fu.getZ() + 4);
        int integer5 = 5;
        for (final BlockPos fu2 : iterable5) {
            if (bpg.getBlockState(fu2).is(this) && --integer5 <= 0) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public boolean canBeReplaced(final BlockState cfj, final BlockPlaceContext bin) {
        final BlockState cfj2 = bin.getLevel().getBlockState(bin.getClickedPos());
        if (cfj2.is(this)) {
            return this.countFaces(cfj2) < VineBlock.PROPERTY_BY_DIRECTION.size();
        }
        return super.canBeReplaced(cfj, bin);
    }
    
    @Nullable
    @Override
    public BlockState getStateForPlacement(final BlockPlaceContext bin) {
        final BlockState cfj3 = bin.getLevel().getBlockState(bin.getClickedPos());
        final boolean boolean4 = cfj3.is(this);
        final BlockState cfj4 = boolean4 ? cfj3 : this.defaultBlockState();
        for (final Direction fz9 : bin.getNearestLookingDirections()) {
            if (fz9 != Direction.DOWN) {
                final BooleanProperty cga10 = getPropertyForFace(fz9);
                final boolean boolean5 = boolean4 && cfj3.<Boolean>getValue((Property<Boolean>)cga10);
                if (!boolean5 && this.canSupportAtFace(bin.getLevel(), bin.getClickedPos(), fz9)) {
                    return ((StateHolder<O, BlockState>)cfj4).<Comparable, Boolean>setValue((Property<Comparable>)cga10, true);
                }
            }
        }
        return boolean4 ? cfj4 : null;
    }
    
    @Override
    protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> a) {
        a.add(VineBlock.UP, VineBlock.NORTH, VineBlock.EAST, VineBlock.SOUTH, VineBlock.WEST);
    }
    
    @Override
    public BlockState rotate(final BlockState cfj, final Rotation cap) {
        switch (cap) {
            case CLOCKWISE_180: {
                return (((((StateHolder<O, BlockState>)cfj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.SOUTH))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.WEST))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.NORTH))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.EAST));
            }
            case COUNTERCLOCKWISE_90: {
                return (((((StateHolder<O, BlockState>)cfj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.EAST))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.SOUTH))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.WEST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.NORTH));
            }
            case CLOCKWISE_90: {
                return (((((StateHolder<O, BlockState>)cfj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.WEST))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.NORTH))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.EAST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.SOUTH));
            }
            default: {
                return cfj;
            }
        }
    }
    
    @Override
    public BlockState mirror(final BlockState cfj, final Mirror bzj) {
        switch (bzj) {
            case LEFT_RIGHT: {
                return (((StateHolder<O, BlockState>)cfj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.SOUTH))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.NORTH));
            }
            case FRONT_BACK: {
                return (((StateHolder<O, BlockState>)cfj).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.WEST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)cfj.<V>getValue((Property<V>)VineBlock.EAST));
            }
            default: {
                return super.mirror(cfj, bzj);
            }
        }
    }
    
    public static BooleanProperty getPropertyForFace(final Direction fz) {
        return VineBlock.PROPERTY_BY_DIRECTION.get(fz);
    }
    
    static {
        UP = PipeBlock.UP;
        NORTH = PipeBlock.NORTH;
        EAST = PipeBlock.EAST;
        SOUTH = PipeBlock.SOUTH;
        WEST = PipeBlock.WEST;
        PROPERTY_BY_DIRECTION = PipeBlock.PROPERTY_BY_DIRECTION.entrySet().stream().filter(entry -> entry.getKey() != Direction.DOWN).collect(Util.<Direction, BooleanProperty>toMap());
        UP_AABB = Block.box(0.0, 15.0, 0.0, 16.0, 16.0, 16.0);
        EAST_AABB = Block.box(0.0, 0.0, 0.0, 1.0, 16.0, 16.0);
        WEST_AABB = Block.box(15.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, 1.0);
        NORTH_AABB = Block.box(0.0, 0.0, 15.0, 16.0, 16.0, 16.0);
    }
}
