package net.minecraft.world.level.pathfinder;

import java.util.EnumSet;
import net.minecraft.world.level.BlockGetter;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Set;
import net.minecraft.world.level.block.Block;
import com.google.common.collect.Sets;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.PathNavigationRegion;

public class FlyNodeEvaluator extends WalkNodeEvaluator {
    @Override
    public void prepare(final PathNavigationRegion bkh, final Mob ala) {
        super.prepare(bkh, ala);
        this.oldWaterCost = ala.getPathfindingMalus(BlockPathTypes.WATER);
    }
    
    @Override
    public void done() {
        this.mob.setPathfindingMalus(BlockPathTypes.WATER, this.oldWaterCost);
        super.done();
    }
    
    @Override
    public Node getStart() {
        int integer2;
        if (this.canFloat() && this.mob.isInWater()) {
            integer2 = Mth.floor(this.mob.getY());
            final BlockPos.MutableBlockPos a3 = new BlockPos.MutableBlockPos(this.mob.getX(), integer2, this.mob.getZ());
            for (Block bph4 = this.level.getBlockState(a3).getBlock(); bph4 == Blocks.WATER; bph4 = this.level.getBlockState(a3).getBlock()) {
                ++integer2;
                a3.set(this.mob.getX(), integer2, this.mob.getZ());
            }
        }
        else {
            integer2 = Mth.floor(this.mob.getY() + 0.5);
        }
        final BlockPos fk3 = new BlockPos(this.mob);
        final BlockPathTypes cqm4 = this.getBlockPathType(this.mob, fk3.getX(), integer2, fk3.getZ());
        if (this.mob.getPathfindingMalus(cqm4) < 0.0f) {
            final Set<BlockPos> set5 = Sets.newHashSet();
            set5.add(new BlockPos(this.mob.getBoundingBox().minX, integer2, this.mob.getBoundingBox().minZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().minX, integer2, this.mob.getBoundingBox().maxZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().maxX, integer2, this.mob.getBoundingBox().minZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().maxX, integer2, this.mob.getBoundingBox().maxZ));
            for (final BlockPos fk4 : set5) {
                final BlockPathTypes cqm5 = this.getBlockPathType(this.mob, fk4);
                if (this.mob.getPathfindingMalus(cqm5) >= 0.0f) {
                    return super.getNode(fk4.getX(), fk4.getY(), fk4.getZ());
                }
            }
        }
        return super.getNode(fk3.getX(), integer2, fk3.getZ());
    }
    
    @Override
    public Target getGoal(final double double1, final double double2, final double double3) {
        return new Target(super.getNode(Mth.floor(double1), Mth.floor(double2), Mth.floor(double3)));
    }
    
