#ifndef BROKER_H
#define BROKER_H
#include <bitset>
namespace hub {
// ====================================================================
//	J Schmidt CTU Prague
// ====================================================================

    template <typename Key, int N> class AttrSet;
    // ---------------------------------------------------------------
    //	class for attribute numbers
    //	all specializations of the template are identical 
    //	but do not assign to ensure 'namespaces' for attrs
    // ---------------------------------------------------------------
    template <typename Key> class AttrIndex {
	template <typename K, int N> friend class AttrSet;
	operator int (void) const { return val_; }
    protected:
	int val_;
	AttrIndex (int i): val_(i) {}
    public:
	AttrIndex (const AttrIndex& p): val_ (p.val_) {}
	bool operator == (const AttrIndex& p) const { return val_ == p.val_; } 
	bool operator <  (const AttrIndex& p) const { return val_ <  p.val_; } 
	AttrIndex& operator = (const AttrIndex& p) {val_ = p.val_; return *this; }
	int val (void) { return val_; }		// testing, do not use in code
    };

    // --------------------------------------------------------------
    //	objects of AttrUnique play the role of constants
    //	with automatically assigned distinct values
    // --------------------------------------------------------------
    template <typename Key> class AttrUnique: public AttrIndex <Key> {
	static int base;
    public:
	AttrUnique (void): AttrIndex <Key> (base++) {}
	~AttrUnique () { if (base == this->val_-1) base--; }
    };
    // --------------------------------------------------------------
    //	the same as above, except for static objects
    //	can be initialized through constructor
    //	or forcibly through init() - needed by enforced initialization
    // --------------------------------------------------------------
    template <typename Key> class StatAttrUnique: public AttrIndex <Key> {
	static int base;	// can be also replaced by AttrUnique <Key> :: base
	bool initOK_;
    public:
	StatAttrUnique (void): AttrIndex <Key> (0) { 
	    if (!this->initOK) this->val_ =  AttrUnique <Key> :: base++; 
	    this->initOK = true; 
	}
	void init (void) { 
	    if (!this->initOK) this->val_ =  AttrUnique <Key> :: base++; 
	    this->initOK = true; 
	}
	void destruct (void) { 
	    if (this->initOK) { 
		if (base == this->val_-1) base--; 
		this->initOK = false; 
	    } 
	}
	~StatAttrUnique ()   { 
	    if (this->initOK) { 
		if (base == this->val_-1) base--; 
		this->initOK = false; 
	    } 
	}
    };
    // --------------------------------------------------------------
    //	a set of binary attributes
    //	each attribute is known or not
    //	if known, it can be true or false
    // --------------------------------------------------------------
    template <typename Key, int N> class AttrSet {
	std::bitset <N> val_;
	std::bitset <N> known_;
    public:
	AttrSet (void) {}
	AttrSet (const AttrIndex <Key>& pos) { 
	    val_.set((int)pos,true); 
	    known_.set((int)pos,true); 
	}
	AttrSet (const AttrIndex <Key>& i, bool vi,const AttrIndex <Key>& j, bool vj) { 
	    val_.set ((int)i,vi); known_.set ((int)i,true); 
	    val_.set ((int)j,vj); known_.set ((int)j,true); 
	}
	AttrSet <Key, N>& set (const AttrIndex <Key>& pos, bool b = true) {
	    val_.set ((int)pos, b);
	    known_.set ((int)pos);
	    return *this;
	}
	AttrSet <Key, N>& unset (const AttrIndex <Key>&  pos) {
	    val_.set ((int)pos, false);
	    known_.set ((int)pos, false);
	    return *this;
	}
	AttrSet <Key, N>& reset (void) {
	    val_.reset();
	    return *this;	    
	}
	bool test (const AttrIndex <Key>& pos) const {
	    return val_.test ((int)pos);
	}
	bool knows (const AttrIndex <Key>& pos) const {
	    return known_.test ((int)pos);
	}
	AttrSet <Key, N>& operator += (const AttrSet <Key, N>& that) {
	    val_ += that.val_;		// what if both sets know a common but conflicting attr
	    known_ += that.known_;
	    return *this;
	}	    
	AttrSet <Key, N> operator + (const AttrSet <Key, N>& that) const {
	    AttrSet <Key, N> res (*this);
	    res += that;
	    return res;
	}
	AttrSet <Key, N> operator + (const AttrIndex <Key>& pos) const {
	    AttrSet <Key, N> res (*this);
	    res.set (pos);
	    return res;
	}

	
	bool IsSubset (const AttrSet <Key, N>& p) const; 
	void Project  (AttrSet <Key, N>& p) const;
    };

    template <typename Key, int N> 
    bool AttrSet <Key, N> :: IsSubset (const AttrSet <Key, N>& p) const {
	std::bitset <N> k (known_);
	k &= p.known_;
	if (k != known_) return false;
	std::bitset <N> v (p.val_);
	v &= known_;
	return v == val_;		// assume val has no bits outside known
    }
    template <typename Key, int N> 
    void AttrSet <Key, N> :: Project (AttrSet <Key, N>& p) const {
	p.known_ |= known_;
	std::bitset <N> mask; mask.set(); mask ^= known_;
	p.val_ &= mask;
	p.val_ |= val_;
    }
}
#endif
