#include "linearExtensionGenerator.h"


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

//LEGBubleyDyer::LEGBubleyDyer(std::shared_ptr<std::vector<std::shared_ptr<POSet>>> posets, std::shared_ptr<Random> rnd) : LinearExtensionGenerator(posets) {
LEGBubleyDyer::LEGBubleyDyer(std::shared_ptr<std::vector<std::shared_ptr<POSet>>> posets, std::shared_ptr<Random> r) : LinearExtensionGenerator(posets) {
    rnd = r;
    max_number_le = std::numeric_limits<std::uint_fast64_t>::max();
    poset = posets->at(0);
    currentLinearExtension = std::make_shared<LinearExtension>(this->poset->size());
    started = false;
}

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

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

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

void LEGBubleyDyer::start(std::uint_fast64_t quante) {
    this->rnd->Restart();
    max_number_le = quante;
    poset->FirstLE(*currentLinearExtension);
    this->started = true;
    this->current_number_le = 1;
    
    this->toUpdate = false;
    this->isSwitched = false;
    this->positionToUpdate = 0;
    
    return;
}

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

void LEGBubleyDyer::next() {
    if (this->started == false) {
        std::string err_str = "LEGBubleyDyer error: not started yet!";
        throw_line(err_str);
    }
    ++this->current_number_le;

    this->toUpdate = this->rnd->RndNextInt(0, 1);
    this->isSwitched = false;

    if (this->toUpdate != 0) {
        this->positionToUpdate = this->rnd->RndNextInt(0, this->currentLinearExtension->size() - 2);
        std::uint_fast64_t e1 = this->currentLinearExtension->getVal(this->positionToUpdate);
        std::uint_fast64_t e2 = this->currentLinearExtension->getVal(this->positionToUpdate + 1);
        if (!this->poset->GreaterThan(e2, e1)) {
            this->currentLinearExtension->set(this->positionToUpdate, e2);
            this->currentLinearExtension->set(this->positionToUpdate + 1, e1);
            this->isSwitched = true;
        }
    }
    return;
}

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

std::uint_fast64_t LEGBubleyDyer::getSetOneElement(std::set<std::uint_fast64_t>& setOne)
{
    std::uint_fast64_t n = setOne.size();
    std::uint_fast64_t p = this->rnd->RndNextInt(0, n - 1);
    
    std::set<std::uint_fast64_t>::iterator it = setOne.begin();
    std::advance(it, p);
    std::uint_fast64_t result = *it;
    return result;
}


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

void LEGBubleyDyer::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  << DELIMETER + std::to_string(this->toUpdate);
        file_le  << DELIMETER + std::to_string(this->positionToUpdate);
        file_le  << DELIMETER + std::to_string(this->isSwitched);

        file_le  << std::endl;
    }
}


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


