#include "structural.h"
#include <map>
using namespace std;
using namespace hub;
//---------------------------------------------------------------------------
//	entity
//---------------------------------------------------------------------------
PortProto* Entity:: CreateNextPort (const std::string& name, const PortProto::flagsType& dir) {
    pair < NameSpace <PortProto>::iterator, bool> search;
    search = interface_.byName_.insert (NameSpace <PortProto> :: value_type (name, NULL));
    if (!search.second) return NULL;
    (*search.first).second = new PortProto (name, interface_.PortNum(), dir);
    interface_.byNumber_.push_back ((*search.first).second);
    return (*search.first).second;
}
//---------------------------------------------------------------------------
Architecture* Entity:: FindOrCreateArch (const std::string& name, ArchImpl* archImpl) { 
    Architecture* arch = architectures_.FindOrCreate<Architecture> (name); 
    if (arch->Impl()) return NULL;
    arch->Parent (this);
    arch->Impl (archImpl);
    return arch;
}
//---------------------------------------------------------------------------
Instance* Entity:: Instantiate 
(const std::string instName, 
 StructArch* parentArch,
 Architecture* currArch ) {
    Instance* inst = parentArch->CreateInstance (instName, this, currArch);
    if (!inst) return NULL;
    interface_.Instantiate (inst);
    return inst;
}
//---------------------------------------------------------------------------
    Joinable::~Joinable () { }
//---------------------------------------------------------------------------
//	Interface
//---------------------------------------------------------------------------
PortProto* InterfaceProto :: FindPort (number_t number, const PortProto::flagsType& dir) {
    number_t n=0;
    NumberSpace<PortProto>::NumberMap::iterator i;
    for (i = byNumber_.begin(); i!= byNumber_.end(); i++) {
	if (dir.IsSubset ((*i)->flags())) {
	    if (n == number) return *i;
	    n++;
	}
    }
    return NULL;
}
//---------------------------------------------------------------------------
PortProto* InterfaceProto :: FindPort (number_t number, const PortProto::indexType& ixx) {
    number_t n=0;
    NumberSpace<PortProto>::NumberMap::iterator i;
    for (i = byNumber_.begin(); i!= byNumber_.end(); i++) {
	if ((*i)->flags().test(ixx)) {
	    if (n == number) return *i;
	    n++;
	}
    }
    return NULL;
}
//---------------------------------------------------------------------------
//	Port prototype
//---------------------------------------------------------------------------
template <> int AttrUnique <PortProto> :: base=0;
AttrUnique <PortProto> PortProto :: input;
AttrUnique <PortProto> PortProto :: output;
AttrSet <PortProto, 32> PortProto :: inDir (input, 1, output, 0);
AttrSet <PortProto, 32> PortProto :: outDir (input, 0, output, 1);
AttrSet <PortProto, 32> PortProto :: inOutDir (input, 1, output, 1);
AttrSet <PortProto, 32> PortProto :: noDir;		// direction unknown
//---------------------------------------------------------------------------
//	Instance
//---------------------------------------------------------------------------
Property* Instance :: CreateProperty (const std::string& name, const std::string& value) {
    pair <NameSpace <Property>::iterator, bool> search;
    search = properties_.insert (NameSpace <Property>::value_type (name, NULL));
    if (!search.second) return NULL;
    (*search.first).second = new Property (name, value);
    return (*search.first).second;
}
//---------------------------------------------------------------------------
Port <Instance>* Instance :: CreatePort (PortProto* proto) {
    number_t portn = proto->number();
    if (portn < interface_.size() && interface_ [portn] != NULL) return NULL;
    Port <Instance> * port = new Port <Instance> (proto, this);
    interface_.Insert (portn, port);
    return port;
}
//---------------------------------------------------------------------------
Port <Instance>* Instance :: FindPort (int number, const PortProto::flagsType& dir) {
    int n=0;
    NumberSpace <Port <Instance> > :: NumberMap::iterator i;
    for (i=interface_.begin(); i!= interface_.end(); i++) {
	if (dir.IsSubset ((*i)->flags())) {
	    if (n == number) return *i;
	    n++;
	}
    }
    return NULL;
}
//---------------------------------------------------------------------------
//	StructArch
//---------------------------------------------------------------------------
const AttrUnique <Architecture> StructArch :: is;
//---------------------------------------------------------------------------
Instance* StructArch :: CreateInstance 
(const std::string name, 
 Entity* entity,
 Architecture* currArch) {
        pair <NameSpace <Instance> :: iterator, bool> search;
    search = instances_.insert (NameSpace <Instance>::value_type (name, NULL));
    if (!search.second) return NULL;
    (*search.first).second = new Instance (name, entity, currArch);
    (*search.first).second->Parent(this);
    return (*search.first).second;
}
//---------------------------------------------------------------------------
Port <StructArch>* StructArch :: CreatePort (PortProto* proto) {
    number_t portn = proto->number();
    if (portn < interface_.size() && interface_ [portn] != NULL) return NULL;
    Port <StructArch> * port = new Port <StructArch> (proto, this);
    interface_.Insert (portn, port);
    return port;
}
//---------------------------------------------------------------------------
Port <StructArch>* StructArch :: FindPort (int number, const PortProto::flagsType& dir) {
    int n=0;
    NumberSpace <Port <StructArch> > :: NumberMap::iterator i;
    for (i=interface_.begin(); i!= interface_.end(); i++) {
	if (dir.IsSubset ((*i)->flags())) {
	    if (n == number) return *i;
	    n++;
	}
    }
    return NULL;
}
