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

import java.util.Collection;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.PushReaction;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;

public class PistonStructureResolver {
    private final Level level;
    private final BlockPos pistonPos;
    private final boolean extending;
    private final BlockPos startPos;
    private final Direction pushDirection;
    private final List<BlockPos> toPush;
    private final List<BlockPos> toDestroy;
    private final Direction pistonDirection;
    
    public PistonStructureResolver(final Level bjw, final BlockPos fk, final Direction fp, final boolean boolean4) {
        this.toPush = Lists.newArrayList();
        this.toDestroy = Lists.newArrayList();
        this.level = bjw;
        this.pistonPos = fk;
        this.pistonDirection = fp;
        this.extending = boolean4;
        if (boolean4) {
            this.pushDirection = fp;
            this.startPos = fk.relative(fp);
        }
        else {
            this.pushDirection = fp.getOpposite();
            this.startPos = fk.relative(fp, 2);
        }
    }
    
    public boolean resolve() {
        this.toPush.clear();
        this.toDestroy.clear();
        final BlockState byj2 = this.level.getBlockState(this.startPos);
        if (!PistonBaseBlock.isPushable(byj2, this.level, this.startPos, this.pushDirection, false, this.pistonDirection)) {
            if (this.extending && byj2.getPistonPushReaction() == PushReaction.DESTROY) {
                this.toDestroy.add(this.startPos);
                return true;
            }
            return false;
        }
        else {
            if (!this.addBlockLine(this.startPos, this.pushDirection)) {
                return false;
            }
            for (int integer3 = 0; integer3 < this.toPush.size(); ++integer3) {
                final BlockPos fk4 = this.toPush.get(integer3);
                if (isSticky(this.level.getBlockState(fk4).getBlock()) && !this.addBranchingBlocks(fk4)) {
                    return false;
                }
            }
            return true;
        }
    }
    
    private static boolean isSticky(final Block bph) {
        return bph == Blocks.SLIME_BLOCK || bph == Blocks.HONEY_BLOCK;
    }
    
    private static boolean canStickToEachOther(final Block bph1, final Block bph2) {
        return (bph1 != Blocks.HONEY_BLOCK || bph2 != Blocks.SLIME_BLOCK) && (bph1 != Blocks.SLIME_BLOCK || bph2 != Blocks.HONEY_BLOCK) && (isSticky(bph1) || isSticky(bph2));
    }
    
    private boolean addBlockLine(final BlockPos fk, final Direction fp) {
        BlockState byj4 = this.level.getBlockState(fk);
        Block bph5 = byj4.getBlock();
        if (byj4.isAir()) {
            return true;
        }
        if (!PistonBaseBlock.isPushable(byj4, this.level, fk, this.pushDirection, false, fp)) {
            return true;
        }
        if (fk.equals(this.pistonPos)) {
            return true;
        }
        if (this.toPush.contains(fk)) {
            return true;
        }
        int integer6 = 1;
        if (integer6 + this.toPush.size() > 12) {
            return false;
        }
        while (isSticky(bph5)) {
            final BlockPos fk2 = fk.relative(this.pushDirection.getOpposite(), integer6);
            final Block bph6 = bph5;
            byj4 = this.level.getBlockState(fk2);
            bph5 = byj4.getBlock();
            if (byj4.isAir() || !canStickToEachOther(bph6, bph5) || !PistonBaseBlock.isPushable(byj4, this.level, fk2, this.pushDirection, false, this.pushDirection.getOpposite())) {
                break;
            }
            if (fk2.equals(this.pistonPos)) {
                break;
            }
            if (++integer6 + this.toPush.size() > 12) {
                return false;
            }
        }
        int integer7 = 0;
        for (int integer8 = integer6 - 1; integer8 >= 0; --integer8) {
            this.toPush.add(fk.relative(this.pushDirection.getOpposite(), integer8));
            ++integer7;
        }
        int integer8 = 1;
        while (true) {
            final BlockPos fk3 = fk.relative(this.pushDirection, integer8);
            final int integer9 = this.toPush.indexOf(fk3);
            if (integer9 > -1) {
                this.reorderListAtCollision(integer7, integer9);
                for (int integer10 = 0; integer10 <= integer9 + integer7; ++integer10) {
                    final BlockPos fk4 = this.toPush.get(integer10);
                    if (isSticky(this.level.getBlockState(fk4).getBlock()) && !this.addBranchingBlocks(fk4)) {
                        return false;
                    }
                }
                return true;
            }
            byj4 = this.level.getBlockState(fk3);
            if (byj4.isAir()) {
                return true;
            }
            if (!PistonBaseBlock.isPushable(byj4, this.level, fk3, this.pushDirection, true, this.pushDirection) || fk3.equals(this.pistonPos)) {
                return false;
            }
            if (byj4.getPistonPushReaction() == PushReaction.DESTROY) {
                this.toDestroy.add(fk3);
                return true;
            }
            if (this.toPush.size() >= 12) {
                return false;
            }
            this.toPush.add(fk3);
            ++integer7;
            ++integer8;
        }
    }
    
    private void reorderListAtCollision(final int integer1, final int integer2) {
        final List<BlockPos> list4 = Lists.newArrayList();
        final List<BlockPos> list5 = Lists.newArrayList();
        final List<BlockPos> list6 = Lists.newArrayList();
        list4.addAll(this.toPush.subList(0, integer2));
        list5.addAll(this.toPush.subList(this.toPush.size() - integer1, this.toPush.size()));
        list6.addAll(this.toPush.subList(integer2, this.toPush.size() - integer1));
        this.toPush.clear();
        this.toPush.addAll(list4);
        this.toPush.addAll(list5);
        this.toPush.addAll(list6);
    }
    
    private boolean addBranchingBlocks(final BlockPos fk) {
        final BlockState byj3 = this.level.getBlockState(fk);
        for (final Direction fp7 : Direction.values()) {
            if (fp7.getAxis() != this.pushDirection.getAxis()) {
                final BlockPos fk2 = fk.relative(fp7);
                final BlockState byj4 = this.level.getBlockState(fk2);
                if (canStickToEachOther(byj4.getBlock(), byj3.getBlock())) {
                    if (!this.addBlockLine(fk2, fp7)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    public List<BlockPos> getToPush() {
        return this.toPush;
    }
    
    public List<BlockPos> getToDestroy() {
        return this.toDestroy;
    }
}
