#pragma once

#include <ostream>
#include <vector>
#include <set>

#include "gdconfig.hpp"
#include "gdtypes.hpp"

/*!
 * \brief data structure to store information about extreme weights of the decomposition
 */
class Weight {

    public:

        Weight(): removed(false), initial(false), iteration(0), tested(false), depth(0) { }

        void print(std::ostream& os) const {
            
            os << "<";
            for(size_t i = 0; i < weight.size(); i ++) {
                os << weight[i];
                if(i < weight.size()-1) {
                    os << ",";
                }
            }
            os << ">";

            os << ", z=" << z;

            os << ", [";

            if(!bnd.empty()) {
                auto it = bnd.begin();
                os << *it;
                it ++;
                for(; it != bnd.end(); ++it) {
                    os << "," << *it;
                }
            }

            if(!adj.empty()) {
                if(!bnd.empty()) {
                    os << ",";
                }
                auto it = adj.begin();
                os << *it;
                it ++;
                for(;it != adj.end(); it ++) {
                    os << "," << *it;
                }
            }

            os << "]";

            os << ", d=" << depth;
            os << ", r=" << removed;
            os << ", t=" << tested;

        }

    public:

        // weight vector
        dichotomy::WeightVec weight;

        // weighted sum for this extreme weight
        dichotomy::COST z;

        // list of boundaries on which the weight is present
        std::set<int> bnd; 
        // list of adjacent polytopes (solutions)
        std::set<size_t> adj;

        // wether the extreme weights is no longer an extreme weights
        bool removed;

        // true if extreme weight of the initial complete weight set
        bool initial;

        // iteration at which the weight is computed
        int iteration;

        // true if the weight was already optimized
        bool tested;

        // represents the (dichotomic) depth at which the weight has been discovered
        // the initial weights in W^0 have depth 1, and a weight vector discovered after optimizing the weighted problem with a given depth has its depth increased by +1
        size_t depth;
};

struct weight_compare {
    // return true if left <lex right
    bool operator() (dichotomy::WeightVec left, dichotomy::WeightVec right) const {

        for(size_t d = 0; d < left.size(); d ++) {

            if(left[d] < right[d]-dichotomy::epsilon1) {
                return true;
            } else if(left[d] > right[d]+dichotomy::epsilon1) {
                return false;
            }
        
        }

        return false;

    }
};