    @Override
    public int getNeighbors(final Node[] arr, final Node cqo) {
        int integer4 = 0;
        final Node cqo2 = this.getNode(cqo.x, cqo.y, cqo.z + 1);
        if (this.isOpen(cqo2)) {
            arr[integer4++] = cqo2;
        }
        final Node cqo3 = this.getNode(cqo.x - 1, cqo.y, cqo.z);
        if (this.isOpen(cqo3)) {
            arr[integer4++] = cqo3;
        }
        final Node cqo4 = this.getNode(cqo.x + 1, cqo.y, cqo.z);
        if (this.isOpen(cqo4)) {
            arr[integer4++] = cqo4;
        }
        final Node cqo5 = this.getNode(cqo.x, cqo.y, cqo.z - 1);
        if (this.isOpen(cqo5)) {
            arr[integer4++] = cqo5;
        }
        final Node cqo6 = this.getNode(cqo.x, cqo.y + 1, cqo.z);
        if (this.isOpen(cqo6)) {
            arr[integer4++] = cqo6;
        }
        final Node cqo7 = this.getNode(cqo.x, cqo.y - 1, cqo.z);
        if (this.isOpen(cqo7)) {
            arr[integer4++] = cqo7;
        }
        final Node cqo8 = this.getNode(cqo.x, cqo.y + 1, cqo.z + 1);
        if (this.isOpen(cqo8) && this.hasMalus(cqo2) && this.hasMalus(cqo6)) {
            arr[integer4++] = cqo8;
        }
        final Node cqo9 = this.getNode(cqo.x - 1, cqo.y + 1, cqo.z);
        if (this.isOpen(cqo9) && this.hasMalus(cqo3) && this.hasMalus(cqo6)) {
            arr[integer4++] = cqo9;
        }
        final Node cqo10 = this.getNode(cqo.x + 1, cqo.y + 1, cqo.z);
        if (this.isOpen(cqo10) && this.hasMalus(cqo4) && this.hasMalus(cqo6)) {
            arr[integer4++] = cqo10;
        }
        final Node cqo11 = this.getNode(cqo.x, cqo.y + 1, cqo.z - 1);
        if (this.isOpen(cqo11) && this.hasMalus(cqo5) && this.hasMalus(cqo6)) {
            arr[integer4++] = cqo11;
        }
        final Node cqo12 = this.getNode(cqo.x, cqo.y - 1, cqo.z + 1);
        if (this.isOpen(cqo12) && this.hasMalus(cqo2) && this.hasMalus(cqo7)) {
            arr[integer4++] = cqo12;
        }
        final Node cqo13 = this.getNode(cqo.x - 1, cqo.y - 1, cqo.z);
        if (this.isOpen(cqo13) && this.hasMalus(cqo3) && this.hasMalus(cqo7)) {
            arr[integer4++] = cqo13;
        }
        final Node cqo14 = this.getNode(cqo.x + 1, cqo.y - 1, cqo.z);
        if (this.isOpen(cqo14) && this.hasMalus(cqo4) && this.hasMalus(cqo7)) {
            arr[integer4++] = cqo14;
        }
        final Node cqo15 = this.getNode(cqo.x, cqo.y - 1, cqo.z - 1);
        if (this.isOpen(cqo15) && this.hasMalus(cqo5) && this.hasMalus(cqo7)) {
            arr[integer4++] = cqo15;
        }
        final Node cqo16 = this.getNode(cqo.x + 1, cqo.y, cqo.z - 1);
        if (this.isOpen(cqo16) && this.hasMalus(cqo5) && this.hasMalus(cqo4)) {
            arr[integer4++] = cqo16;
        }
        final Node cqo17 = this.getNode(cqo.x + 1, cqo.y, cqo.z + 1);
        if (this.isOpen(cqo17) && this.hasMalus(cqo2) && this.hasMalus(cqo4)) {
            arr[integer4++] = cqo17;
        }
        final Node cqo18 = this.getNode(cqo.x - 1, cqo.y, cqo.z - 1);
        if (this.isOpen(cqo18) && this.hasMalus(cqo5) && this.hasMalus(cqo3)) {
            arr[integer4++] = cqo18;
        }
        final Node cqo19 = this.getNode(cqo.x - 1, cqo.y, cqo.z + 1);
        if (this.isOpen(cqo19) && this.hasMalus(cqo2) && this.hasMalus(cqo3)) {
            arr[integer4++] = cqo19;
        }
        final Node cqo20 = this.getNode(cqo.x + 1, cqo.y + 1, cqo.z - 1);
        if (this.isOpen(cqo20) && this.hasMalus(cqo16) && this.hasMalus(cqo11) && this.hasMalus(cqo10)) {
            arr[integer4++] = cqo20;
        }
        final Node cqo21 = this.getNode(cqo.x + 1, cqo.y + 1, cqo.z + 1);
        if (this.isOpen(cqo21) && this.hasMalus(cqo17) && this.hasMalus(cqo8) && this.hasMalus(cqo10)) {
            arr[integer4++] = cqo21;
        }
        final Node cqo22 = this.getNode(cqo.x - 1, cqo.y + 1, cqo.z - 1);
        if (this.isOpen(cqo22) && this.hasMalus(cqo18) && this.hasMalus(cqo11) && this.hasMalus(cqo9)) {
            arr[integer4++] = cqo22;
        }
        final Node cqo23 = this.getNode(cqo.x - 1, cqo.y + 1, cqo.z + 1);
        if (this.isOpen(cqo23) && this.hasMalus(cqo19) && this.hasMalus(cqo8) && this.hasMalus(cqo9)) {
            arr[integer4++] = cqo23;
        }
        final Node cqo24 = this.getNode(cqo.x + 1, cqo.y - 1, cqo.z - 1);
        if (this.isOpen(cqo24) && this.hasMalus(cqo16) && this.hasMalus(cqo15) && this.hasMalus(cqo14)) {
            arr[integer4++] = cqo24;
        }
        final Node cqo25 = this.getNode(cqo.x + 1, cqo.y - 1, cqo.z + 1);
        if (this.isOpen(cqo25) && this.hasMalus(cqo17) && this.hasMalus(cqo12) && this.hasMalus(cqo14)) {
            arr[integer4++] = cqo25;
        }
        final Node cqo26 = this.getNode(cqo.x - 1, cqo.y - 1, cqo.z - 1);
        if (this.isOpen(cqo26) && this.hasMalus(cqo18) && this.hasMalus(cqo15) && this.hasMalus(cqo13)) {
            arr[integer4++] = cqo26;
        }
        final Node cqo27 = this.getNode(cqo.x - 1, cqo.y - 1, cqo.z + 1);
        if (this.isOpen(cqo27) && this.hasMalus(cqo19) && this.hasMalus(cqo12) && this.hasMalus(cqo13)) {
            arr[integer4++] = cqo27;
        }
        return integer4;
    }
    
    private boolean hasMalus(@Nullable final Node cqo) {
        return cqo != null && cqo.costMalus >= 0.0f;
    }
    
