package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.AbstractStateHolder;
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 net.minecraft.world.level.Level;
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.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(((((((AbstractStateHolder<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 byj, final BlockGetter bjg, final BlockPos fk, final CollisionContext cvq) {
        VoxelShape cwf6 = Shapes.empty();
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.UP)) {
            cwf6 = Shapes.or(cwf6, VineBlock.UP_AABB);
        }
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.NORTH)) {
            cwf6 = Shapes.or(cwf6, VineBlock.SOUTH_AABB);
        }
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.EAST)) {
            cwf6 = Shapes.or(cwf6, VineBlock.WEST_AABB);
        }
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.SOUTH)) {
            cwf6 = Shapes.or(cwf6, VineBlock.NORTH_AABB);
        }
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.WEST)) {
            cwf6 = Shapes.or(cwf6, VineBlock.EAST_AABB);
        }
        return cwf6;
    }
    
    @Override
    public boolean canSurvive(final BlockState byj, final LevelReader bjz, final BlockPos fk) {
        return this.hasFaces(this.getUpdatedState(byj, bjz, fk));
    }
    
    private boolean hasFaces(final BlockState byj) {
        return this.countFaces(byj) > 0;
    }
    
    private int countFaces(final BlockState byj) {
        int integer3 = 0;
        for (final BooleanProperty bzb5 : VineBlock.PROPERTY_BY_DIRECTION.values()) {
            if (byj.<Boolean>getValue((Property<Boolean>)bzb5)) {
                ++integer3;
            }
        }
        return integer3;
    }
    
    private boolean canSupportAtFace(final BlockGetter bjg, final BlockPos fk, final Direction fp) {
        if (fp == Direction.DOWN) {
            return false;
        }
        final BlockPos fk2 = fk.relative(fp);
        if (isAcceptableNeighbour(bjg, fk2, fp)) {
            return true;
        }
        if (fp.getAxis() != Direction.Axis.Y) {
            final BooleanProperty bzb6 = VineBlock.PROPERTY_BY_DIRECTION.get(fp);
            final BlockState byj7 = bjg.getBlockState(fk.above());
            return byj7.getBlock() == this && byj7.<Boolean>getValue((Property<Boolean>)bzb6);
        }
        return false;
    }
    
    public static boolean isAcceptableNeighbour(final BlockGetter bjg, final BlockPos fk, final Direction fp) {
        final BlockState byj4 = bjg.getBlockState(fk);
        return Block.isFaceFull(byj4.getCollisionShape(bjg, fk), fp.getOpposite());
    }
    
    private BlockState getUpdatedState(BlockState byj, final BlockGetter bjg, final BlockPos fk) {
        final BlockPos fk2 = fk.above();
        if (byj.<Boolean>getValue((Property<Boolean>)VineBlock.UP)) {
            byj = ((AbstractStateHolder<O, BlockState>)byj).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, isAcceptableNeighbour(bjg, fk2, Direction.DOWN));
        }
        BlockState byj2 = null;
        for (final Direction fp8 : Direction.Plane.HORIZONTAL) {
            final BooleanProperty bzb9 = getPropertyForFace(fp8);
            if (byj.<Boolean>getValue((Property<Boolean>)bzb9)) {
                boolean boolean10 = this.canSupportAtFace(bjg, fk, fp8);
                if (!boolean10) {
                    if (byj2 == null) {
                        byj2 = bjg.getBlockState(fk2);
                    }
                    boolean10 = (byj2.getBlock() == this && byj2.<Boolean>getValue((Property<Boolean>)bzb9));
                }
                byj = ((AbstractStateHolder<O, BlockState>)byj).<Comparable, Boolean>setValue((Property<Comparable>)bzb9, boolean10);
            }
        }
        return byj;
    }
    
    @Override
    public BlockState updateShape(final BlockState byj1, final Direction fp, final BlockState byj3, final LevelAccessor bjx, final BlockPos fk5, final BlockPos fk6) {
        if (fp == Direction.DOWN) {
            return super.updateShape(byj1, fp, byj3, bjx, fk5, fk6);
        }
        final BlockState byj4 = this.getUpdatedState(byj1, bjx, fk5);
        if (!this.hasFaces(byj4)) {
            return Blocks.AIR.defaultBlockState();
        }
        return byj4;
    }
    
    @Override
    public void tick(final BlockState byj, final ServerLevel xd, final BlockPos fk, final Random random) {
        final BlockState byj2 = this.getUpdatedState(byj, xd, fk);
        if (byj2 != byj) {
            if (this.hasFaces(byj2)) {
                xd.setBlock(fk, byj2, 2);
            }
            else {
                Block.dropResources(byj, xd, fk);
                xd.removeBlock(fk, false);
            }
            return;
        }
        if (xd.random.nextInt(4) != 0) {
            return;
        }
        final Direction fp7 = Direction.getRandomFace(random);
        final BlockPos fk2 = fk.above();
        if (!fp7.getAxis().isHorizontal() || byj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fp7))) {
            if (fp7 == Direction.UP && fk.getY() < 255) {
                if (this.canSupportAtFace(xd, fk, fp7)) {
                    xd.setBlock(fk, ((AbstractStateHolder<O, BlockState>)byj).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, true), 2);
                    return;
                }
                if (xd.isEmptyBlock(fk2)) {
                    if (!this.canSpread(xd, fk)) {
                        return;
                    }
                    BlockState byj3 = byj;
                    for (final Direction fp8 : Direction.Plane.HORIZONTAL) {
                        if (random.nextBoolean() || !isAcceptableNeighbour(xd, fk2.relative(fp8), Direction.UP)) {
                            byj3 = ((AbstractStateHolder<O, BlockState>)byj3).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp8), false);
                        }
                    }
                    if (this.hasHorizontalConnection(byj3)) {
                        xd.setBlock(fk2, byj3, 2);
                    }
                    return;
                }
            }
            if (fk.getY() > 0) {
                final BlockPos fk3 = fk.below();
                final BlockState byj4 = xd.getBlockState(fk3);
                if (byj4.isAir() || byj4.getBlock() == this) {
                    final BlockState byj5 = byj4.isAir() ? this.defaultBlockState() : byj4;
                    final BlockState byj6 = this.copyRandomFaces(byj, byj5, random);
                    if (byj5 != byj6 && this.hasHorizontalConnection(byj6)) {
                        xd.setBlock(fk3, byj6, 2);
                    }
                }
            }
            return;
        }
        if (!this.canSpread(xd, fk)) {
            return;
        }
        final BlockPos fk3 = fk.relative(fp7);
        final BlockState byj4 = xd.getBlockState(fk3);
        if (byj4.isAir()) {
            final Direction fp8 = fp7.getClockWise();
            final Direction fp9 = fp7.getCounterClockWise();
            final boolean boolean13 = byj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fp8));
            final boolean boolean14 = byj.<Boolean>getValue((Property<Boolean>)getPropertyForFace(fp9));
            final BlockPos fk4 = fk3.relative(fp8);
            final BlockPos fk5 = fk3.relative(fp9);
            if (boolean13 && isAcceptableNeighbour(xd, fk4, fp8)) {
                xd.setBlock(fk3, ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp8), true), 2);
            }
            else if (boolean14 && isAcceptableNeighbour(xd, fk5, fp9)) {
                xd.setBlock(fk3, ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp9), true), 2);
            }
            else {
                final Direction fp10 = fp7.getOpposite();
                if (boolean13 && xd.isEmptyBlock(fk4) && isAcceptableNeighbour(xd, fk.relative(fp8), fp10)) {
                    xd.setBlock(fk4, ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp10), true), 2);
                }
                else if (boolean14 && xd.isEmptyBlock(fk5) && isAcceptableNeighbour(xd, fk.relative(fp9), fp10)) {
                    xd.setBlock(fk5, ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp10), true), 2);
                }
                else if (xd.random.nextFloat() < 0.05 && isAcceptableNeighbour(xd, fk3.above(), Direction.UP)) {
                    xd.setBlock(fk3, ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Boolean>setValue((Property<Comparable>)VineBlock.UP, true), 2);
                }
            }
        }
        else if (isAcceptableNeighbour(xd, fk3, fp7)) {
            xd.setBlock(fk, ((AbstractStateHolder<O, BlockState>)byj).<Comparable, Boolean>setValue((Property<Comparable>)getPropertyForFace(fp7), true), 2);
        }
    }
    
    private BlockState copyRandomFaces(final BlockState byj1, BlockState byj2, final Random random) {
        for (final Direction fp6 : Direction.Plane.HORIZONTAL) {
            if (random.nextBoolean()) {
                final BooleanProperty bzb7 = getPropertyForFace(fp6);
                if (!byj1.<Boolean>getValue((Property<Boolean>)bzb7)) {
                    continue;
                }
                byj2 = ((AbstractStateHolder<O, BlockState>)byj2).<Comparable, Boolean>setValue((Property<Comparable>)bzb7, true);
            }
        }
        return byj2;
    }
    
    private boolean hasHorizontalConnection(final BlockState byj) {
        return byj.<Boolean>getValue((Property<Boolean>)VineBlock.NORTH) || byj.<Boolean>getValue((Property<Boolean>)VineBlock.EAST) || byj.<Boolean>getValue((Property<Boolean>)VineBlock.SOUTH) || byj.<Boolean>getValue((Property<Boolean>)VineBlock.WEST);
    }
    
    private boolean canSpread(final BlockGetter bjg, final BlockPos fk) {
        final int integer4 = 4;
        final Iterable<BlockPos> iterable5 = BlockPos.betweenClosed(fk.getX() - 4, fk.getY() - 1, fk.getZ() - 4, fk.getX() + 4, fk.getY() + 1, fk.getZ() + 4);
        int integer5 = 5;
        for (final BlockPos fk2 : iterable5) {
            if (bjg.getBlockState(fk2).getBlock() == this && --integer5 <= 0) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public boolean canBeReplaced(final BlockState byj, final BlockPlaceContext bcq) {
        final BlockState byj2 = bcq.getLevel().getBlockState(bcq.getClickedPos());
        if (byj2.getBlock() == this) {
            return this.countFaces(byj2) < VineBlock.PROPERTY_BY_DIRECTION.size();
        }
        return super.canBeReplaced(byj, bcq);
    }
    
    @Nullable
    @Override
    public BlockState getStateForPlacement(final BlockPlaceContext bcq) {
        final BlockState byj3 = bcq.getLevel().getBlockState(bcq.getClickedPos());
        final boolean boolean4 = byj3.getBlock() == this;
        final BlockState byj4 = boolean4 ? byj3 : this.defaultBlockState();
        for (final Direction fp9 : bcq.getNearestLookingDirections()) {
            if (fp9 != Direction.DOWN) {
                final BooleanProperty bzb10 = getPropertyForFace(fp9);
                final boolean boolean5 = boolean4 && byj3.<Boolean>getValue((Property<Boolean>)bzb10);
                if (!boolean5 && this.canSupportAtFace(bcq.getLevel(), bcq.getClickedPos(), fp9)) {
                    return ((AbstractStateHolder<O, BlockState>)byj4).<Comparable, Boolean>setValue((Property<Comparable>)bzb10, true);
                }
            }
        }
        return boolean4 ? byj4 : 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 byj, final Rotation btu) {
        switch (btu) {
            case CLOCKWISE_180: {
                return (((((AbstractStateHolder<O, BlockState>)byj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.SOUTH))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.WEST))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.NORTH))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.EAST));
            }
            case COUNTERCLOCKWISE_90: {
                return (((((AbstractStateHolder<O, BlockState>)byj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.EAST))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.SOUTH))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.WEST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.NORTH));
            }
            case CLOCKWISE_90: {
                return (((((AbstractStateHolder<O, BlockState>)byj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.WEST))).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.NORTH))).setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.EAST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.SOUTH));
            }
            default: {
                return byj;
            }
        }
    }
    
    @Override
    public BlockState mirror(final BlockState byj, final Mirror bsu) {
        switch (bsu) {
            case LEFT_RIGHT: {
                return (((AbstractStateHolder<O, BlockState>)byj).setValue((Property<Comparable>)VineBlock.NORTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.SOUTH))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.SOUTH, (Comparable)byj.<V>getValue((Property<V>)VineBlock.NORTH));
            }
            case FRONT_BACK: {
                return (((AbstractStateHolder<O, BlockState>)byj).setValue((Property<Comparable>)VineBlock.EAST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.WEST))).<Comparable, Comparable>setValue((Property<Comparable>)VineBlock.WEST, (Comparable)byj.<V>getValue((Property<V>)VineBlock.EAST));
            }
            default: {
                return super.mirror(byj, bsu);
            }
        }
    }
    
    public static BooleanProperty getPropertyForFace(final Direction fp) {
        return VineBlock.PROPERTY_BY_DIRECTION.get(fp);
    }
    
    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);
    }
}
