//
// Created by marvin on 16.08.18.
//

#ifndef FAST_DOWNWARD_BACKWARD_TASK_H
#define FAST_DOWNWARD_BACKWARD_TASK_H

#include "delegating_task.h"

#include <vector>

using namespace std;

namespace backward_tasks {
    struct ExplicitBackwardOperator {
        vector<FactPair> preconditions;
        vector<FactPair> effects;
        const int cost;
        const string name;
        const int parent_operator_id;

        ExplicitBackwardOperator(vector<FactPair>, vector<FactPair>, int, string, int);
    };

    struct ExplicitBackwardVariable {
        const int domain_size;
        const string name;
        const vector<string> fact_names;
        const int axiom_layer, axiom_default_value;

        const int initial_value, goal_value; //respective value in the backward search

        ExplicitBackwardVariable(int, string, vector<string>, int, int);
    };

    class BackwardTask : public tasks::DelegatingTask {
        const vector<ExplicitBackwardVariable> extra_variables;
        const vector<FactPair> goals;
        mutable vector<int> initial_state_values;//maybe not mutable?
        vector<ExplicitBackwardOperator> operators;

        const vector<FactPair> get_goal_from_initial() const;
        vector<int> get_initial_from_goal() const;
        vector<ExplicitBackwardOperator> get_operators() const;
        vector<ExplicitBackwardVariable> get_backward_variables() const;
        pair<bool,int> get_correct_variable_id(int) const;
        void create_operators_recursively(
                vector<ExplicitBackwardOperator>&,
                const ExplicitBackwardOperator&,
                vector<FactPair>, vector<FactPair>) const;
        bool is_mutex(vector<FactPair>) const;

    public:
        explicit BackwardTask(
                const std::shared_ptr<AbstractTask> &parent);
        explicit BackwardTask(
                const options::Options &opts);
        ~BackwardTask() = default;

        int get_num_goals() const override;
        FactPair get_goal_fact(int index) const override;
        vector<int> get_initial_state_values() const override;

        int get_num_variables() const override;
        std::string get_variable_name(int var) const override;
        int get_variable_domain_size(int var) const override;
        int get_variable_axiom_layer(int var) const override;
        int get_variable_default_axiom_value(int var) const override;
        std::string get_fact_name(const FactPair &fact) const override;
        bool are_facts_mutex(const FactPair &fact1, const FactPair &fact2) const override;

        int get_operator_cost(int index, bool is_axiom) const override;
        std::string get_operator_name(int index, bool is_axiom) const override;
        int get_num_operators() const override;
        int get_num_operator_preconditions(int index, bool is_axiom) const override;
        FactPair get_operator_precondition(
                int op_index, int fact_index, bool is_axiom) const override;
        int get_num_operator_effects(int op_index, bool is_axiom) const override;
        int get_num_operator_effect_conditions(
                int op_index, int eff_index, bool is_axiom) const override;
        FactPair get_operator_effect_condition(
                int op_index, int eff_index, int cond_index, bool is_axiom) const override;
        FactPair get_operator_effect(
                int op_index, int eff_index, bool is_axiom) const override;

        //Not derived Operators:
        OperatorID get_forward_op_id(OperatorID op_index) const;
        int get_num_operators_without_artificial() const;
    };
}

#endif //FAST_DOWNWARD_BACKWARD_TASK_H
