package net.minecraft.world.entity.ai.navigation;

import java.util.Iterator;
import net.minecraft.core.BlockPosition;
import net.minecraft.util.MathHelper;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityInsentient;
import net.minecraft.world.level.IBlockAccess;
import net.minecraft.world.level.World;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.pathfinder.PathEntity;
import net.minecraft.world.level.pathfinder.PathMode;
import net.minecraft.world.level.pathfinder.PathPoint;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.level.pathfinder.Pathfinder;
import net.minecraft.world.level.pathfinder.PathfinderNormal;
import net.minecraft.world.phys.Vec3D;

public class Navigation extends NavigationAbstract {

    private boolean avoidSun;

    public Navigation(EntityInsentient entityinsentient, World world) {
        super(entityinsentient, world);
    }

    @Override
    protected Pathfinder a(int i) {
        this.nodeEvaluator = new PathfinderNormal();
        this.nodeEvaluator.a(true);
        return new Pathfinder(this.nodeEvaluator, i);
    }

    @Override
    protected boolean a() {
        return this.mob.isOnGround() || this.p() || this.mob.isPassenger();
    }

    @Override
    protected Vec3D b() {
        return new Vec3D(this.mob.locX(), (double) this.u(), this.mob.locZ());
    }

    @Override
    public PathEntity a(BlockPosition blockposition, int i) {
        BlockPosition blockposition1;

        if (this.level.getType(blockposition).isAir()) {
            for (blockposition1 = blockposition.down(); blockposition1.getY() > this.level.getMinBuildHeight() && this.level.getType(blockposition1).isAir(); blockposition1 = blockposition1.down()) {
                ;
            }

            if (blockposition1.getY() > this.level.getMinBuildHeight()) {
                return super.a(blockposition1.up(), i);
            }

            while (blockposition1.getY() < this.level.getMaxBuildHeight() && this.level.getType(blockposition1).isAir()) {
                blockposition1 = blockposition1.up();
            }

            blockposition = blockposition1;
        }

        if (!this.level.getType(blockposition).getMaterial().isBuildable()) {
            return super.a(blockposition, i);
        } else {
            for (blockposition1 = blockposition.up(); blockposition1.getY() < this.level.getMaxBuildHeight() && this.level.getType(blockposition1).getMaterial().isBuildable(); blockposition1 = blockposition1.up()) {
                ;
            }

            return super.a(blockposition1, i);
        }
    }

    @Override
    public PathEntity a(Entity entity, int i) {
        return this.a(entity.getChunkCoordinates(), i);
    }

    private int u() {
        if (this.mob.isInWater() && this.r()) {
            int i = this.mob.cY();
            IBlockData iblockdata = this.level.getType(new BlockPosition(this.mob.locX(), (double) i, this.mob.locZ()));
            int j = 0;

            do {
                if (!iblockdata.a(Blocks.WATER)) {
                    return i;
                }

                ++i;
                iblockdata = this.level.getType(new BlockPosition(this.mob.locX(), (double) i, this.mob.locZ()));
                ++j;
            } while (j <= 16);

            return this.mob.cY();
        } else {
            return MathHelper.floor(this.mob.locY() + 0.5D);
        }
    }

    @Override
    protected void D_() {
        super.D_();
        if (this.avoidSun) {
            if (this.level.g(new BlockPosition(this.mob.locX(), this.mob.locY() + 0.5D, this.mob.locZ()))) {
                return;
            }

            for (int i = 0; i < this.path.e(); ++i) {
                PathPoint pathpoint = this.path.a(i);

                if (this.level.g(new BlockPosition(pathpoint.x, pathpoint.y, pathpoint.z))) {
                    this.path.b(i);
                    return;
                }
            }
        }

    }

