std::string 
SBasePlugin::getURI() const
{
  if (mSBMLExt == NULL) 
    return getElementNamespace();
  
  const std::string &package = mSBMLExt->getName();
  const SBMLDocument* doc = getSBMLDocument();

  if (doc == NULL)
    return getElementNamespace();
  
  SBMLNamespaces* sbmlns = doc->getSBMLNamespaces();

  if (sbmlns == NULL)
    return getElementNamespace();

  if (package == "" || package == "core")
    return sbmlns->getURI();

  std::string packageURI = sbmlns->getNamespaces()->getURI(package);
  if (!packageURI.empty())
    return packageURI;

  return getElementNamespace();
}
void
ASTBase::logError (XMLInputStream& stream, const XMLToken& element, SBMLErrorCode_t code,
          const std::string& msg)
{
  SBMLNamespaces* ns = stream.getSBMLNamespaces();
  if (ns != NULL)
  {
    static_cast <SBMLErrorLog*>
      (stream.getErrorLog())->logError(
      code,
      ns->getLevel(), 
      ns->getVersion(),
      msg, 
      element.getLine(), 
      element.getColumn());
  }
  else
  {
    static_cast <SBMLErrorLog*>
      (stream.getErrorLog())->logError(
      code, 
      SBML_DEFAULT_LEVEL, 
      SBML_DEFAULT_VERSION, 
      msg, 
      element.getLine(), 
      element.getColumn());
  }
}
void
ASTCiNumberNode::addExpectedAttributes(ExpectedAttributes& attributes, 
                                     XMLInputStream& stream)
{
  ASTBase::addExpectedAttributes(attributes, stream);

  SBMLNamespaces * sbmlns = stream.getSBMLNamespaces();
  if (sbmlns != NULL)
  {
    if (sbmlns->getLevel() > 2)
    {
      attributes.add("definitionURL");
    }
    else if (sbmlns->getLevel() == 2 && sbmlns->getVersion() == 5)
    {
      attributes.add("definitionURL");
    }
  }
}
LIBSBML_CPP_NAMESPACE_BEGIN
#ifdef __cplusplus

/**
 * logs the given erroron the error log of the stream.
 * 
 * @param stream the stream to log the error on
 * @param element the element to log the error for
 * @param code the error code to log
 * @param msg optional message
 */
