#ifndef EXPLOIT_HPP
#define EXPLOIT_HPP

#include <memory>
#include <string>
#include <vector>

#include "quality.h"
#include "topology.h"
#include "../util/build_sql.h"

#include "../mpi/serialize_tuple.h"
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>

#include <boost/serialization/is_bitwise_serializable.hpp>

typedef std::tuple<ACTION_T, ParameterizedQuality> PostconditionQ;
typedef std::tuple<ACTION_T, ParameterizedTopology> PostconditionT;

/** Exploit class
 * @brief Holds information about an exploit.
 * @details Holds information about an exploit including:
 *
 * - id
 * - name
 * - preconditions
 * - postconditions
 */
class Exploit {
    friend std::ostream & operator << (std::ostream &os, const Exploit &ex);
    friend class boost::serialization::access;

    int id;
    std::string name;
    size_t num_params;
    std::string group;

    std::vector<ParameterizedQuality> preconds_q;
    std::vector<ParameterizedTopology> preconds_t;

    std::vector<PostconditionQ> postconds_q;
    std::vector<PostconditionT> postconds_t;

    template<class Archive>
    void serialize(Archive &ar, const unsigned int /* file_version */){
        ar & id & name & num_params & group & preconds_q & preconds_t & postconds_q & postconds_t;
    }
  public:
    Exploit(int preId, std::string &preName, int preNumParams,
            std::string &groupName,
            std::tuple<std::vector<ParameterizedQuality>,
                       std::vector<ParameterizedTopology>>
                preconds,
            std::tuple<std::vector<PostconditionQ>,
                       std::vector<PostconditionT>>
                postconds);
    Exploit();

    int get_id() const { return id; }

    std::string get_name() const { return name; }
    std::string get_group() const { return group; }

    size_t get_num_params() const { return num_params; }

    void print_preconds_q();
    void print_preconds_t();
    void print_postconds_q();
    void print_postconds_t();
    void print_id();

    std::vector<ParameterizedQuality> precond_list_q();
    std::vector<ParameterizedTopology> precond_list_t();

    std::vector<PostconditionQ> postcond_list_q();
    std::vector<PostconditionT> postcond_list_t();

    // static std::vector<Exploit> fetch_all();

    // static void print_all();
};

#endif // EXPLOIT_HPP
