#include "linearExtensionGenerator.h"
#include "treeOfIdeals.h"
#include "latticeOfIdeals.h"


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

LEGTreeOfIdeals::LEGTreeOfIdeals(std::shared_ptr<std::vector<std::shared_ptr<POSet>>> posets) : LinearExtensionGenerator(posets) {
    this->started = false;
    this->poset = posets->at(0);

    if (dynamic_pointer_cast<BinaryVariablePOSet>(this->poset) != nullptr) {
        std::string err_str = "LEGTreeOfIdeals error: wrong poset";
        throw_line(err_str);
    }
        
    this->latticeOfIdeals = this->poset->latticeOfIdeals();
    this->latticeOfIdealsCrossing = std::make_shared<std::vector<std::uint_fast64_t>>(this->poset->size(), 0);
    this->moreCrossing = std::make_shared<std::vector<bool>>(this->poset->size());
    this->currentLinearExtension = std::make_shared<LinearExtension>(this->poset->size());
}

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

std::string LEGTreeOfIdeals::to_string() const {
    std::string base_string = LinearExtensionGenerator::to_string();
    std::string risultato = "";
    risultato += "ByTreeOfIdeal:";
    if (base_string != "")
        risultato += "\n\t" + FindAndReplaceAll(base_string, "\n", "\n\t");
    return risultato;
}

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

void LEGTreeOfIdeals::start(std::uint_fast64_t) {
    this->latticeOfIdealsCrossing = std::make_shared<std::vector<std::uint_fast64_t>>(this->poset->size(), 0);
    this->moreCrossing = std::make_shared<std::vector<bool>>(this->poset->size());
    this->currentLinearExtension = std::make_shared<LinearExtension>(this->poset->size());
    std::shared_ptr<std::vector<std::uint_fast64_t>> path = this->latticeOfIdeals->getFromPath(this->latticeOfIdealsCrossing, this->moreCrossing);
    
    for (std::uint_fast64_t k = 0; k < this->currentLinearExtension->size(); ++k) {
        auto val = path->at(k);
        this->currentLinearExtension->set(k, val);
    }
    
    this->started = true;
    this->current_number_le = 1;
}

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

void LEGTreeOfIdeals::next() {
    if (this->started == false) {
        std::string err_str = "LEGTreeOfIdeals error: not started yet!";
        throw_line(err_str);
    }
    
    auto result = std::find(this->moreCrossing->rbegin(), this->moreCrossing->rend(), true);
    if (result == this->moreCrossing->rend()) {
        std::string err_str = "LEGTreeOfIdeals error: max number of linear extention reached!";
        throw_line(err_str);
    }
    ++this->current_number_le;

    auto pos = (std::distance(result, this->moreCrossing->rend()) - 1);
    ++this->latticeOfIdealsCrossing->at((std::uint_fast64_t) pos);
    std::fill (this->latticeOfIdealsCrossing->begin() + pos + 1, this->latticeOfIdealsCrossing->end(), 0);
    
    std::shared_ptr<std::vector<std::uint_fast64_t>> path = this->latticeOfIdeals->getFromPath(this->latticeOfIdealsCrossing, this->moreCrossing);
    
    for (std::uint_fast64_t k = 0; k < this->currentLinearExtension->size(); ++k) {
        auto val = path->at(k);
        this->currentLinearExtension->set(k, val);
    }
}

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

bool LEGTreeOfIdeals::hasNext() {
    auto result = std::find(this->moreCrossing->rbegin(), this->moreCrossing->rend(), true);
    return result != this->moreCrossing->rend();
}


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

void LEGTreeOfIdeals::to_file(std::fstream& file_le, char DELIMETER) {
    if (file_le.is_open())
    {
        std::string str_le = "";
        bool first = true;
        for (std::uint_fast64_t k = 0; k < this->currentLinearExtension->size(); ++k) {
            std::string nome_etichetta = this->poset->GetEName(this->currentLinearExtension->getVal(k));
            if (first) {
                str_le = "" + nome_etichetta;
                first = false;
            }
            else {
                str_le += DELIMETER + nome_etichetta;
            }
        }
        file_le << str_le;
        file_le << std::endl;
    }
}