    @Override
    protected boolean a(Vec3D vec3d, Vec3D vec3d1, int i, int j, int k) {
        int l = MathHelper.floor(vec3d.x);
        int i1 = MathHelper.floor(vec3d.z);
        double d0 = vec3d1.x - vec3d.x;
        double d1 = vec3d1.z - vec3d.z;
        double d2 = d0 * d0 + d1 * d1;

        if (d2 < 1.0E-8D) {
            return false;
        } else {
            double d3 = 1.0D / Math.sqrt(d2);

            d0 *= d3;
            d1 *= d3;
            i += 2;
            k += 2;
            if (!this.a(l, MathHelper.floor(vec3d.y), i1, i, j, k, vec3d, d0, d1)) {
                return false;
            } else {
                i -= 2;
                k -= 2;
                double d4 = 1.0D / Math.abs(d0);
                double d5 = 1.0D / Math.abs(d1);
                double d6 = (double) l - vec3d.x;
                double d7 = (double) i1 - vec3d.z;

                if (d0 >= 0.0D) {
                    ++d6;
                }

                if (d1 >= 0.0D) {
                    ++d7;
                }

                d6 /= d0;
                d7 /= d1;
                int j1 = d0 < 0.0D ? -1 : 1;
                int k1 = d1 < 0.0D ? -1 : 1;
                int l1 = MathHelper.floor(vec3d1.x);
                int i2 = MathHelper.floor(vec3d1.z);
                int j2 = l1 - l;
                int k2 = i2 - i1;

                do {
                    if (j2 * j1 <= 0 && k2 * k1 <= 0) {
                        return true;
                    }

                    if (d6 < d7) {
                        d6 += d4;
                        l += j1;
                        j2 = l1 - l;
                    } else {
                        d7 += d5;
                        i1 += k1;
                        k2 = i2 - i1;
                    }
                } while (this.a(l, MathHelper.floor(vec3d.y), i1, i, j, k, vec3d, d0, d1));

                return false;
            }
        }
    }

    private boolean a(int i, int j, int k, int l, int i1, int j1, Vec3D vec3d, double d0, double d1) {
        int k1 = i - l / 2;
        int l1 = k - j1 / 2;

        if (!this.b(k1, j, l1, l, i1, j1, vec3d, d0, d1)) {
            return false;
        } else {
            for (int i2 = k1; i2 < k1 + l; ++i2) {
                for (int j2 = l1; j2 < l1 + j1; ++j2) {
                    double d2 = (double) i2 + 0.5D - vec3d.x;
                    double d3 = (double) j2 + 0.5D - vec3d.z;

                    if (d2 * d0 + d3 * d1 >= 0.0D) {
                        PathType pathtype = this.nodeEvaluator.a(this.level, i2, j - 1, j2, this.mob, l, i1, j1, true, true);

                        if (!this.a(pathtype)) {
                            return false;
                        }

                        pathtype = this.nodeEvaluator.a(this.level, i2, j, j2, this.mob, l, i1, j1, true, true);
                        float f = this.mob.a(pathtype);

                        if (f < 0.0F || f >= 8.0F) {
                            return false;
                        }

                        if (pathtype == PathType.DAMAGE_FIRE || pathtype == PathType.DANGER_FIRE || pathtype == PathType.DAMAGE_OTHER) {
                            return false;
                        }
                    }
                }
            }

            return true;
        }
    }

    protected boolean a(PathType pathtype) {
        return pathtype == PathType.WATER ? false : (pathtype == PathType.LAVA ? false : pathtype != PathType.OPEN);
    }

    private boolean b(int i, int j, int k, int l, int i1, int j1, Vec3D vec3d, double d0, double d1) {
        Iterator iterator = BlockPosition.a(new BlockPosition(i, j, k), new BlockPosition(i + l - 1, j + i1 - 1, k + j1 - 1)).iterator();

        BlockPosition blockposition;
        double d2;
        double d3;

        do {
            if (!iterator.hasNext()) {
                return true;
            }

            blockposition = (BlockPosition) iterator.next();
            d2 = (double) blockposition.getX() + 0.5D - vec3d.x;
            d3 = (double) blockposition.getZ() + 0.5D - vec3d.z;
        } while (d2 * d0 + d3 * d1 < 0.0D || this.level.getType(blockposition).a((IBlockAccess) this.level, blockposition, PathMode.LAND));

        return false;
    }

    public void a(boolean flag) {
        this.nodeEvaluator.b(flag);
    }

    public boolean e() {
        return this.nodeEvaluator.d();
    }

    public void b(boolean flag) {
        this.nodeEvaluator.a(flag);
    }

    public boolean f() {
        return this.nodeEvaluator.d();
    }

    public void c(boolean flag) {
        this.avoidSun = flag;
    }
}
