// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: ffiguard.cpp 263 2009-01-12 10:00:33Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#include "ff_heuristic/ffiguard.h"
#include "ff_heuristic/ffvar.h"
#include "ff_heuristic/ffhelper.h"
#include "ff_heuristic/ffback.h"

#include <iostream>
#include <cassert>

namespace ff {
    
    using namespace std;

    ostream& operator<<(ostream& o, IntegerConstraint::comp_t c) {
	switch (c) {
	case IntegerConstraint::LT:  return o << "<";
	case IntegerConstraint::LE:  return o << "<=";
	case IntegerConstraint::EQ:  return o << "=";
	case IntegerConstraint::GE:  return o << ">=";
	case IntegerConstraint::GT:  return o << ">";
	case IntegerConstraint::NEQ: return o << "!=";
	default:
	    assert(false);
	    return o;
	}
    }

    witness_t IntegerConstraint::getWitness(const Value& lhs, const Value& rhs) const {
	switch (comp) {
	case LT:  return lhs.lt_witness(rhs);
	case LE:  return lhs.le_witness(rhs);
	case EQ:  return lhs.eq_witness(rhs);
	case GE:  return lhs.ge_witness(rhs);
	case GT:  return lhs.gt_witness(rhs);
	case NEQ: return lhs.neq_witness(rhs);
	default:
	    assert(false);
	    return make_pair(no_witness, no_witness);
	}
    }

    ////////////////////////////////////////////////////////////////////

    VarConstraint::VarConstraint(const Variable* lhs, const Variable* rhs, comp_t comp, int32_t id) : 
	IntegerConstraint(lhs, comp, id),
	rhs(rhs)
    {}

    void VarConstraint::accept(RelaxedSolution* solution) const {
	solution->add(this);
    }
    
    ostream& VarConstraint::display(ostream& o) const {
	return o << lhs->getName() << comp << rhs->getName();
    }
    
    ////////////////////////////////////////////////////////////////////

    ConstConstraint::ConstConstraint(const Variable* lhs, int32_t rhs, comp_t comp, int32_t id) : 
	IntegerConstraint(lhs, comp, id),
	rhs(rhs)
    {}

    void ConstConstraint::accept(RelaxedSolution* solution) const {
	solution->add(this);
    }

    witness_t ConstConstraint::getWitness(const Value& lhs, const Value& rhs) const {
	witness_t result = IntegerConstraint::getWitness(lhs, rhs);
	result.second = no_witness;
	return result;
    }
    
    ostream& ConstConstraint::display(ostream& o) const {
	return o << lhs->getName() << comp << rhs;
    }

    ////////////////////////////////////////////////////////////////////
    
    NullConstraint::NullConstraint(int32_t id) :
	IntegerConstraint(NULL, EQ, id)
    {}

    void NullConstraint::accept(RelaxedSolution* solution) const {
	solution->add(this);
    }
    
    ostream& NullConstraint::display(std::ostream& o) const { 
	return o << "true";
    }
    
    ////////////////////////////////////////////////////////////////////

    IntegerGuard::IntegerGuard() : 
	constraints(),
	firstUnsat(0) 
    {}

    IntegerGuard::~IntegerGuard() {
	destroyVector(constraints);
    }

    void IntegerGuard::addConstraint(IntegerConstraint* ic) {
	assert(ic != NULL);
	constraints.push_back(ic);
    }
	
    ostream& IntegerGuard::display(ostream& o) const {
	if (empty()) {
	    return o << "true";
	} else {
	    for (uint32_t i = 0; i < constraints.size() - 1; i++) {
		o << *constraints[i] << " && ";
	    }
	    return o << *constraints.back();
	}
    }
}

