#pragma once
#include "world.hpp"
#include "common.hpp"
#include <pthread.h>


class ShortestPath {
    private:
        typedef struct node_s {
            unsigned x, y;
            unsigned dist;
            node_s* prev;
        } node_t;
        node_t* buf;

        node_t* at(unsigned, unsigned);
        const node_t* at(unsigned, unsigned) const;
        bool update_neighbour(node_t*, node_t*);
        bool may_visit(const Layout*, unsigned, unsigned, unsigned, unsigned) const;

    public:
        const unsigned w, h;

        ShortestPath(const Layout*, unsigned, unsigned, unsigned=-1, unsigned=-1, volatile const bool* cancel=NULL);
        ~ShortestPath();
        static bool is_reachable(const Layout*, unsigned, unsigned, unsigned, unsigned);
        unsigned dist(unsigned, unsigned) const;

        bool step(unsigned x, unsigned y, unsigned& next_x, unsigned& next_y) const;
};


class ShortestPathFac {
    private:
        typedef struct {
            pthread_mutex_t mtx;
            ShortestPath* rv;
            bool canceled;
            const Layout* layout;
            unsigned start_x, start_y;
            unsigned end_x, end_y;
        } args_t;
        mutable args_t* args;
        mutable ShortestPath* inst;

    public:
        ShortestPathFac(const Layout*, unsigned, unsigned, unsigned, unsigned);
        ~ShortestPathFac(); ///< cancels and/or frees result
        const ShortestPath* get() const; ///< non-null as soon as ready
};