package engine.mobileAI.utilities;
import engine.objects.Regions;
import java.awt.geom.Area;
import java.util.ArrayList;

public class PathingUtilities {
    public static class Point {
        public int x;
        public int y;
        public Point previous;

        public Point(int x, int y, Point previous) {
            this.x = x;
            this.y = y;
            this.previous = previous;
        }

        public Point offset(int ox, int oy) { return new Point(x + ox, y + oy, this);  }
    }

    public static boolean IsWalkable(Area navMesh, Point point) {
        if (navMesh.contains(point.x, point.y))
            return true;

        Regions region = Regions.getRegionAtPoint(point);
        if (region != null) {
            return !(region.getHeightAtPoint(point) - point.y > 2);
        }
        return false;
    }

    public static ArrayList<Point> FindNeighbors(Area navMesh, Point point) {
        ArrayList<Point> neighbors = new ArrayList<>();
        Point up = point.offset(0,  1);
        Point down = point.offset(0,  -1);
        Point left = point.offset(-1, 0);
        Point right = point.offset(1, 0);
        if (IsWalkable(navMesh, up)) neighbors.add(up);
        if (IsWalkable(navMesh, down)) neighbors.add(down);
        if (IsWalkable(navMesh, left)) neighbors.add(left);
        if (IsWalkable(navMesh, right)) neighbors.add(right);
        return neighbors;
    }

    public static ArrayList<Point> FindPath(Area navMesh, Point start, Point end) {
        boolean finished = false;
        ArrayList<Point> used = new ArrayList<>();
        used.add(start);
        while (!finished) {
            ArrayList<Point> newOpen = new ArrayList<>();
            for(int i = 0; i < used.size(); ++i){
                Point point = used.get(i);
                for (Point neighbor : FindNeighbors(navMesh, point)) {
                    if (!used.contains(neighbor) && !newOpen.contains(neighbor)) {
                        newOpen.add(neighbor);
                    }
                }
            }

            for(Point point : newOpen) {
                used.add(point);
                if (end.equals(point)) {
                    finished = true;
                    break;
                }
            }

            if (!finished && newOpen.isEmpty())
                return null;
        }

        ArrayList<Point> path = new ArrayList<>();
        Point point = used.get(used.size() - 1);
        while(point.previous != null) {
            path.add(0, point);
            point = point.previous;
        }
        return path;
    }
}
