int CompModelPlugin::saveAllReferencedElements(set<SBase*> uniqueRefs, set<SBase*> replacedBys)
{
  SBMLDocument* doc = getSBMLDocument();
  Model* model = static_cast<Model*>(getParentSBMLObject());
  if (model==NULL) {
    if (doc) {
      string error = "Unable to discover any referenced elements in CompModelPlugin::saveAllReferencedElements: no Model parent of the 'comp' model plugin.";
      doc->getErrorLog()->logPackageError("comp", CompModelFlatteningFailed, getPackageVersion(), getLevel(), getVersion(), error);
    }
    return LIBSBML_OPERATION_FAILED;
  }
  int ret = LIBSBML_OPERATION_SUCCESS;

  //Get a list of everything, pull out anything that's a deletion, replacement, or port, and save what they're pointing to.
  //At the same time, make sure that no two things point to the same thing.
  set<SBase*> RE_deletions = set<SBase*>(); //Deletions only point to things in the same model.
  List* allElements = model->getAllElements();
  string modname = "the main model in the document";
  if (model->isSetId()) {
    modname = "the model '" + model->getId() + "'";
  }
  for (unsigned int el=0; el<allElements->getSize(); el++) {
    SBase* element = static_cast<SBase*>(allElements->get(el));
    int type = element->getTypeCode();
    if (type==SBML_COMP_DELETION ||
        type==SBML_COMP_REPLACEDBY ||
        type==SBML_COMP_REPLACEDELEMENT ||
        type==SBML_COMP_PORT) {
          //Don't worry about SBML_COMP_SBASEREF because they're all children of one of the above types.
          SBaseRef* reference = static_cast<SBaseRef*>(element);
          ReplacedElement* re = static_cast<ReplacedElement*>(element);
          ret = reference->saveReferencedElement();
          if (ret != LIBSBML_OPERATION_SUCCESS) 
          {
            if (type != SBML_COMP_REPLACEDBY && doc) 
            {
              SBMLErrorLog* errlog = doc->getErrorLog();
              SBMLError* lasterr = const_cast<SBMLError*>
                (doc->getErrorLog()->getError(doc->getNumErrors()-1));
              if ( (errlog->contains(UnrequiredPackagePresent) || 
                    errlog->contains(RequiredPackagePresent))) 
              {
                if ( lasterr->getErrorId() == CompIdRefMustReferenceObject)
                {
                   //Change the error into a warning
                   string fullmsg = lasterr->getMessage() 
                     + "  However, this may be because of the unrecognized "
                     + "package present in this document:  ignoring this "
                     + "element and flattening anyway.";
                   errlog->remove(lasterr->getErrorId());
                   errlog->logPackageError("comp", 
                     CompIdRefMayReferenceUnknownPackage, getPackageVersion(), 
                     getLevel(), getVersion(), fullmsg, element->getLine(), 
                     element->getColumn(), LIBSBML_SEV_WARNING);
                    element->removeFromParentAndDelete();
                    continue;
                }
                else if ( lasterr->getErrorId() == CompMetaIdRefMustReferenceObject)
                {
                   //Change the error into a warning
                   string fullmsg = lasterr->getMessage() 
                     + "  However, this may be because of the unrecognized "
                     + "package present in this document:  ignoring this "
                     + "element and flattening anyway.";
                   errlog->remove(lasterr->getErrorId());
                   errlog->logPackageError("comp", 
                     CompMetaIdRefMayReferenceUnknownPkg, getPackageVersion(), 
                     getLevel(), getVersion(), fullmsg, element->getLine(), 
                     element->getColumn(), LIBSBML_SEV_WARNING);
                    element->removeFromParentAndDelete();
                    continue;
                }
                else if (lasterr->getErrorId() == 
                                  CompIdRefMayReferenceUnknownPackage)
                {
                  element->removeFromParentAndDelete();
                  continue;
                }
                else if (lasterr->getErrorId() == 
                                  CompMetaIdRefMayReferenceUnknownPkg)
                {
                  element->removeFromParentAndDelete();
                  continue;
                }
              }
              else 
              {
                delete allElements;
                return ret;
              }
            }
            else {
              delete allElements;
              return ret;
            }
          }
          SBase* direct = reference->getDirectReference();
          bool adddirect = true;
          if (type == SBML_COMP_REPLACEDBY) {
            SBase* rbParent = reference->getParentSBMLObject();
            if (uniqueRefs.insert(rbParent).second == false) {
              if (doc) {
                string error = "Error discovered in CompModelPlugin::saveAllReferencedElements when checking " + modname + ": a <" + rbParent->getElementName() + "> ";
                if (direct->isSetId()) {
                  error += "with the id '" + rbParent->getId() + "'";
                  if (rbParent->isSetMetaId()) {
                    error += ", and the metaid '" + rbParent->getMetaId() + "'";
                  }
                }
                else if (rbParent->isSetMetaId()) {
                  error += "with the metaId '" + rbParent->getMetaId() + "'";
                }
                error += " has a <replacedBy> child and is also pointed to by a <port>, <deletion>, <replacedElement>, or one or more <replacedBy> objects.";
                doc->getErrorLog()->logPackageError("comp", CompNoMultipleReferences, getPackageVersion(), getLevel(), getVersion(), error);
              }
              delete allElements;
              return LIBSBML_OPERATION_FAILED;
            }
            adddirect = replacedBys.insert(direct).second;
          }
          if (type==SBML_COMP_REPLACEDELEMENT && re->isSetDeletion()) {
            adddirect = RE_deletions.insert(direct).second;
          }
          if (adddirect) {
            if (uniqueRefs.insert(direct).second == false) {
              if (doc) {
                string error = "Error discovered in CompModelPlugin::saveAllReferencedElements when checking " + modname + ": ";
                if (replacedBys.find(direct) != replacedBys.end()) {
                  error += "one or more <replacedBy> elements, plus a <deletion>, <replacedElement>, or <port> element";
                }
                else if (RE_deletions.find(direct) != RE_deletions.end()) {
                  error += "one or more <replacedElement> elements using a 'deletion' attribute, plus a <deletion>, <replacedElement>, or <port> element";
                }
                else {
                  error += "multiple <deletion>, <replacedElement>, and/or <port> elements";
                }
                error += " point directly to the <" + direct->getElementName() + "> ";
                if (direct->isSetId()) {
                  error += "with the id '" + direct->getId() + "'";
                  if (direct->isSetMetaId()) {
                    error += ", and the metaid '" + direct->getMetaId() + "'";
                  }
                  error += ".";
                }
                else if (direct->isSetMetaId()) {
                  error += "with the metaId '" + direct->getMetaId() + "'.";
                }
                doc->getErrorLog()->logPackageError("comp", CompNoMultipleReferences, getPackageVersion(), getLevel(), getVersion(), error);
              }
              delete allElements;
              return LIBSBML_OPERATION_FAILED;
            }
          }
    }
  }

  delete allElements;

  //Now call saveAllReferencedElements for all instantiated submodels.
  for (unsigned long sm=0; sm<getNumSubmodels(); sm++) {
    Model* sub = getSubmodel(sm)->getInstantiation();
    if (sub==NULL) {
      return LIBSBML_OPERATION_FAILED;
    }
    CompModelPlugin* subplug = static_cast<CompModelPlugin*>(sub->getPlugin(getPrefix()));
    if (subplug==NULL) {
      return LIBSBML_OPERATION_FAILED;
    }
    ret = subplug->saveAllReferencedElements(uniqueRefs, replacedBys);
    if (ret != LIBSBML_OPERATION_SUCCESS) {
      return ret;
    }
  }

  return LIBSBML_OPERATION_SUCCESS;
}
END_TEST

