ParameterDefinition *MacroParameterNode::getParameterDefinition(
				boolean includeDummies)
{
    MacroDefinition *md = this->getNetwork()->getDefinition();

    //
    // During deletion of a MacroDefinition, there is no MacroDefinition
    // for this node and therefore no ParameterDefinition.  So return NULL.
    //
    if (!md)
	return NULL;

    int idx = this->getIndex();
    if (idx <= 0)
	return NULL;

    if (this->isInput()) {
	ASSERT(this->isInputRepeatable() == FALSE);
 	if (idx > md->getInputCount())
	    return NULL;
    } else {
	ASSERT(this->isOutputRepeatable() == FALSE);
	if (idx > md->getOutputCount())
	    return NULL;
    }

    ParameterDefinition *pd;
    if (this->isInput()) {
	if (includeDummies)
	    pd = md->getInputDefinition(idx);
	else  
	    pd = md->getNonDummyInputDefinition(idx);
    } else {
	if (includeDummies)
	    pd = md->getOutputDefinition(idx);
	else  
	    pd = md->getNonDummyOutputDefinition(idx);
    }

    return pd;
}
void MacroParameterNode::switchNetwork(Network *from, Network *to, boolean silently)
{
    MacroDefinition *md = from->getDefinition();
    ParameterDefinition *pd = this->getParameterDefinition();
    ParameterDefinition *dummyPd;
    int n;

    dummyPd = new ParameterDefinition(-1);
    dummyPd->setDummy(TRUE);
    dummyPd->addType(new DXType(DXType::ObjectType));

    if(this->isInput())
	md->replaceInput(dummyPd, pd);
    else
	md->replaceOutput(dummyPd, pd);

    //
    // Switch the Network pointers
    //
    this->UniqueNameNode::switchNetwork(from, to, silently);

    //
    // Make sure we are a macro
    //
    to->makeMacro(TRUE);

    md = to->getDefinition();

    if(this->isInput())
    {
	n = md->getFirstAvailableInputPosition();

	if (n <= md->getInputCount()) {
	    dummyPd = md->getInputDefinition(n);
	    ASSERT(dummyPd->isDummy());
	    md->replaceInput(pd,dummyPd);
	} else {
	    md->addInput(pd);
	}
	this->setIndex(n);
    }
    else
    {
	n = md->getFirstAvailableOutputPosition();

	if (n <= md->getOutputCount()) {
	    ParameterDefinition *dummyPd = md->getOutputDefinition(n);
	    ASSERT(dummyPd->isDummy());
	    md->replaceOutput(pd,dummyPd);
	} else {
	    md->addOutput(pd);
	}
	this->setIndex(n);
    }

    //
    // See if the input is named input_%d or output_%d
    // and if so, change it to match the possibly new index.
    //
    pd = this->getParameterDefinition();
    char buf[64];
    if (this->isInput()) {
	strcpy(buf,"input_");
    } else {
	strcpy(buf,"output_");
    }
    int buflen = strlen(buf);
    const char* current_name = pd->getNameString();
    const char* new_name = NUL(char*);
    boolean name_reset = FALSE;
    if (EqualSubstring(current_name, buf, buflen)) {
	int endint = 0;
	const char *end = &current_name[strlen(current_name)];
	if (IsInteger(current_name+buflen,endint) &&
	    ((current_name+buflen+endint) == end)) {
		sprintf(buf+buflen,"%d",this->getIndex());
		pd->setName(buf);
		name_reset = TRUE;
	}
    }

    //
    // Resolve name conflicts with other nodes using global names.
    //
    if (!name_reset) {
	int name_clash=0, i;
	if (this->isInput()) {
	    int count = to->getInputCount();
	    for (i=1 ; !name_clash && (i <= count) ; i++) {
		ParameterDefinition *opd = to->getInputDefinition(i);
		if ((i != this->getIndex()) &&
		    EqualString(current_name,opd->getNameString()))
		    name_clash = i;
	    }
	} else {
	    int count = to->getOutputCount();
	    for (i=1 ; !name_clash && (i <= count) ; i++) {
		ParameterDefinition *opd = to->getOutputDefinition(i);
		if ((i != this->getIndex()) &&
		    EqualString(current_name,opd->getNameString()))
		    name_clash = i;
	    }
	}

	if (name_clash) {
	    char name_buf[64];
	    if (this->isInput()) {
		sprintf(name_buf,"input_%d", this->getIndex());
	    } else {
		sprintf(name_buf,"output_%d", this->getIndex());
	    }
	    new_name = name_buf;

	    if (!silently) 
		WarningMessage (
		    "Parameter name `%s' is the same name used by parameter #%d.\n"
		    "Your macro %s has been renamed \"%s\".",
		    current_name, name_clash, (this->isInput()? "Input" : "Output"),
		    new_name
		);
	    pd->setName(name_buf);
	    name_reset = TRUE;
	}
    }

    if (!name_reset) {
	const char* conflict = to->nameConflictExists(this, this->getUniqueName());
	if (conflict) {
	    char name_buf[64];
	    if (this->isInput()) {
		sprintf(name_buf,"input_%d", this->getIndex());
	    } else {
		sprintf(name_buf,"output_%d", this->getIndex());
	    }
	    new_name = name_buf;

	    if (!silently)
		WarningMessage (
		    "A %s with name \"%s\" already exists.\n"
		    "Your macro %s has been renamed \"%s\".",
		    conflict, this->getUniqueName(), (this->isInput()? "Input" : "Output"),
		    name_buf
		);
	    pd->setName(name_buf);
	    name_reset = TRUE;
	}
    }
}
boolean
MacroParameterNode::initialize()
{
    this->UniqueNameNode::initialize();
    Network *net = this->getNetwork();
    if (!net->isMacro())
	net->makeMacro(TRUE);
    MacroDefinition *md = net->getDefinition();
    ParameterDefinition *param=NULL;

    boolean input = this->isInput();
    if (!md->isReadingNet()) {
	param = new ParameterDefinition(-1);
	param->addType(new DXType(DXType::ObjectType));
    }

    char s[100];
    if (input)
    {
	if (!md->isReadingNet()) {
	    int n = md->getFirstAvailableInputPosition();
	    param->markAsInput();
	    if (n <= md->getInputCount()) {
		ParameterDefinition *dummyPd = md->getInputDefinition(n);
		ASSERT(dummyPd->isDummy());
		md->replaceInput(param,dummyPd);
	    } else {
		md->addInput(param);
	    }
	    this->setIndex(n);
	    sprintf(s, "input_%d", this->index);
	    param->setName(s);
	    param->setDefaultValue("(no default)");
	}

	//
	// The Parameter  must have its own ParameterDefinition since
	// it may change depending upon what we are connected to.
	// FIXME: ParameterDefinition should have a dup() method.
	//
	Parameter *p = this->getOutputParameter(1);
	ParameterDefinition *pd = p->getDefinition();
#if 11
	ParameterDefinition *newpd = pd->duplicate();
#else
	ParameterDefinition *newpd = 
	    new ParameterDefinition(pd->getNameSymbol());
	List *l = pd->getTypes();
	DXType *dxt;
	for (ListIterator li(*l); dxt = (DXType*)li.getNext();)
	    newpd->addType(dxt);
	newpd->markAsOutput();
	newpd->setDefaultVisibility(pd->getDefaultVisibility());
	newpd->setViewability(pd->isViewable());
	newpd->setDescription(pd->getDescription());
	newpd->setWriteableCacheability(pd->hasWriteableCacheability());
	newpd->setDefaultCacheability(pd->getDefaultCacheability());
	if (pd->isRequired())
	    newpd->setRequired();
	else
	    newpd->setNotRequired();
	if (pd->isDefaultValue())
	    newpd->setDefaultValue(pd->getDefaultValue());
	else
	    newpd->setDescriptiveValue(pd->getDefaultValue());
#endif
	p->setDefinition(newpd);
    }
    else
    {
	if (!md->isReadingNet()) {
	    int n = md->getFirstAvailableOutputPosition();
	    param->markAsOutput();
	    if (n <= md->getOutputCount()) {
		ParameterDefinition *dummyPd = md->getOutputDefinition(n);
		ASSERT(dummyPd->isDummy());
		md->replaceOutput(param,dummyPd);
	    } else {
		md->addOutput(param);
	    }
	    this->setIndex(n);
	    sprintf(s, "output_%d", this->index);
	    param->setName(s);
	    param->setDefaultValue("(no default)");
	}

	//
	// The Parameter  must have its own ParameterDefinition since
	// it may change depending upon what we are connected to.
	// FIXME: ParameterDefinition should have a dup() method.
	//
	Parameter *p = this->getInputParameter(1);
	ParameterDefinition *pd = p->getDefinition();
#if 11
	ParameterDefinition *newpd = pd->duplicate();
#else
	ParameterDefinition *newpd =
	    new ParameterDefinition(pd->getNameSymbol());
	List *l = pd->getTypes();
	DXType *dxt;
	for (ListIterator li(*l); dxt = (DXType*)li.getNext();)
	    newpd->addType(dxt);
	newpd->markAsInput();
	newpd->setDefaultVisibility(pd->getDefaultVisibility());
	newpd->setViewability(pd->isViewable());
	newpd->setDescription(pd->getDescription());
	newpd->setWriteableCacheability(pd->hasWriteableCacheability());
	newpd->setDefaultCacheability(pd->getDefaultCacheability());
	if (pd->isRequired())
	    newpd->setRequired();
	else
	    newpd->setNotRequired();
	if (pd->isDefaultValue())
	    newpd->setDefaultValue(pd->getDefaultValue());
	else
	    newpd->setDescriptiveValue(pd->getDefaultValue());
#endif
	p->setDefinition(newpd);
    }
    return TRUE;
}