#include "vhdl_export_trav.h"
#include "hub/err.h"
#include "hub/symfunc.h"
#include <string>
#include <list>
using namespace hub;
//---------------------------------------------------------------------------
void VhdlExpTrav :: operator () (void) {
    client_->haveUnit ();
    Hub :: LibIter li;
    if (theLib_ && fixedLib_) {
    	travLib (theLib_);
    } else {
	    for (li = theHub_->LibBeg(); li != theHub_->LibEnd(); li++) {
	        travLib (li->second);
        }
    }

	Hub::DesignIter di;
    if (fixedDesign_) {
        if (theDesign_) {
            client_->haveDesign (theDesign_);
            client_-> endDesign (theDesign_);
        }       // else fixed no design?  <<<<<<<<<<<<<<
    } else {
	    for (di = theHub_->DesignBeg(); di != theHub_->DesignEnd(); di++) {
	        client_->haveDesign (di->second);
	        client_-> endDesign (di->second);
        }
    }
    client_->endUnit  ();
}
//---------------------------------------------------------------------------
void  VhdlExpTrav :: travLib (hub::Library* lib) {
    Library :: EntIter ei;

    if (fixedEntity_) {
        if (!theEntity_) theEntity_ = lib->FindEntity (items_[ent].content());
        if (theEntity_) {           // if not, we might be in the wrong library
            client_->haveLibrary (lib);
            travEnt (theEntity_);       
            client_->endLibrary (lib);
        }
    } else {
        client_->haveLibrary (lib);
	    for (ei = lib->EntBeg(); ei != lib->EntEnd(); ei++) {
	        travEnt (ei->second);
	    }
        client_->endLibrary (lib);
    }	    
}
//---------------------------------------------------------------------------
void VhdlExpTrav :: travPorts(hub::Entity* ent){
	Entity :: PortProtoIter ppi;
	for (ppi = ent->PortProtoBeg(); ppi != ent->PortProtoEnd(); ppi++) {
	    client_->havePortProto (ppi->second);
    }
}
//---------------------------------------------------------------------------
void  VhdlExpTrav :: travEnt (hub::Entity* ent) {
    Entity :: ArchIter ai;
    if (fixedArch_) {
        if (!theArch_) theArch_ = ent->FindArch (items_[arch].content());
        if (theArch_) {             // good entity
            client_->haveEntity (ent);
        	client_->havePortClause();
            travPorts(ent);
	        client_->endPortClause();
            client_->haveArch (theArch_);
	        client_->endArch  (theArch_);
            client_->endEntity (ent);
        }
    } else {
        client_->haveEntity (ent);
    	client_->havePortClause();
        travPorts(ent);
	    client_->endPortClause();
	    for (ai = ent->ArchBeg(); ai != ent->ArchEnd(); ai++) {
	        client_->haveArch (ai->second);
	        client_->endArch (ai->second);
	    }
        client_->endEntity (ent);
    }
}
//---------------------------------------------------------------------------
void VhdlExpTravClient :: havePortClause(void){}
void VhdlExpTravClient :: endPortClause(void){}
//---------------------------------------------------------------------------
VhdlExpTravClient :: ~VhdlExpTravClient () { }
// ==========================================================================
void VhdlStructTraverser :: travNets (void) {
    StructArch :: NetIter ni;
    Net :: JoinIter ji;
    for (ni = archImpl_->NetBeg(); ni != archImpl_->NetEnd(); ni++) 
		client_->haveNet (archImpl_,ni->second);  
}
//---------------------------------------------------------------------------
void VhdlStructTraverser :: travPorts (void) {
    StructArch :: PortIter pi;
    for (pi = archImpl_->PortBeg(); pi != archImpl_->PortEnd(); pi++) {
	    client_->havePort (*pi);
    }
}
//---------------------------------------------------------------------------
void VhdlStructTraverser :: travInsts (void) {
    StructArch :: InstIter ii;
    for (ii = archImpl_->InstBeg(); ii != archImpl_->InstEnd(); ii++) {
		if(isPrimitive(ii->second))
			client_->havePrimInst(ii->second);
		else 
			client_->haveInst(ii->second);
    }
}
//---------------------------------------------------------------------------
bool exists(std::list<Entity*> entities, Entity* ent){
	std::list<Entity*>::const_iterator i;
	for( i = entities.begin(); i!= entities.end(); ++i){
		if( *i == ent ) return true;
	}
	return false;
}
//---------------------------------------------------------------------------
bool VhdlStructTraverser :: isPrimitive(hub::Instance* inst){
	BehavArch* ba = inst->CurrentArch()->Impl<BehavArch>();
	if(!ba) return false;
	SymFunc* sf = ba->description<SymFunc>();
	return sf ? true : false;
}
//---------------------------------------------------------------------------
void VhdlStructTraverser :: travComponents(void){
	std::list<Entity*> components;
	
	StructArch :: InstIter ii;
    for (ii = archImpl_->InstBeg(); ii != archImpl_->InstEnd(); ii++) {
		if(!exists( components , ii->second->entity()) && !isPrimitive(ii->second)){
			client_->haveComponent(ii->second->entity());
			client_->havePortClause();
			Entity *parent = ii->second->entity(); 
			Entity :: PortProtoIter ppi;
			for (ppi = parent->PortProtoBeg(); ppi != parent->PortProtoEnd(); ppi++) {
			client_->havePortProto (ppi->second);
			}
			client_->endPortClause();
			client_->endComponent();
			components.push_back(ii->second->entity());
		}
    }
}
//---------------------------------------------------------------------------
void VhdlStructTravClient :: haveNet (hub::StructArch* arch,hub::Net*){}
void VhdlStructTravClient :: haveComponent(hub::Entity*){}
void VhdlStructTravClient :: endComponent(void){}
void VhdlStructTravClient :: havePortClause(void){}
void VhdlStructTravClient :: endPortClause(void){}
void VhdlStructTravClient :: havePortProto(hub::PortProto*){}
void VhdlStructTravClient :: havePrimInst(hub::Instance*){}
//---------------------------------------------------------------------------
VhdlStructTravClient :: ~VhdlStructTravClient(){}
//---------------------------------------------------------------------------
