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

// HACK! Ignore this if used as a top-level compile target.
#ifdef FF_VAR_H

#include "ff_heuristic/ffvar.h"
#include <iostream>
#include <cassert>

namespace ff {

    using namespace std;

    //////////////////////////////////////////////////////////////////// 
    
    static inline bool test_lt(int32_t l, int32_t r) { return l < r; }
    static inline bool test_le(int32_t l, int32_t r) { return l <= r; }
    static inline bool test_eq(int32_t l, int32_t r) { return l == r; }
    static inline bool test_ge(int32_t l, int32_t r) { return l >= r; }
    static inline bool test_gt(int32_t l, int32_t r) { return l > r; }
    static inline bool test_neq(int32_t l, int32_t r) { return l != r; }

    inline witness_t Value::getWitness(const Value& other, test_func test) const {
 	raw_t rhs = other.getRaw();
	while (rhs) {
	    int32_t r = other.nextInt(rhs);
	    raw_t lhs = getRaw();
	    while (lhs) {
		int32_t l = nextInt(lhs);
		if (test(l, r)) {
		    return make_pair(l, r);
		}
	    }
	}
	assert(false);
	return make_pair(0,0);
    }

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

    inline ostream& Range::display(ostream& o) const {
	return o << "[" << lower << ", " << upper << "]";
    }
    
    //////////////////////////////////////////////////////////////////// 
    
    static const int32_t R2I_SIZE = 37;
    static const int32_t RAW2INT[R2I_SIZE] = {
	-1,   0,   1,  26,   2,  23,  27,  -1,   3,  16,
	24,  30,  28,  11,  -1,  13,   4,   7,  17,  -1,
	25,  22,  31,  15,  29,  10,  12,   6,  -1,  21,
	14,   9,   5,  20,   8,  19,  18
    };
    
    inline Value::Value() : 
	current(0),
	next(0)
    {}

    inline Value::Value(raw_t raw) : 
	current(raw),
	next(0)
    {}
    
    inline void Value::init(int32_t value) {
	next = int2raw(value);
	current = next;
    }

    inline Value::raw_t Value::lastBit(raw_t bits) const {
	return (bits & (bits - 1)) ^ bits;
    }
	
    inline Value::raw_t Value::nextBit(raw_t& bits) const {
	raw_t result = lastBit(bits);
	bits ^= result;
	return result;
    }
	
    inline int32_t Value::raw2int(Value::raw_t bits) const {
	return RAW2INT[bits % R2I_SIZE];
    }
    
    inline Value:: raw_t Value::int2raw(int32_t val) const {
	assert(MIN <= val && val <= MAX);	
	return 1UL << val;
    }
    
    inline int32_t Value::nextInt(Value::raw_t& bits) const {
	return raw2int(nextBit(bits));
    }	

    inline bool Value::lt(const Value&) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }
    
    inline bool Value::lt(int32_t) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }

    inline witness_t Value::lt_witness(const Value& other) const {	
	return getWitness(other, test_lt);
    }
    
    inline bool Value::le(const Value&) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }

    inline bool Value::le(int32_t) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }

    inline witness_t Value::le_witness(const Value& other) const {	
	return getWitness(other, test_le);
    }
    
    inline bool Value::eq(const Value& value) const {
	return current & value.current;
    }
    
    inline witness_t Value::eq_witness(const Value& other) const {	
	return getWitness(other, test_eq);
    }
		
    inline bool Value::eq(int32_t value) const {
	return current & int2raw(value);
    }
    
    inline bool Value::ge(const Value&) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }
    
    inline bool Value::ge(int32_t) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }
    
    inline witness_t Value::ge_witness(const Value& other) const {	
	return getWitness(other, test_ge);
    }
    
    inline bool Value::gt(const Value&) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }

    inline bool Value::gt(int32_t) const {
	cout << __PRETTY_FUNCTION__ << " not implemented" << endl;
	return true;
    }

    inline witness_t Value::gt_witness(const Value& other) const {	
	return getWitness(other, test_gt);
    }

    static inline bool onlyOneBit(uint32_t r) {
	// if deleting the lowest bit yields a zero bitstring, then
	// the bitstring contains only one bit
	assert(r != 0);
	return (r & (r-1)) == 0;
    }
    
    inline bool Value::neq(const Value& value) const {
	if (onlyOneBit(current) && onlyOneBit(value.current)) {
	    return current != value.current;
	} else {
	    return true;
	}
    }
    
    inline bool Value::neq(int32_t value) const {
	return current ^ int2raw(value);
    }

    inline witness_t Value::neq_witness(const Value& other) const {	
 	return getWitness(other, test_neq);
    }
    
    inline void Value::incLevel() {
	current = next;
    }
    
    inline bool Value::add(const Value& val) {
	next |= val.current;
	return next & ~current;
    }
    
    inline bool Value::add(int32_t val) {	
	next |= int2raw(val);
	return next & ~current;
    }
    
    inline ostream& Value::display(ostream& o) const {
	raw_t tmp = current;
	o << "{";
	while (tmp) {
	    o << nextInt(tmp);
	    if (tmp) 
		o << ", ";
	}
	return o << "}";
    }


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

    inline Variable::Variable():
	name("NO NAME"),
	range(0, 0), 
	val() 
    {}
    
    inline void Variable::init(int32_t value) {
	val.init(value);
    }
    
    inline void Variable::incLevel() {
	val.incLevel();
    }
    
    inline bool Variable::add(const Variable* other) {
	return val.add(other->val);
    }
    
    inline bool Variable::add(int32_t value) {
	return val.add(value);
    }
    
    inline const Range& Variable::getRange() const {
	return range;
    }

    inline void Variable::setRange(const Range& r) {
	range = r;
    }
    
    inline bool Variable::lt(const Variable* other) const {
	return val.lt(other->val);
    }
    
    inline bool Variable::lt(int32_t value) const {
	return val.lt(value);
    }	

    inline bool Variable::le(const Variable* other) const {
	return val.le(other->val);
    }
    
    inline bool Variable::le(int32_t value) const {
	return val.le(value);
    }	

    inline bool Variable::eq(const Variable* other) const {
	return val.eq(other->val);
    }
    
    inline bool Variable::eq(int32_t value) const {
	return val.eq(value);
    }	

    inline bool Variable::ge(const Variable* other) const {
	return val.ge(other->val);
    }
    
    inline bool Variable::ge(int32_t value) const {
	return val.ge(value);
    }	

    inline bool Variable::gt(const Variable* other) const {
	return val.gt(other->val);
    }
    
    inline bool Variable::gt(int32_t value) const {
	return val.gt(value);
    }	

    inline bool Variable::neq(const Variable* other) const {
	return val.neq(other->val);
    }
    
    inline bool Variable::neq(int32_t value) const {
	return val.neq(value);
    }	

    inline const string& Variable::getName() const {
	return name;
    }
    
    inline void Variable::setName(const string& name) {
	this->name = name;
    }

    inline ostream& Variable::display(ostream& o) const {
	return o << name << " := " << val;
    }
}

#endif /* FF_VAR_H */
