//
// Created by Marvin on 06.08.2018.
//

#ifndef FAST_DOWNWARD_NBS_SUB_SEARCH_H
#define FAST_DOWNWARD_NBS_SUB_SEARCH_H

#include "../open_list.h"
#include "../search_engine.h"
#include "../tasks/backward_task.h"
#include "../search_statistics_expanded.h"

#include <unordered_map>

class PruningMethod;

using namespace std;

namespace nbs_search {

    struct VectorHasher {
        //TODO replace with FD hasher!
        int operator()(const vector<int> &vec) const {
            std::size_t seed = vec.size();
            for(auto& i : vec) {
                seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
            }
            return seed;
        }
    };

    class DirectionalSearch : public SearchEngine {
        const bool reopen_closed_nodes;
        const bool forward_flag;
        bool pruning;

        shared_ptr<PruningMethod> pruning_method;
        shared_ptr<Evaluator> f_evaluator;
        shared_ptr<Evaluator> g_evaluator;
        SearchStatisticsExpanded expanded_statistics;


        int calculate_plan_cost(const Plan &plan, const TaskProxy &task_proxy);
        void initial_dump() const;
        void print_checkpoint_line(int g) const;
        void check_frontier_and_set_plan(const GlobalState &state,
                                         shared_ptr<DirectionalSearch>,
                                         shared_ptr<backward_tasks::BackwardTask>);
        void check_goal(const GlobalState &state);
        bool is_mutex(const GlobalState &state);
        void set_current_plan(const GlobalState &state, const GlobalState &other_state, shared_ptr<DirectionalSearch>);

    protected:
        void initialize() override {};
        SearchStatus step() override {return FAILED;};

    public:
        explicit DirectionalSearch(const options::Options &opts,
                                   bool forwardFlag,
                                   shared_ptr<AbstractTask> input_task);
        virtual ~DirectionalSearch() = default;

        int current_plan_cost = -1;
        int current_plan_g = -1, current_plan_h = -1;
        unique_ptr<StateOpenList> waiting_open_list;
        unique_ptr<StateOpenList> ready_open_list;
        std::unordered_map<vector<int>, StateID, VectorHasher> states;

        void initialize_public();
        void update_f_value_statistics(int clb);
        void step(shared_ptr<DirectionalSearch>,
                shared_ptr<backward_tasks::BackwardTask>);
        SearchSpace& get_search_space();
        void set_plan_with_cost(const Plan &p, int cost);
        void flush_update(int current_clb);
        int flush_state(bool has_constraint, int constraint);
        int get_lowest_ready_value();
        int get_lowest_waiting_value();
        pair<SearchNode, bool> get_node_and_check(const GlobalState &state);
        const SearchStatisticsExpanded &get_expanded_statistics() const {return expanded_statistics;}
        void printDirectionalStatistic(shared_ptr<backward_tasks::BackwardTask>) const;
    };
}

#endif //FAST_DOWNWARD_NBS_SUB_SEARCH_H
