/*
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given @p id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
CiElementMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "The formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the <" << object.getElementName();
  msg << "> ";
  switch(object.getTypeCode()) {
  case SBML_INITIAL_ASSIGNMENT:
  case SBML_EVENT_ASSIGNMENT:
  case SBML_ASSIGNMENT_RULE:
  case SBML_RATE_RULE:
    //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
    break;
  default:
    if (object.isSetId()) {
      msg << "with id '" << object.getId() << "' ";
    }
    break;
  }
  if (object.getLevel() == 2 && object.getVersion() == 1)
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter.";
  else if (object.getLevel() < 3)
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction.";
  else
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction/speciesReference.";
  safe_free(formula);

  return msg.str();
}
/*
 * Logs a constraint failure to the validator for the given SBML object.
 * The parameter message is used instead of the constraint's member
 * variable msg.
 */
void
VConstraint::logFailure (const SBase& object, const std::string& message)
{
  std::string pkg = object.getPackageName();
  unsigned int pkgVersion = object.getPackageVersion();
  if (mId > 99999 && pkg == "core")
  {
    // we are dealing with a core object that is logging errors 
    // relating to a package
    // need to work out which pkg

    unsigned int offset = (unsigned int)(floor((double)mId/100000.0)) * 100000;

    if (offset == 9900000)
    {
      // we are dealing with the strict units validator
      mId = mId - offset;
    }
    else
    {
      // it is possible that the object does not have a direct plugin
      // it may the child of an object that does
      // so lets cut straight to the parent document
      const SBMLDocument * doc = object.getSBMLDocument();
      if (doc != NULL)
      {
        for (unsigned int i = 0; i < doc->getNumPlugins(); i++)
        {
          const SBMLExtension * ext = doc->getPlugin(i)->getSBMLExtension();

          if (ext->getErrorIdOffset() == offset)
          {
            pkg = doc->getPlugin(i)->getPackageName();
            pkgVersion = doc->getPlugin(i)->getPackageVersion();
            break;
          }
        }
      }
    }
  }

  SBMLError error = SBMLError( mId, object.getLevel(), object.getVersion(),
			       message, object.getLine(), object.getColumn(),
             LIBSBML_SEV_ERROR, LIBSBML_CAT_SBML, pkg, pkgVersion);

  if (error.getSeverity() != LIBSBML_SEV_NOT_APPLICABLE)
    mValidator.logFailure(error);

/*    ( SBMLError( mId, object.getLevel(), object.getVersion(),
                 message, object.getLine(), object.getColumn(),
                 LIBSBML_SEV_ERROR, LIBSBML_CAT_SBML ));*/

}
/*
 * Logs a constraint failure to the validator for the given SBML object.
 * The parameter message is used instead of the constraint's member
 * variable msg.
 */
void
VConstraint::logFailure (const SBase& object, const std::string& message)
{
  if (&object == NULL || &message == NULL) return;

  SBMLError error = SBMLError( mId, object.getLevel(), object.getVersion(),
			       message, object.getLine(), object.getColumn() );

  if (error.getSeverity() != LIBSBML_SEV_NOT_APPLICABLE)
    mValidator.logFailure(error);

/*    ( SBMLError( mId, object.getLevel(), object.getVersion(),
                 message, object.getLine(), object.getColumn(),
                 LIBSBML_SEV_ERROR, LIBSBML_CAT_SBML ));*/

}
/**
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
CiElementMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "\nThe formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the " << getTypename(object);
  if (object.getLevel() == 2 && object.getVersion() == 1)
    msg << " uses '" << node.getName() << "' that is not the id of a species/compartment/parameter.";
  else
    msg << " uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction.";
  safe_free(formula);

  return msg.str();
}