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 bqb, final BlockPos fu, final Direction fz, final boolean boolean4) {
        this.toPush = Lists.newArrayList();
        this.toDestroy = Lists.newArrayList();
        this.level = bqb;
        this.pistonPos = fu;
        this.pistonDirection = fz;
        this.extending = boolean4;
        if (boolean4) {
            this.pushDirection = fz;
            this.startPos = fu.relative(fz);
        }
        else {
            this.pushDirection = fz.getOpposite();
            this.startPos = fu.relative(fz, 2);
        }
    }
    
    public boolean resolve() {
        this.toPush.clear();
        this.toDestroy.clear();
        final BlockState cfj2 = this.level.getBlockState(this.startPos);
        if (!PistonBaseBlock.isPushable(cfj2, this.level, this.startPos, this.pushDirection, false, this.pistonDirection)) {
            if (this.extending && cfj2.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 fu4 = this.toPush.get(integer3);
                if (isSticky(this.level.getBlockState(fu4).getBlock()) && !this.addBranchingBlocks(fu4)) {
                    return false;
                }
            }
            return true;
        }
    }
    
    private static boolean isSticky(final Block bvr) {
        return bvr == Blocks.SLIME_BLOCK || bvr == Blocks.HONEY_BLOCK;
    }
    
    private static boolean canStickToEachOther(final Block bvr1, final Block bvr2) {
        return (bvr1 != Blocks.HONEY_BLOCK || bvr2 != Blocks.SLIME_BLOCK) && (bvr1 != Blocks.SLIME_BLOCK || bvr2 != Blocks.HONEY_BLOCK) && (isSticky(bvr1) || isSticky(bvr2));
    }
    
    private boolean addBlockLine(final BlockPos fu, final Direction fz) {
        BlockState cfj4 = this.level.getBlockState(fu);
        Block bvr5 = cfj4.getBlock();
        if (cfj4.isAir()) {
            return true;
        }
        if (!PistonBaseBlock.isPushable(cfj4, this.level, fu, this.pushDirection, false, fz)) {
            return true;
        }
        if (fu.equals(this.pistonPos)) {
            return true;
        }
        if (this.toPush.contains(fu)) {
            return true;
        }
        int integer6 = 1;
        if (integer6 + this.toPush.size() > 12) {
            return false;
        }
        while (isSticky(bvr5)) {
            final BlockPos fu2 = fu.relative(this.pushDirection.getOpposite(), integer6);
            final Block bvr6 = bvr5;
            cfj4 = this.level.getBlockState(fu2);
            bvr5 = cfj4.getBlock();
            if (cfj4.isAir() || !canStickToEachOther(bvr6, bvr5) || !PistonBaseBlock.isPushable(cfj4, this.level, fu2, this.pushDirection, false, this.pushDirection.getOpposite())) {
                break;
            }
            if (fu2.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(fu.relative(this.pushDirection.getOpposite(), integer8));
            ++integer7;
        }
        int integer8 = 1;
        while (true) {
            final BlockPos fu3 = fu.relative(this.pushDirection, integer8);
            final int integer9 = this.toPush.indexOf(fu3);
            if (integer9 > -1) {
                this.reorderListAtCollision(integer7, integer9);
                for (int integer10 = 0; integer10 <= integer9 + integer7; ++integer10) {
                    final BlockPos fu4 = this.toPush.get(integer10);
                    if (isSticky(this.level.getBlockState(fu4).getBlock()) && !this.addBranchingBlocks(fu4)) {
                        return false;
                    }
                }
                return true;
            }
            cfj4 = this.level.getBlockState(fu3);
            if (cfj4.isAir()) {
                return true;
            }
            if (!PistonBaseBlock.isPushable(cfj4, this.level, fu3, this.pushDirection, true, this.pushDirection) || fu3.equals(this.pistonPos)) {
                return false;
            }
            if (cfj4.getPistonPushReaction() == PushReaction.DESTROY) {
                this.toDestroy.add(fu3);
                return true;
            }
            if (this.toPush.size() >= 12) {
                return false;
            }
            this.toPush.add(fu3);
            ++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 fu) {
        final BlockState cfj3 = this.level.getBlockState(fu);
        for (final Direction fz7 : Direction.values()) {
            if (fz7.getAxis() != this.pushDirection.getAxis()) {
                final BlockPos fu2 = fu.relative(fz7);
                final BlockState cfj4 = this.level.getBlockState(fu2);
                if (canStickToEachOther(cfj4.getBlock(), cfj3.getBlock())) {
                    if (!this.addBlockLine(fu2, fz7)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    public List<BlockPos> getToPush() {
        return this.toPush;
    }
    
    public List<BlockPos> getToDestroy() {
        return this.toDestroy;
    }
}
