#ifndef poset_wrapper_hpp
#define poset_wrapper_hpp

#include <memory>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>

#include "separation.h"

#ifndef R_NO_REMAP
#define R_NO_REMAP
#endif
#include <Rinternals.h>
#include <R.h>

class POSet;
class TranformExtension;
class FunctionLinearExtension;
class LinearExtensionGenerator;
class LinearExtension;

//************************************
//************************************
//************************************

class POSetWrap {
    static std::uint_fast64_t conta;
public:
    std::uint_fast64_t numero = 0;
    enum class POSetTypes { generic, lin, prod, lexProd, prodLin, bucket, binaryVariable};
    enum class FunctionLinearType {
        FLETMutualRankingProbability,
        FLETAverageHeight,
        FLETSeparationAsymmetricLower,
        FLETSeparationAsymmetricUpper,
        FLETSeparationSymmetric,
        FLETRFunction,
    };

    static std::map<std::string, POSetWrap::FunctionLinearType> functionLinearMapType;
    /*{
        { "MutualRankingProbability", FunctionLinearType::FLETMutualRankingProbability },
        { "AverageHeight", FunctionLinearType::FLETAverageHeight },
        { "Separation", FunctionLinearType::FLETSeparation },
        { "RFunction", FunctionLinearType::FLETRFunction },
    };*/
private:
    enum class TranformExtensionType {
        TETItentity,
        TETLexicographical,
    };
    std::map<std::string, TranformExtensionType> tranformExtensionMapType {
        { "Identity", TranformExtensionType::TETItentity },
        { "Lexicographical", TranformExtensionType::TETLexicographical },
    };

    enum class LinearExtensionGeneratorType {
        LEGTBubleyDyer,
        TreeOfIdeals,
    };

    std::map<std::string, LinearExtensionGeneratorType> linearExtensionGeneratorMapType{
        { "BubleyDyer", LinearExtensionGeneratorType::LEGTBubleyDyer },
        { "TreeOfIdeals", LinearExtensionGeneratorType::TreeOfIdeals },
    };

    POSetWrap() {
        numero = ++POSetWrap::conta;
        poset = nullptr;
    }
public:
    std::shared_ptr<POSet> poset;
    POSetTypes type;
    ~POSetWrap() {}
    static POSetWrap* BuildGeneric(std::shared_ptr<std::vector<std::string>>, std::list<std::pair<std::string, std::string>>&);
    static POSetWrap* BuildBucketPOSet(std::shared_ptr<std::vector<std::string>>, std::list<std::pair<std::string, std::string>>&);
    static POSetWrap* BuildLinear(std::shared_ptr<std::vector<std::string>>);
    static POSetWrap* BuildProduct(std::vector<POSetWrap*>& posets);
    static POSetWrap* BuildLexicographicProduct(std::vector<POSetWrap*>& posets);
    static POSetWrap* BuildBinaryVariablePOSet(std::vector<std::string>&);
    static POSetWrap* BuildIntersection(std::vector<POSetWrap*>& posets);
    static POSetWrap* BuildLinearSum(std::vector<POSetWrap*>& posets);
    static POSetWrap* BuildDisjointSum(std::vector<POSetWrap*>& posets);
    static POSetWrap* BuildLiftingPOSet(POSetWrap* poset, std::string new_element);
    static POSetWrap* BuildFencePOSet(std::shared_ptr<std::vector<std::string>> elements, bool orientation);
    static POSetWrap* BuildDualPOSet(POSetWrap* poset);
    std::shared_ptr<std::vector<std::string>> Elements() const;
    std::shared_ptr<std::vector<std::vector<bool>>> IncidenceMatrix() const;
    SEXP CoverRelation(int&) const;
    SEXP CoverMatrix(int&) const;
    std::shared_ptr<std::list<std::pair<std::string, std::string>>> OrderRelation() const;
    SEXP IsDominatedBy(std::vector<std::string>&, std::vector<std::string>&, int&) const;
    SEXP Dominates(std::vector<std::string>&, std::vector<std::string>&, int&) const;
    SEXP IsComparableWith(std::vector<std::string>&, std::vector<std::string>&, int&) const;
    SEXP IsIncomparableWith(std::vector<std::string>&, std::vector<std::string>&, int&) const;
    std::shared_ptr<std::set<std::string>> UpsetOf(std::shared_ptr<std::vector<std::string>>) const;
    bool IsUpSet(std::shared_ptr<std::vector<std::string>>) const;
    std::shared_ptr<std::set<std::string>> DownsetOf(std::shared_ptr<std::vector<std::string>>) const;
    bool IsDownSet(std::shared_ptr<std::vector<std::string>>) const;
    SEXP ComparabilitySetOf(std::string e, int&) const;
    SEXP IncomparabilitySetOf(std::string e, int&) const;
    SEXP Maximal(int&) const;
    SEXP Minimal(int&) const;
    bool IsMaximal(std::string e) const;
    bool IsMinimal(std::string e) const;
    SEXP Meet(std::vector<std::string>&, int&) const;
    SEXP Join(std::vector<std::string>&, int&) const;
    SEXP Incomparabilities(int&) const;
    bool IsExtensionOf(POSetWrap*) const;
    SEXP ExactMRP(std::uint_fast64_t output_ogni_in_sec, int&) const;
    SEXP BruggemannLercheSorensenDominance(int&) const;

};



#endif /* poset_wrapper_hpp */
