// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: ffsolution.cpp 141 2008-02-25 10:51:00Z sebastian $
//
////////////////////////////////////////////////////////////////////

#include "ff_heuristic/ffsolution.h"
#include "ff_heuristic/ffiguard.h"
#include "ff_heuristic/ffloc.h"
#include "ff_heuristic/ffsystem.h"

#include <ostream>

namespace ff {
    using namespace std;

    std::ostream& Supporter::display(std::ostream& o) const {
	return o << "(" << var->getName() << ", " << value << ")";
    }

    bool Supporter::equals(const Supporter& other) const {
	assert(other.var);
	return var->getID() == other.var->getID() && value == other.value;
    }
    
    ////////////////////////////////////////////////////////////////////
    
    Level::Level(const System* system) : 
	system(system),
	locations(system->getNrLocations(), false),
	edges(system->getNrEdges(), false) 
    {}

    ostream& Level::display(ostream& o) const {
	o << "supporters: ";
	for (uint32_t i = 0; i < supporters.size(); i++) {
	    o << supporters[i] << " ";
	}
	o << endl << "locations: ";
	for (uint32_t i = 0; i < locations.size(); i++) {
	    if (locations[i]) {
		o << *system->getLocations()[i] << " ";
	    }
	}
	o << endl << "value sets: ";
	for (uint32_t i = 0; i < raws.size(); i++) {
	    o << Value(raws[i]) << " ";	    
	}
	return o;
    }

    ////////////////////////////////////////////////////////////////////
    
    void RelaxedSolution::add(const Location* loc) {
	assert(0 <= loc->getActivationLevel() && loc->getActivationLevel() < int32_t(levels.size()));

	levels[loc->getActivationLevel()].locations[loc->getID()] = true;
    }  

    void RelaxedSolution::add(const Supporter& supp, int32_t level) {
	assert(supp.var);
	assert(levels[level].raws[supp.var->getID()] & (1UL << supp.value));

	vector<Supporter>& supps = levels[level].supporters;
	for (uint32_t j = 0; j < supps.size(); j++) {
	    if (supp.equals(supps[j])) {
		return;
	    }
	}
	supps.push_back(supp);
	return;	
    }

    void RelaxedSolution::add(const Supporter& supp) {
	for (uint32_t i = 0; i < size(); i++) {
	    if (levels[i].raws[supp.var->getID()] & (1UL << supp.value)) {
		add(supp, i);
		return;
	    }
	}
	assert(false);
    }

    void RelaxedSolution::add(const IntegerConstraint* ic) {
	ic->accept(this);
    }
    
    void RelaxedSolution::add(const VarConstraint* c) {
	assert(0 <= c->getActivationLevel() && c->getActivationLevel() < int32_t(size()));

	Value lhs(levels[c->getActivationLevel()].raws[c->lhs->getID()]);
	Value rhs(levels[c->getActivationLevel()].raws[c->rhs->getID()]);
	witness_t w = c->getWitness(lhs, rhs);

	add(Supporter(c->lhs, w.first));
	add(Supporter(c->rhs, w.second));
    }

    void RelaxedSolution::add(const ConstConstraint* c) {
	assert(0 <= c->getActivationLevel() && c->getActivationLevel() < int32_t(size()));
	
	Value lhs(levels[c->getActivationLevel()].raws[c->lhs->getID()]);
	Value rhs(1UL << c->rhs);

	add(Supporter(c->lhs, c->getWitness(lhs, rhs).first));
    }

    void RelaxedSolution::add(const NullConstraint*) {
	assert(false);
    }

    ostream& RelaxedSolution::display(ostream& o) const {
	for (uint32_t i = 0; i < levels.size(); i++) {
	    o << i << ": " << endl << levels[i] << endl;
	} 
	return o;
    }
}