START_TEST (test_RemoveFromParent_alreadyRemoved)
{
  SBMLReader        reader;
  SBMLDocument*     d;

  std::string filename(TestDataDirectory);
  filename += "multiple-ids.xml";


  d = reader.readSBML(filename);

  if (d == NULL)
  {
    fail("readSBML(\"multiple-ids.xml\") returned a NULL pointer.");
  }
  SBase* obj;

  //List of function definitions
  obj = d->getElementByMetaId("meta20");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta20");
  fail_unless(obj == NULL);

  //Function definition
  obj = d->getElementByMetaId("meta21");
  fail_unless(obj == NULL);

  //Unit Definition
  obj = d->getElementByMetaId("meta30");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta30");
  fail_unless(obj == NULL);

  //Unit
  obj = d->getElementByMetaId("meta32");
  fail_unless(obj == NULL);

  //List of units
  obj = d->getElementByMetaId("meta31");
  fail_unless(obj == NULL);

  //List of compartments
  obj = d->getElementByMetaId("meta3");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta3");
  fail_unless(obj == NULL);

  //Compartment
  obj = d->getElementByMetaId("meta4");
  fail_unless(obj == NULL);

  //List of species
  obj = d->getElementByMetaId("meta5");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta5");
  fail_unless(obj == NULL);

  //Species
  obj = d->getElementByMetaId("meta6");
  fail_unless(obj == NULL);

  //Kinetic law
  obj = d->getElementByMetaId("meta11");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta11");
  fail_unless(obj == NULL);

  //Local parameter
  obj = d->getElementByMetaId("meta28");
  fail_unless(obj == NULL);

  //List of local parameters
  obj = d->getElementByMetaId("meta27");
  fail_unless(obj == NULL);

  //List of modifiers
  obj = d->getElementByMetaId("meta34");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta34");
  fail_unless(obj == NULL);

  //Modifier species reference
  obj = d->getElementByMetaId("meta35");
  fail_unless(obj == NULL);

  //Reaction
  obj = d->getElementByMetaId("meta8");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta8");
  fail_unless(obj == NULL);

  //Species reference
  obj = d->getElementByMetaId("meta10");
  fail_unless(obj == NULL);

  //List of reactants
  obj = d->getElementByMetaId("meta9");
  fail_unless(obj == NULL);

  //List of parameters
  obj = d->getElementByMetaId("meta33");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta33");
  fail_unless(obj == NULL);

  //Parameter
  obj = d->getElementByMetaId("meta18");
  fail_unless(obj == NULL);

  //List of event assignments
  obj = d->getElementByMetaId("meta15");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta15");
  fail_unless(obj == NULL);

  //Event assignment
  obj = d->getElementByMetaId("meta16");
  fail_unless(obj == NULL);

  //Event
  obj = d->getElementByMetaId("meta13");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta13");
  fail_unless(obj == NULL);

  //Trigger
  obj = d->getElementByMetaId("meta14");
  fail_unless(obj == NULL);

  //Delay
  obj = d->getElementByMetaId("meta17");
  fail_unless(obj == NULL);

  //Priority
  obj = d->getElementByMetaId("meta19");
  fail_unless(obj == NULL);

  //List of initial assignments
  obj = d->getElementByMetaId("meta22");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta22");
  fail_unless(obj == NULL);

  //Initial assignment
  obj = d->getElementByMetaId("meta23");
  fail_unless(obj == NULL);

  //List of rules
  obj = d->getElementByMetaId("meta24");
  fail_unless(obj != NULL);
  fail_unless(obj->removeFromParentAndDelete() == LIBSBML_OPERATION_SUCCESS);
  obj = d->getElementByMetaId("meta24");
  fail_unless(obj == NULL);

  //Rate rule
  obj = d->getElementByMetaId("meta25");
  fail_unless(obj == NULL);

  //Assignment rule
  obj = d->getElementByMetaId("meta26");
  fail_unless(obj == NULL);


  delete d;
}