// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: ffvar.h 137 2008-02-21 17:38:32Z sebastian $
//
////////////////////////////////////////////////////////////////////

#ifndef FF_VAR_H // don't change the name of the define since it is
		 // also used in ffvar.cpp
#define FF_VAR_H

#include <inttypes.h>
#include <iosfwd>
#include <string>
#include <vector>

namespace ff {
    class Edge;
    ////////////////////////////////////////////////////////////////////   
    //    
    // A Value has a current and a next value. New values are added to
    // the next value and become available after the next call to
    // incLevel().
    // 
    ////////////////////////////////////////////////////////////////////   
    
    typedef std::pair<int32_t, int32_t> witness_t;
    
    class Value {
    public:
	typedef uint32_t raw_t;
    private:
	static const int32_t MIN = 0;
	static const int32_t MAX = 31;
	
	raw_t current;
	raw_t next;

	raw_t lastBit(raw_t bits) const; 
	raw_t nextBit(raw_t& bits)const; 
	raw_t int2raw(int32_t value) const; 	
	int32_t raw2int(raw_t bits) const; 
	int32_t nextInt(raw_t& bits) const; 
	
	typedef bool (*test_func)(int32_t, int32_t);
	witness_t getWitness(const Value& other, test_func) const;
	
    public:
	Value();
	Value(raw_t raw);
	
	void init(int32_t val); 
	void incLevel(); 
	bool add(const Value& val);
	bool add(int32_t val); 

	bool lt(const Value& val) const; 
	bool lt(int32_t val) const;	
	witness_t lt_witness(const Value& other) const;
	
	bool le(const Value& val) const; 
	bool le(int32_t val) const;	
	witness_t le_witness(const Value& other) const;

	bool eq(const Value& val) const; 
	bool eq(int32_t val) const;	
	witness_t eq_witness(const Value& other) const;

	bool ge(const Value& val) const; 
	bool ge(int32_t val) const;	
	witness_t ge_witness(const Value& other) const;

	bool gt(const Value& val) const; 
	bool gt(int32_t val) const;	
	witness_t gt_witness(const Value& other) const;

	bool neq(const Value& val) const; 
	bool neq(int32_t val) const;
	witness_t neq_witness(const Value& other) const;
	
	raw_t getRaw() const { return current; }
	
	std::ostream& display(std::ostream& o) const;
    };

    inline std::ostream& operator<<(std::ostream& o, const Value& val) {
	return val.display(o);
    }

    ////////////////////////////////////////////////////////////////////
    //
    // A Range has a lower and an upper bound. 
    //
    ////////////////////////////////////////////////////////////////////
    
    class Range {
    public:
	int32_t lower;
	int32_t upper;
	
	Range(int32_t lower, int32_t upper) : lower(lower), upper(upper) {}
	std::ostream& display(std::ostream& o) const;
    };
    
    inline std::ostream& operator<<(std::ostream& o, const Range& range) {
	return range.display(o);
    }

    ////////////////////////////////////////////////////////////////////
    //
    // A Variable consists of a Range and a Value object. 
    // 
    ////////////////////////////////////////////////////////////////////

    class Variable {
    private:
	std::string name;
	Range range;
	Value val;
	int32_t id;
    public:
	std::vector<const Edge*> writeEdges;
	
	Variable();

	void init(int32_t value); 
	void incLevel(); 
	bool add(const Variable* other); 
	bool add(int32_t value); 
	void setID(int32_t id) { this->id = id; }
	Value::raw_t getRaw() const { return val.getRaw(); }
	int32_t getID() const { return id; }
	const Value& getValue() const { return val; }
	
	// comparators
	bool lt(const Variable* other) const; 
	bool lt(int32_t value) const;

	bool le(const Variable* other) const; 
	bool le(int32_t value) const;

	bool eq(const Variable* other) const; 
	bool eq(int32_t value) const;

	bool ge(const Variable* other) const; 
	bool ge(int32_t value) const;

	bool gt(const Variable* other) const; 
	bool gt(int32_t value) const;

	bool neq(const Variable* other) const; 
	bool neq(int32_t value) const;

	void setRange(const Range& r);
	const Range& getRange() const; 
	void setName(const std::string& name);
	const std::string& getName() const;
	std::ostream& display(std::ostream& o) const;
    };

    inline std::ostream& operator<<(std::ostream& o, const Variable& var) {
	return var.display(o);
    }
}

#include "ff_heuristic/ffvar.cpp"

#endif /* FF_VAR_H */
