//
// Created by Kyle Cook on 4/9/17.
//

#ifndef AG_GEN_QUALITY_H
#define AG_GEN_QUALITY_H

#include <string>

#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>


#include "../util/keyvalue.h"


//EncodedQuality is a POD: can leverage bitwise serialization
union EncodedQuality {
    struct {
        int asset_id : 16;
        int attr : 12;
        int op : 4;
        int val : 16;
    } dec;
    size_t enc;
};

BOOST_IS_BITWISE_SERIALIZABLE(EncodedQuality)

/**
 * @brief Holds information about a Quality and a parameter number.
 */
struct ParameterizedQuality {
    int param;
    std::string name;
    std::string value;
	std::string op;

    int get_param_num() { return param; }

    void print() {
        std::cout << "Param: " + std::to_string(param) << std::endl;
        std::cout << "Attribute: " + name << std::endl;
		std::cout << "Operation: " << op << std::endl;
		std::cout << "Value: " + value << std::endl << std::endl;
	}

    friend std::ostream & operator << (std::ostream &os, const ParameterizedQuality &ql);
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive &ar, const unsigned int /* file_version */){
        ar & param & name & value & op;
    }

    ParameterizedQuality(){}
    ParameterizedQuality(int _param, std::string _name, std::string _value, std::string _op) :
            param(_param), name(_name), value(_value), op(_op)
        {}
};
//BOOST_IS_BITWISE_SERIALIZABLE(ParameterizedQuality)

using PostconditionQuality = std::tuple<ParameterizedQuality, std::string>;

/** Quality class
 * @brief Holds information for the Quality
 */
class Quality {

    friend std::ostream & operator << (std::ostream &os, const Quality &ql);
    friend class boost::serialization::access;

    int asset_id;
    std::string name;
    std::string op;
    std::string value;

    size_t encoded;

    EncodedQuality encode(const Keyvalue &kv_facts) const;

    friend class Factbase;

    template<class Archive>
    void serialize(Archive &ar, const unsigned int /* file_version */){
        ar & asset_id & name & op & value & encoded;
    }

  public:
    Quality(int assetId, std::string qualName, std::string op,
            std::string qualValue, Keyvalue &facts);
    Quality();

    int get_asset_id() const;
    std::string get_name() const;
    std::string get_op() const;
    std::string get_value() const;

    const size_t get_encoding() const;

    void set_value(std::string &val);
    void set_value_addp(std::string &val);
    void set_value_minp(std::string &val);

    void print() const;

    bool operator==(const Quality &rhs) const;
    bool operator<(const Quality &rhs) const;
    bool operator>(const Quality &rhs) const; 
    bool operator>=(const Quality &rhs) const; 
    bool operator<=(const Quality &rhs) const; 

};

#endif // AG_GEN_QUALITY_H
