//---------------------------------------------------------------------------
#include "pla_import.h"
#include "hub/structural.h"
#include "hub/behavioral.h"
#include "hub/pla.h"
#include "edif_err.h"
#include <sstream>

using namespace hub;
// --------------------------------------------------------------------------------------
void PlaImpLang::enregister (void) {
    registry_.push_back((new PlaImpLang ("PLA"))->addSuffix (".pla"));
}
// --------------------------------------------------------------------------------------
void PlaImpLang::getDefaults (hub::Hub* h, const std::string& fn, Import::Destinations& dflt) {
    dflt.clear();                                      
    dflt.push_back (Location (h, "Destination"));       // Destination #0: Model
    dflt[0][Location::lib].oblig  (true); 
    dflt[0][Location::lib].content  ("pla_library");
    dflt[0][Location::ent].locked (true);               // keep the entity name empty & locked
                                                        // we dont know what CreateUnique returns
    dflt[0][Location::arch].oblig (true); 
    dflt[0][Location::arch].content ("pla");
}

//---------------------------------------------------------------------------
std::string consName (const char* str, int no) {
    std::ostringstream t;
    t << str << no;
    return t.str();
}
//---------------------------------------------------------------------------
void PlaImport::operator() (std::istream* istr, const std::string& filename, Import::Destinations& dests) {
    fn = filename;
    dest_ = & (dests [0]);
    (*dest_) [Location::ent].content (ImportLang::bareName(filename));
    parser_.run(*istr, fn);
}

//---------------------------------------------------------------------------
void PlaImport::haveInPorts(int portsCount, std::list<std::string> portNames) {
    PortProto* proto;
    std::string portName;
    std::list<std::string>::iterator it = portNames.begin();
    for( int i = 0; i < portsCount; i++ ) {
        if( portNames.empty() )
            portName = consName("I",i);
        else {
            portName = *it;
            it++;
        }
        proto = dest_->theEntity()->CreateNextPort(portName, PortProto::inDir);
        if (!proto) {
	    throw RedefException (RedefReason ("port", portName),
			      LexPosition(parser_.l),
			      CircCtx (*dest_));
        }
    }
}
//---------------------------------------------------------------------------
void PlaImport::haveOutPorts(int portsCount, std::list<std::string> portNames) {
    PortProto* proto;
    std::string portName;
    std::list<std::string>::iterator it = portNames.begin();
    for (int i = 0; i < portsCount; i++ ) {
        if (portNames.empty()) {
            portName = consName("O",i);
        } else {
            portName = *it;
            it++;
        }
        proto = dest_->theEntity()->CreateNextPort (portName, PortProto::outDir);
        if (!proto) {
	        throw RedefException (RedefReason ("port", portName),
			      LexPosition(parser_.l),
			      CircCtx (*dest_));
        }
    }
}
//---------------------------------------------------------------------------
void PlaImport::haveDescription(std::string& type, int inNo, int outNo, std::list<std::string> &inPortNames, 
								std::list<std::string> &outPortNames, std::list<std::string> &matrix) {
    BehavArch* behavArch;
    PlaAgent *agent = new PlaAgent(inNo, outNo, type, matrix); 
    dest_->theArch (dest_->theLib()->FindArch(*agent, std::string("PLA ")+type));

    if (dest_->theArch()) {      // entity found by behaviour
        dest_->theEntity (dest_->theArch()->Parent());
    } else {                    //we have to create new entity
        dest_->CreateUniqueEntity <BehavArch> ();
        behavArch = dest_->theArch()->Impl<BehavArch>();

        // behavioral decription
        behavArch->description (agent->CreateDescr());

	    // ports
	    haveInPorts(inNo, inPortNames);
	    haveOutPorts(outNo, outPortNames);
    }
}
//---------------------------------------------------------------------------
