//
// Created by marvin on 20.11.18.
//

#ifndef FAST_DOWNWARD_FMM_SUB_H
#define FAST_DOWNWARD_FMM_SUB_H

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

#include <unordered_map>
#include <map>

class PruningMethod;

namespace fmm {

    struct VectorHasher {
        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 FmmSubSearch : public SearchEngine {
        const bool reopen_closed_nodes;
        const bool forward_flag;
        bool pruning;
        double fraction_p;

        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<FmmSubSearch>,
                                         shared_ptr<backward_tasks::BackwardTask>);
        bool is_mutex(const GlobalState &state);
        void set_current_plan(const GlobalState &state, const GlobalState &other_state, shared_ptr<FmmSubSearch>);
        void rememberState(EvaluationContext &context);
        void forgetState(EvaluationContext &context);

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

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

        unique_ptr<StateOpenList> open_list;
        std::unordered_map<vector<int>, StateID, VectorHasher> states;
        int current_plan_cost = -1;
        int current_plan_g = -1, current_plan_h = -1;
        std::map<int,int> min_g;
        std::map<int,int> min_f;

        void initialize_public();
        void update_f_value_statistics(int clb);
        void step(shared_ptr<FmmSubSearch>,
                  shared_ptr<backward_tasks::BackwardTask>);
        SearchSpace& get_search_space();
        void set_plan_with_cost(const Plan &p, int cost);
        pair<double, bool> get_lowest_open_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;
        void gather_and_print_g_groups();
    };

}

#endif //FAST_DOWNWARD_FMM_SUB_H