    private boolean isOpen(@Nullable final Node cqo) {
        return cqo != null && !cqo.closed;
    }
    
    @Nullable
    @Override
    protected Node getNode(final int integer1, final int integer2, final int integer3) {
        Node cqo5 = null;
        final BlockPathTypes cqm6 = this.getBlockPathType(this.mob, integer1, integer2, integer3);
        final float float7 = this.mob.getPathfindingMalus(cqm6);
        if (float7 >= 0.0f) {
            cqo5 = super.getNode(integer1, integer2, integer3);
            cqo5.type = cqm6;
            cqo5.costMalus = Math.max(cqo5.costMalus, float7);
            if (cqm6 == BlockPathTypes.WALKABLE) {
                final Node node = cqo5;
                ++node.costMalus;
            }
        }
        if (cqm6 == BlockPathTypes.OPEN || cqm6 == BlockPathTypes.WALKABLE) {
            return cqo5;
        }
        return cqo5;
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bjg, final int integer2, final int integer3, final int integer4, final Mob ala, final int integer6, final int integer7, final int integer8, final boolean boolean9, final boolean boolean10) {
        final EnumSet<BlockPathTypes> enumSet12 = EnumSet.<BlockPathTypes>noneOf(BlockPathTypes.class);
        BlockPathTypes cqm13 = BlockPathTypes.BLOCKED;
        final BlockPos fk14 = new BlockPos(ala);
        cqm13 = this.getBlockPathTypes(bjg, integer2, integer3, integer4, integer6, integer7, integer8, boolean9, boolean10, enumSet12, cqm13, fk14);
        if (enumSet12.contains(BlockPathTypes.FENCE)) {
            return BlockPathTypes.FENCE;
        }
        BlockPathTypes cqm14 = BlockPathTypes.BLOCKED;
        for (final BlockPathTypes cqm15 : enumSet12) {
            if (ala.getPathfindingMalus(cqm15) < 0.0f) {
                return cqm15;
            }
            if (ala.getPathfindingMalus(cqm15) < ala.getPathfindingMalus(cqm14)) {
                continue;
            }
            cqm14 = cqm15;
        }
        if (cqm13 == BlockPathTypes.OPEN && ala.getPathfindingMalus(cqm14) == 0.0f) {
            return BlockPathTypes.OPEN;
        }
        return cqm14;
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bjg, final int integer2, final int integer3, final int integer4) {
        BlockPathTypes cqm6 = WalkNodeEvaluator.getBlockPathTypeRaw(bjg, integer2, integer3, integer4);
        if (cqm6 == BlockPathTypes.OPEN && integer3 >= 1) {
            final Block bph7 = bjg.getBlockState(new BlockPos(integer2, integer3 - 1, integer4)).getBlock();
            final BlockPathTypes cqm7 = WalkNodeEvaluator.getBlockPathTypeRaw(bjg, integer2, integer3 - 1, integer4);
            if (cqm7 == BlockPathTypes.DAMAGE_FIRE || bph7 == Blocks.MAGMA_BLOCK || cqm7 == BlockPathTypes.LAVA || bph7 == Blocks.CAMPFIRE) {
                cqm6 = BlockPathTypes.DAMAGE_FIRE;
            }
            else if (cqm7 == BlockPathTypes.DAMAGE_CACTUS) {
                cqm6 = BlockPathTypes.DAMAGE_CACTUS;
            }
            else if (cqm7 == BlockPathTypes.DAMAGE_OTHER) {
                cqm6 = BlockPathTypes.DAMAGE_OTHER;
            }
            else if (cqm7 == BlockPathTypes.COCOA) {
                cqm6 = BlockPathTypes.COCOA;
            }
            else if (cqm7 == BlockPathTypes.FENCE) {
                cqm6 = BlockPathTypes.FENCE;
            }
            else {
                cqm6 = ((cqm7 == BlockPathTypes.WALKABLE || cqm7 == BlockPathTypes.OPEN || cqm7 == BlockPathTypes.WATER) ? BlockPathTypes.OPEN : BlockPathTypes.WALKABLE);
            }
        }
        if (cqm6 == BlockPathTypes.WALKABLE || cqm6 == BlockPathTypes.OPEN) {
            cqm6 = WalkNodeEvaluator.checkNeighbourBlocks(bjg, integer2, integer3, integer4, cqm6);
        }
        return cqm6;
    }
    
    private BlockPathTypes getBlockPathType(final Mob ala, final BlockPos fk) {
        return this.getBlockPathType(ala, fk.getX(), fk.getY(), fk.getZ());
    }
    
    private BlockPathTypes getBlockPathType(final Mob ala, final int integer2, final int integer3, final int integer4) {
        return this.getBlockPathType(this.level, integer2, integer3, integer4, ala, this.entityWidth, this.entityHeight, this.entityDepth, this.canOpenDoors(), this.canPassDoors());
    }
}
