#ifndef ARCH_H
#define ARCH_H
#include "named.h"
#include "attr.h"
#include "entity_fw.h"

namespace hub {

// =====================================================================
//	base class of any concrete architecture implementation 
// ---------------------------------------------------------------------
class Architecture;

class ArchImpl {
protected:
    AttrSet <Architecture, 32>  flags_;
    Architecture* parent_;			// parent architecture
public:
    void Parent (Architecture* arch) { parent_ = arch; }
    Architecture* Parent (void) { return parent_; }
    
    typedef AttrSet <Architecture, 32> flagsType;

    ArchImpl (void): parent_(NULL) {}   
    // this has been made virtual because ArchImpl must be polymorphic
    virtual bool predicate (const AttrIndex <Architecture>& i) const { return flags_.test(i); }
    virtual bool superset  (const flagsType& i) const { return i.IsSubset(flags_); }
    virtual ~ArchImpl() {}
};

// =====================================================================
//	architecture
// ---------------------------------------------------------------------
class Architecture: public NameHaving {
protected:
    Entity* entity_;			// parent entity
    ArchImpl* impl_;			// pointer to implementation
public:
    std::string fileName;
    void Parent (Entity* ent) { entity_ = ent; }
    Entity* Parent (void) { return entity_; }

    Architecture (const std::string& name): 
	NameHaving (name), 
        entity_(NULL), 
        impl_(NULL) {}   
    virtual ~Architecture () {}
    bool predicate (const AttrIndex <Architecture>& i) const { 
		return impl_ ? impl_->predicate (i) : false; 
	}

    template <class AImpl> AImpl* Create (void);
    template <class AImpl> AImpl* Impl (void) { return dynamic_cast <AImpl*> (impl_); }
    ArchImpl* Impl (void) { return impl_; }
    void Impl (ArchImpl* archImpl) { impl_ = archImpl; archImpl->Parent (this); }
};
// --------------------------------------------------------------------
template <class AImpl> 
AImpl* Architecture :: Create (void) {
    if (impl_) return NULL;
    AImpl* newImpl = new AImpl;
    impl_ = newImpl;
    impl_->Parent (this);
    return newImpl;
}


}
#endif