static void
logError (XMLInputStream* stream, const XMLToken& element, SBMLErrorCode_t code,
          const std::string& msg = "")
{
  if (&element == NULL || stream == NULL) return;

  SBMLNamespaces* ns = stream->getSBMLNamespaces();
  if (ns != NULL)
  {
    static_cast <SBMLErrorLog*>
      (stream->getErrorLog())->logError(
      code,
      ns->getLevel(), 
      ns->getVersion(),
      msg, 
      element.getLine(), 
      element.getColumn());
  }
  else
  {
    static_cast <SBMLErrorLog*>
      (stream->getErrorLog())->logError(
      code, 
      SBML_DEFAULT_LEVEL, 
      SBML_DEFAULT_VERSION, 
      msg, 
      element.getLine(), 
      element.getColumn());
  }
}
std::string 
ASTBasePlugin::getURI() const
{
  if (mSBMLExt == NULL) 
    return getElementNamespace();
  
  const std::string &package = (mSBMLExt != NULL) ? mSBMLExt->getName() : std::string("");

  SBMLNamespaces* sbmlns = getSBMLNamespaces();

  if (sbmlns == NULL)
    return getElementNamespace();

  if (package == "" || package == "core")
    return sbmlns->getURI();

  std::string packageURI = sbmlns->getNamespaces()->getURI(package);
  if (!packageURI.empty())
    return packageURI;

  return getElementNamespace();
}
LIBSBML_EXTERN XMLNode getXmlNodeForSBase(const SBase* object)
{
  char* rawsbml = const_cast<SBase*>(object)->toSBML();  
  SBMLNamespaces *sbmlns = object->getSBMLNamespaces();
  XMLNamespaces* xmlns = sbmlns->getNamespaces()->clone();
  // in rare cases the above returns a package element with default namespace, however the 
  // XMLNamespaces would then assign the actual default namespace, which is in most cases
  // the SBML namespace. In that case we adjust the default namespace here
  ISBMLExtensionNamespaces *extns = dynamic_cast<ISBMLExtensionNamespaces*>(sbmlns);
  if (extns != NULL)
  {
    xmlns->remove("");
    xmlns->add(xmlns->getURI(extns->getPackageName()), "");    
  }

  XMLNode* tmp = XMLNode::convertStringToXMLNode(rawsbml, xmlns);
  if (tmp == NULL) return XMLNode();
  XMLNode result(*tmp);
  delete tmp;
  delete xmlns;
  free(rawsbml);
  return result;
}
int
SBMLLevelVersionConverter::convert()
{
  SBMLNamespaces *ns = getTargetNamespaces();
  if (ns == NULL)
  {
    return LIBSBML_CONV_INVALID_TARGET_NAMESPACE;
  }
  bool hasValidNamespace = ns->isValidCombination();
  if (hasValidNamespace == false)
  {
    return LIBSBML_CONV_INVALID_TARGET_NAMESPACE;
  }
  
  if (mDocument == NULL)
  {
    return LIBSBML_OPERATION_FAILED;
  }
  bool strict = getValidityFlag();

  //bool success = mDocument->setLevelAndVersion(mTargetNamespaces->getLevel(), 
  //  mTargetNamespaces->getVersion(), false);
  /* mDocument->check we are not already the level and version */

  unsigned int currentLevel = mDocument->getLevel();
  unsigned int currentVersion = mDocument->getVersion();
  unsigned int targetLevel = getTargetLevel(); 
  unsigned int targetVersion = getTargetVersion();

  if (currentLevel == targetLevel && currentVersion == targetVersion)
  {
    return LIBSBML_OPERATION_SUCCESS;
  }

  /* since this function will write to the error log we should
   * clear anything in the log first
   */
  mDocument->getErrorLog()->clearLog();
  Model * currentModel = mDocument->getModel();

  bool conversion = false;

  bool ignorePackages = getProperties()->getBoolValue("ignorePackages");

  /* if model has extensions we cannot convert */
  if (!ignorePackages && mDocument->getNumPlugins() > 0)
  {

    // disable all unused packages
    SBMLExtensionRegistry::getInstance().disableUnusedPackages(mDocument);
    if (mDocument->getNumPlugins() > 0)
    {
      // if there are still plugins enabled fail
      mDocument->getErrorLog()->logError(PackageConversionNotSupported, 
                                         currentLevel, currentVersion);
      return LIBSBML_CONV_PKG_CONVERSION_NOT_AVAILABLE;

    }
  }


  // deal with the case where a package that libsbml does not know about
  // has been read in
  // the model is not L3V1 core ONLY and so should not be
  // converted by this function

  // TO DO - SK Comment

  //if (mDocument->mAttributesOfUnknownPkg.isEmpty())
  //{
  //  mDocument->getErrorLog()->logError(PackageConversionNotSupported, 
  //                                     currentLevel, currentVersion);
  //  return LIBSBML_CONV_PKG_CONVERSION_NOT_AVAILABLE;
  //}
  unsigned char origValidators = mDocument->getApplicableValidators();
  unsigned char convValidators = mDocument->getConversionValidators();
  /* if strict = true we will only convert a valid model
   * to a valid model with a valid internal representation
   */
  /* see whether the unit validator is on */
  //bool strictSBO   = ((convValidators & 0x04) == 0x04);
  bool strictUnits = strict && ((convValidators & UnitsCheckON) == UnitsCheckON);
  
  if (strict == true)
  {
    /* use validators that the user has selected
    */
    /* hack to catch errors caught at read time */
    char* doc = writeSBMLToString(mDocument);
    SBMLDocument *d = readSBMLFromString(doc);
    util_free(doc);
    unsigned int errors = d->getNumErrors();

    for (unsigned int i = 0; i < errors; i++)
    {
      mDocument->getErrorLog()->add(*(d->getError(i)));
    }
    delete d;

    errors += mDocument->checkConsistency();
    errors = mDocument->getErrorLog()->getNumFailsWithSeverity(LIBSBML_SEV_ERROR);

    /* if the current model is not valid dont convert 
    */
    if (errors > 0)
    {
      return LIBSBML_CONV_INVALID_SRC_DOCUMENT;
    }

    mDocument->getErrorLog()->clearLog();
  }

  unsigned int i;
  bool duplicateAnn = false;
  //look at annotation on sbml element - since validation only happens on the model :-(
  XMLNode *ann = mDocument->getAnnotation();
  if (ann != NULL)
  {
    for (i = 0; i < ann->getNumChildren(); i++)
    {
      std::string name = ann->getChild(i).getPrefix();
      for( unsigned int n= i+1; n < ann->getNumChildren(); n++)
      {
        if (ann->getChild(n).getPrefix() == name)
          duplicateAnn = true;
      }
    }
  }

  if (currentModel != NULL)
  {
    unsigned int origLevel;
    unsigned int origVersion;
    Model *origModel;
    if (strict)
    {
      /* here we are strict and only want to do
       * conversion if output will be valid
       *
       * save a copy of the model so it can be restored
       */
      origLevel = currentLevel;
      origVersion = currentVersion;
      origModel = currentModel->clone();
    }

    conversion = performConversion(strict, strictUnits, duplicateAnn);
      
    if (conversion == false)
    {
      /* if we were strict restore original model */

      if (strict)
      {
        delete origModel;
        mDocument->setApplicableValidators(origValidators);
        mDocument->updateSBMLNamespace("core", origLevel, origVersion);
      }
    }
    else
    {
      if (strict)
      {
        /* now we want to mDocument->check whether the resulting model is valid
         */
        mDocument->validateSBML();
        unsigned int errors = 
           mDocument->getErrorLog()->getNumFailsWithSeverity(LIBSBML_SEV_ERROR);
        if (errors > 0)
        { /* error - we dont covert
           * restore original values and return
           */
          conversion = false;
          /* undo any changes */
          currentModel = origModel->clone();
          mDocument->updateSBMLNamespace("core", origLevel, origVersion);
          mDocument->setApplicableValidators(origValidators);
          delete origModel;
        }
        else
        {
          delete origModel;
        }
      }
    }
  }
  else
  {
    mDocument->updateSBMLNamespace("core", targetLevel, targetVersion);
    conversion = true;
  }

  /* restore original value */
  mDocument->setApplicableValidators(origValidators); 
  

  if (conversion)
    return LIBSBML_OPERATION_SUCCESS;
  else
    return LIBSBML_OPERATION_FAILED;
}