/**
 * @file    Unit.h
 * @brief   Definitions of Unit and ListOfUnits.
 * @author  Ben Bornstein
 *
 * $Id: Unit.h 10084 2009-08-22 11:52:43Z ajouraku $
 * $HeadURL: https://sbml.svn.sourceforge.net/svnroot/sbml/branches/rel-4-0-0/src/sbml/Unit.h $
 *
 *<!---------------------------------------------------------------------------
 * This file is part of libSBML.  Please visit http://sbml.org for more
 * information about SBML, and the latest version of libSBML.
 *
 * Copyright 2005-2009 California Institute of Technology.
 * Copyright 2002-2005 California Institute of Technology and
 *                     Japan Science and Technology Corporation.
 * 
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation.  A copy of the license agreement is provided
 * in the file named "LICENSE.txt" included with this software distribution
 * and also available online as http://sbml.org/software/libsbml/license.html
 *----------------------------------------------------------------------- -->
 *
 * @class Unit
 * @brief LibSBML implementation of SBML's %Unit construct.
 *
 * The SBML unit definition facility uses two classes of objects,
 * UnitDefinition and Unit.  The approach to defining units in %SBML is
 * compositional; for example, <em>meter second<sup> &ndash;2</sup></em> is
 * constructed by combining a Unit object representing <em>meter</em> with
 * another Unit object representing <em>second<sup> &ndash;2</sup></em>.
 * The combination is wrapped inside a UnitDefinition, which provides for
 * assigning an identifier and optional name to the combination.  The
 * identifier can then be referenced from elsewhere in a model.  Thus, the
 * UnitDefinition class is the container, and Unit instances are placed
 * inside UnitDefinition instances.
 *
 * A Unit structure has four attributes named "kind", "exponent", "scale"
 * and "multiplier".  It represents a (possibly transformed) reference to a
 * base unit.  The attribute "kind" on Unit indicates the chosen base unit.
 * Its value in SBML Level&nbsp;2 Version&nbsp;4 must be one of the following
 * predefined strings:
 *
 * @htmlinclude libsbml-base-units.html
 *
 * (See also the definition of the <code>UNIT_KIND_</code> constants in <a
 * class="el" href="#UnitKind_t">the section below</a>.)  For SBML
 * Level&nbsp;2 Version&nbsp;1 models, the string @c Celsius is also
 * permitted.  Note also that the table above contains two names not
 * strictly defined in SBML Level&nbsp;2: @c liter and @c meter.  For
 * convenience, libSBML defines the American English spellings of these
 * units, although the SBML specification limits the valid unit names to
 * those defined by SI.
 *
 * The optional attribute named "exponent" on Unit represents an exponent
 * on the unit.  Its default value is @c 1 (one).  A Unit structure also
 * has an optional attribute called "scale"; its value must be an integer
 * exponent for a power-of-ten multiplier used to set the scale of the
 * unit.  For example, a unit having a "kind" value of @c gram and a
 * "scale" value of @c -3 signifies 10<sup>&nbsp;&ndash;3</sup>
 * \f$\times\f$ gram, or milligrams.  The default value of "scale" is @c 0
 * (zero), because 10<sup> 0</sup> = 1.  Lastly, the optional attribute
 * named "multiplier" can be used to multiply the kind unit by a
 * real-numbered factor; this enables the definition of units that are not
 * power-of-ten multiples of SI units.  For instance, a multiplier of
 * 0.3048 could be used to define @c foot as a measure of length in terms
 * of a @c metre.  The "multiplier" attribute has a default value of @c 1
 * (one).
 *
 * <h3><a class="anchor" name="UnitKind_t">UnitKind_t</a></h3>
 *
 * SBML defines a set of base units which serves as the starting point for
 * new unit definitions.  This set of base units consists of the SI units
 * and a small number of additional convenience units.
 * 
 * @if clike Until SBML Level&nbsp;2 Version&nbsp;3, there
 * existed a data type in the SBML specifications called @c UnitKind,
 * enumerating the possible SBML base units.  Although SBML Level&nbsp;2
 * Version&nbsp;3 removed this type from the language specification,
 * libSBML maintains the corresponding enumeration type @c UnitKind_t as a
 * convenience and as a way to provide backward compatibility to previous
 * SBML Level/Version specifications.  (The removal in SBML Level&nbsp;2
 * Version&nbsp;3 of the enumeration @c UnitKind was also accompanied by
 * the redefinition of the data type @c UnitSId to include the previous @c
 * UnitKind values as reserved symbols in the @c UnitSId space.  This
 * change has no net effect on permissible models, their representation or
 * their syntax.  The purpose of the change in the SBML specification was
 * simply to clean up an inconsistency about the contexts in which these
 * values were usable.)  The @c UnitKind_t enumeration in libSBML has a 
 * small number of differences compared to the SBML specifications:
 * @endif@if java In SBML Level&nbsp;2 Versions before
 * Version&nbsp;3, there existed an enumeration of units called @c
 * UnitKind.  In Version&nbsp;3, this enumeration was removed and the
 * identifier class @c UnitSId redefined to include the previous @c
 * UnitKind values as reserved symbols.  This change has no net effect on
 * permissible models, their representation or their syntax.  The purpose
 * of the change in the SBML specification was simply to clean up an
 * inconsistency about the contexts in which these values were usable.
 * However, LibSBML maintains UnitKind in the form of of a set of static
 * integer constants whose names begin with the characters
 * <code>UNIT_KIND_</code>.  These constants are defined in the class
 * <code><a href="libsbmlConstants.html">libsbmlConstants</a></code> This
 * enumeration in libSBML has a small number of differences compared to the
 * SBML specifications: @endif
 *
 * <ul>
 * <li> The alternate spelling @c "meter" is included in addition to the
 * official SI spelling @c "metre".
 *
 * <li> The alternate spelling @c "liter" is included in addition to the
 * official SI spelling @c "litre".
 *
 * <li> The unit @c "Celsius" is included because of its presence in
 * specifications of SBML prior to SBML Level&nbsp;2 Version&nbsp;3.
 * </ul>
 *
 * @if clike The table below lists the symbols defined in the
 * @c UnitKind_t enumeration, and their
 * meanings. @endif@if java The table below lists the unit
 * constants defined in libSBML, and their meanings. @endif
 *
 * @htmlinclude libsbml-unitkind-table.html
 * 
 * <!-- leave this next break as-is to work around some doxygen bug -->
 */ 
/**
 * @class ListOfUnits
 * @brief LibSBML implementation of SBML's %ListOfUnits construct.
 * 
 * The various ListOf___ classes in %SBML are merely containers used for
 * organizing the main components of an %SBML model.  All are derived from
 * the abstract class SBase, and inherit the various attributes and
 * subelements of SBase, such as "metaid" as and "annotation".  The
 * ListOf___ classes do not add any attributes of their own.
 *
 * ListOfUnits is entirely contained within UnitDefinition.
 */

#ifndef Unit_h
#define Unit_h

#include <math.h>

#include <sbml/common/extern.h>
#include <sbml/common/sbmlfwd.h>
#include <sbml/UnitKind.h>


#ifdef __cplusplus


#include <string>
#include <cstring>

#include <sbml/SBase.h>
#include <sbml/ListOf.h>
#include <sbml/common/operationReturnValues.h>

LIBSBML_CPP_NAMESPACE_BEGIN

class SBMLVisitor;


class LIBSBML_EXTERN Unit : public SBase
{
public:

  /**
   * Creates a new Unit using the given SBML @p level and @p version
   * values.
   *
   * @param level an unsigned int, the SBML Level to assign to this Unit
   *
   * @param version an unsigned int, the SBML Version to assign to this
   * Unit
   * 
   * @note Once a Unit has been added to an SBMLDocument, the @p level,
   * @p version for the document @em override those used
   * to create the Unit.  Despite this, the ability to supply the values
   * at creation time is an important aid to creating valid SBML.  Knowledge of
   * the intented SBML Level and Version determine whether it is valid to
   * assign a particular value to an attribute, or whether it is valid to add
   * an object to an existing SBMLDocument.
   */
  Unit (unsigned int level, unsigned int version);


  /**
   * Creates a new Unit using the given SBMLNamespaces object
   * @p sbmlns.
   *
   * The SBMLNamespaces object encapsulates SBML Level/Version/namespaces
   * information.  It is used to communicate the SBML Level, Version, and
   * (in Level&nbsp;3) packages used in addition to SBML Level&nbsp; Core.
   * A common approach to using this class constructor is to create an
   * SBMLNamespaces object somewhere in a program, once, then pass it to
   * object constructors such as this one when needed.
   *
   * @param sbmlns an SBMLNamespaces object.
   *
   * @note Once a Unit has been added to an SBMLDocument, the @p level,
   * @p version and @p xmlns namespaces for the document @em override those used
   * to create the Unit.  Despite this, the ability to supply the values
   * at creation time is an important aid to creating valid SBML.  Knowledge of
   * the intented SBML Level and Version determine whether it is valid to
   * assign a particular value to an attribute, or whether it is valid to add
   * an object to an existing SBMLDocument.
   */
  Unit (SBMLNamespaces* sbmlns);


  /**
   * Destroys this Unit.
   */
  virtual ~Unit ();


  /**
  * Copy constructor; creates a copy of this Unit.
  */
  Unit(const Unit& orig);


  /**
   * Assignment operator.
   */
  Unit& operator=(const Unit& orig);


  /**
   * Accepts the given SBMLVisitor for this instance of Unit.
   *
   * @param v the SBMLVisitor instance to be used.
   *
   * @return the result of calling <code>v.visit()</code>, which indicates
   * whether the Visitor would like to visit the next Unit in the list
   * of units within which this Unit is embedded (i.e., in the ListOfUnits
   * located in the enclosing UnitDefinition instance).
   */
  virtual bool accept (SBMLVisitor& v) const;


  /**
   * Creates and returns a deep copy of this Unit.
   * 
   * @return a (deep) copy of this Unit.
   */
  virtual Unit* clone () const;


  /**
   * Initializes the attributes of this Unit (except for "kind") to their
   * defaults values.
   *
   * The default values are as follows:
   * 
   * @li exponent   = 1
   * @li scale      = 0
   * @li multiplier = 1.0
   *
   * The "kind" attribute is left unchanged.
   */
  void initDefaults ();


  /**
   * Returns the "kind" of Unit this is.
   * 
   * @return the value of the "kind" attribute of this Unit as a value from
   * the <a class="el" href="#UnitKind_t">UnitKind_t</a> enumeration
   */
  UnitKind_t getKind () const;


  /**
   * Returns the value of the "exponent" attribute of this unit.
   * 
   * @return the "exponent" value of this Unit, as an integer
   */
  int getExponent () const;


  /**
   * Returns the value of the "scale" attribute of this unit.
   * 
   * @return the "scale" value of this Unit, as an integer.
   */
  int getScale () const;


  /**
   * Returns the value of the "multiplier" attribute of this Unit.
   * 
   * @return the "multiplier" value of this Unit, as a double
   */
  double getMultiplier () const;


  /**
   * Returns the value of the "offset" attribute of this Unit.
   *
   * @warning The "offset" attribute is only available in SBML Level&nbsp;2
   * Version&nbsp;1.  This attribute is not present in SBML Level&nbsp;2
   * Version&nbsp;2 or above.  When producing SBML models using these later
   * specifications, modelers and software tools need to account for units
   * with offsets explicitly.  The %SBML specification document offers a
   * number of suggestions for how to achieve this.  LibSBML methods such
   * as this one related to "offset" are retained for compatibility with
   * earlier versions of SBML Level&nbsp;2, but their use is strongly
   * discouraged.
   * 
   * @return the "offset" value of this Unit, as a double
   */
  double getOffset () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c ampere.
   * 
   * @return @c true if the kind of this Unit is @c ampere, @c false
   * otherwise. 
   */
  bool isAmpere () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c becquerel
   *
   * @return @c true if the kind of this Unit is @c becquerel, @c false
   * otherwise. 
   */
  bool isBecquerel () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c candela
   *
   * @return @c true if the kind of this Unit is @c candela, @c false
   * otherwise. 
   */
  bool isCandela () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c Celsius
   *
   * @return @c true if the kind of this Unit is @c Celsius, @c false
   * otherwise. 
   *
   * @warning The predefined unit @c Celsius was removed from the list of
   * predefined units in SBML Level&nbsp;2 Version&nbsp;2 at the same time
   * that the "offset" attribute was removed from Unit definitions.
   * LibSBML methods such as this one related to @c Celsius are retained in
   * order to support SBML Level&nbsp;2 Version&nbsp;1, but their use is
   * strongly discouraged.
   */
  bool isCelsius () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c coulomb
   *
   * @return @c true if the kind of this Unit is @c coulomb, @c false
   * otherwise. 
   */
  bool isCoulomb () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c
   * dimensionless
   *
   * @return @c true if the kind of this Unit is @c dimensionless, @c false
   * 
   * otherwise.
   */
  bool isDimensionless () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c farad
   *
   * @return @c true if the kind of this Unit is @c farad, @c false
   * otherwise. 
   */
  bool isFarad () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c gram
   *
   * @return @c true if the kind of this Unit is @c gram, @c false
   * otherwise. 
   */
  bool isGram () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c gray
   *
   * @return @c true if the kind of this Unit is @c gray, @c false
   * otherwise. 
   */
  bool isGray () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c henry
   *
   * @return @c true if the kind of this Unit is @c henry, @c false
   * otherwise. 
   */
  bool isHenry () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c hertz
   *
   * @return @c true if the kind of this Unit is @c hertz, @c false
   * otherwise. 
   */
  bool isHertz () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c item
   *
   * @return @c true if the kind of this Unit is @c item, @c false
   * otherwise. 
   */
  bool isItem () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c joule
   *
   * @return @c true if the kind of this Unit is @c joule, @c false
   * otherwise. 
   */
  bool isJoule () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c katal
   *
   * @return @c true if the kind of this Unit is @c katal, @c false
   * otherwise. 
   */
  bool isKatal () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c kelvin
   *
   * @return @c true if the kind of this Unit is @c kelvin, @c false
   * otherwise. 
   */
  bool isKelvin () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c kilogram
   *
   * @return @c true if the kind of this Unit is @c kilogram, @c false
   * otherwise. 
   */
  bool isKilogram () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c litre
   *
   * @return @c true if the kind of this Unit is @c litre or 'liter', @c
   * false 
   * otherwise.
   */
  bool isLitre () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c lumen
   *
   * @return @c true if the kind of this Unit is @c lumen, @c false
   * otherwise. 
   */
  bool isLumen () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c lux
   *
   * @return @c true if the kind of this Unit is @c lux, @c false
   * otherwise. 
   */
  bool isLux () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c metre
   *
   * @return @c true if the kind of this Unit is @c metre or 'meter', @c
   * false 
   * otherwise.
   */
  bool isMetre () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c mole
   *
   * @return @c true if the kind of this Unit is @c mole, @c false
   * otherwise. 
   */
  bool isMole () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c newton
   *
   * @return @c true if the kind of this Unit is @c newton, @c false
   * otherwise. 
   */
  bool isNewton () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c ohm
   *
   * @return @c true if the kind of this Unit is @c ohm, @c false
   * otherwise. 
   */
  bool isOhm () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c pascal
   *
   * @return @c true if the kind of this Unit is @c pascal, @c false
   * otherwise. 
   */
  bool isPascal () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c radian
   *
   * @return @c true if the kind of this Unit is @c radian, @c false
   * otherwise. 
   */
  bool isRadian () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c second
   *
   * @return @c true if the kind of this Unit is @c second, @c false
   * otherwise. 
   */
  bool isSecond () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c siemens
   *
   * @return @c true if the kind of this Unit is @c siemens, @c false
   * otherwise. 
   */
  bool isSiemens () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c sievert
   *
   * @return @c true if the kind of this Unit is @c sievert, @c false
   * otherwise. 
   */
  bool isSievert () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c steradian
   *
   * @return @c true if the kind of this Unit is @c steradian, @c false
   * otherwise. 
   */
  bool isSteradian () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c tesla
   *
   * @return @c true if the kind of this Unit is @c tesla, @c false
   * otherwise. 
   */
  bool isTesla () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c volt
   *
   * @return @c true if the kind of this Unit is @c volt, @c false
   * otherwise. 
   */
  bool isVolt () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c watt
   *
   * @return @c true if the kind of this Unit is @c watt, @c false
   * otherwise. 
   */
  bool isWatt () const;


  /**
   * Predicate for testing whether this Unit is of the kind @c weber
   *
   * @return @c true if the kind of this Unit is @c weber, @c false
   * otherwise. 
   */
  bool isWeber () const;


  /**
   * Predicate to test whether the "kind" attribute of this Unit has been set.
   * 
   * @return @c true if the "kind" attribute of this Unit has been set, @c
   * false otherwise.
   */
  bool isSetKind () const;


  /**
   * Sets the "kind" attribute value of this Unit.
   *
   * @param kind a value from the <a class="el"
   * href="#UnitKind_t">UnitKind_t</a> enumeration
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
   * @li LIBSBML_INVALID_ATTRIBUTE_VALUE
   */
  int setKind (UnitKind_t kind);


  /**
   * Sets the "exponent" attribute value of this Unit.
   *
   * @param value the integer to which the attribute "exponent" should be set
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
   */
  int setExponent (int value);


  /**
   * Sets the "scale" attribute value of this Unit.
   *
   * @param value the integer to which the attribute "scale" should be set
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
   */
  int setScale (int value);


  /**
   * Sets the "multipler" attribute value of this Unit.
   *
   * @param value the floating-point value to which the attribute
   * "multiplier" should be set
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
   * @li LIBSBML_UNEXPECTED_ATTRIBUTE
   */
  int setMultiplier (double value);


  /**
   * Sets the "offset" attribute value of this Unit.
   *
   * @param value the float-point value to which the attribute "offset"
   * should set
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
   * @li LIBSBML_UNEXPECTED_ATTRIBUTE
   *
   * @warning The "offset" attribute is only available in SBML Level&nbsp;2
   * Version&nbsp;1.  This attribute is not present in SBML Level&nbsp;2
   * Version&nbsp;2 or above.  When producing SBML models using these later
   * specifications, modelers and software tools need to account for units
   * with offsets explicitly.  The %SBML specification document offers a
   * number of suggestions for how to achieve this.  LibSBML methods such
   * as this one related to "offset" are retained for compatibility with
   * earlier versions of SBML Level&nbsp;2, but their use is strongly
   * discouraged.
   */
  int setOffset (double value);


  /**
   * Returns the libSBML type code of this object instance.
   *
   * @if clike LibSBML attaches an identifying code to every
   * kind of SBML object.  These are known as <em>SBML type codes</em>.
   * The set of possible type codes is defined in the enumeration
   * #SBMLTypeCode_t.  The names of the type codes all begin with the
   * characters @c SBML_. @endif@if java LibSBML attaches an
   * identifying code to every kind of SBML object.  These are known as
   * <em>SBML type codes</em>.  In other languages, the set of type codes
   * is stored in an enumeration; in the Java language interface for
   * libSBML, the type codes are defined as static integer constants in
   * interface class {@link libsbmlConstants}.  The names of the type codes
   * all begin with the characters @c SBML_. @endif
   *
   * @return the SBML type code for this object, or @c SBML_UNKNOWN (default).
   *
   * @see getElementName()
   */
  virtual SBMLTypeCode_t getTypeCode () const;


  /**
   * Returns the XML element name of this object, which for Unit, is
   * always @c "unit".
   * 
   * @return the name of this element, i.e., @c "unit". 
   */
  virtual const std::string& getElementName () const;


  /**
   * Predicate to test whether a given string is the name of a
   * predefined SBML unit.
   *
   * @param name a string to be tested against the predefined unit names
   *
   * @param level the Level of SBML for which the determination should be
   * made.  This is necessary because there are a few small differences
   * in allowed units between SBML Level&nbsp;1 and Level&nbsp;2.
   * 
   * @return @c true if @p name is one of the five SBML predefined unit
   * identifiers (@c "substance", @c "volume", @c "area", @c "length" or @c
   * "time"), @c false otherwise.
   *
   * @note The predefined unit identifiers @c "length" and @c "area" were
   * added in Level&nbsp;2 Version&nbsp;1
   */
  static bool isBuiltIn (const std::string& name, unsigned int level);


  /**
   * Predicate to test whether a given string is the name of a valid
   * base unit in SBML (such as @c "gram" or @c "mole").
   *
   * This method exists because prior to SBML Level&nbsp;2 Version&nbsp;3,
   * an enumeration called @c UnitKind was defined by SBML.  This enumeration
   * was removed in SBML Level&nbsp;2 Version&nbsp;3 and its values were
   * folded into the space of values of a type called @c UnitSId.  This method
   * therefore has less significance in SBML Level&nbsp;2 Version&nbsp;3
   * and Level&nbsp;2 Version&nbsp;4, but remains for backward
   * compatibility and support for reading models in older Versions of
   * Level&nbsp;2.
   *
   * @param name a string to be tested
   * 
   * @param level an unsigned int representing the SBML specification
   * Level 
   * 
   * @param version an unsigned int representing the SBML specification
   * Version
   * 
   * @return @c true if name is a valid UnitKind, @c false otherwise
   *
   * @note The allowed unit names differ between SBML Levels&nbsp;1
   * and&nbsp;2 and again slightly between Level&nbsp;2 Versions&nbsp;1
   * and&nbsp;2.
   */
  static bool isUnitKind (const std::string& name,
                          unsigned int level, unsigned int version);


  /** 
  * Predicate returning @c true or @c false depending on whether two
  * Unit objects are identical.
  *
  * Two Unit objects are considered to be @em identical if they match in
  * all attributes.  (Contrast this to the method
  * Unit::areEquivalent(Unit * unit1, %Unit * unit2), which compares
  * Unit objects only with respect to certain attributes.)
  *
  * @param unit1 the first Unit object to compare
  * @param unit2 the second Unit object to compare
  *
  * @return @c true if all the attributes of unit1 are identical
  * to the attributes of unit2, @c false otherwise.
  *
  * @see areEquivalent(Unit * unit1, %Unit * unit2)
  */
  static bool areIdentical(Unit * unit1, Unit * unit2);


  /** 
  * Predicate returning @c true or @c false depending on whether 
  * Unit objects are equivalent.
  *
  * Two Unit objects are considered to be @em equivalent if their "kind"
  * and "exponent" attributes are equal.  (Contrast this to the method
  * Unit::areIdentical(Unit * unit1, %Unit * unit2), which compares Unit
  * objects with respect to all attributes, not just the kind and
  * exponent.)
  *
  * @param unit1 the first Unit object to compare
  * @param unit2 the second Unit object to compare
  *
  * @return @c true if the "kind" and "exponent" attributes of unit1 are
  * identical to the kind and exponent attributes of unit2, @c false
  * otherwise.
  * 
  * @see areIdentical(Unit * unit1, %Unit * unit2)
  */
  static bool areEquivalent(Unit * unit1, Unit * unit2);


  /** 
  * Manipulates the attributes of the Unit to express the unit with the 
  * value of the scale attribute reduced to zero.
  *
  * For example, 1 millimetre can be expressed as a Unit with kind=@c
  * "metre" multiplier=@c "1" scale=@c "-3" exponent=@c "1". It can also be
  * expressed as a Unit with kind=@c "metre"
  * multiplier=<code>"0.001"</code> scale=@c "0" exponent=@c "1".
  *
  * @param unit the Unit object to manipulate.
   *
   * @return integer value indicating success/failure of the
   * function.  @if clike The value is drawn from the
   * enumeration #OperationReturnValues_t. @endif The possible values
   * returned by this function are:
   * @li LIBSBML_OPERATION_SUCCESS
  */
  static int removeScale(Unit * unit);


  /** 
  * Merges two Unit objects with the same "kind" attribute value into a
  * single Unit.
  * 
  * For example, the following,
  * @code
  * <unit kind="metre" exponent="2"/>
  * <unit kind="metre" exponent="1"/>
  * @endcode
  * would be merged to become
  * @code
  * <unit kind="metre" exponent="3"/>
  * @endcode
  *
  * @param unit1 the first Unit object; the result of the operation is
  * left as a new version of this unit, modified in-place.
  * 
  * @param unit2 the second Unit object to merge with the first
  */
  static void merge(Unit * unit1, Unit * unit2);


  /**
  * Returns a UnitDefinition object which contains the argument Unit
  * converted to the appropriate SI unit.
  *
  * @param unit the Unit object to convert to SI
  *
  * @return a UnitDefinition object containing the SI unit.
  */
  static UnitDefinition * convertToSI(const Unit * unit);


  /**
   * Predicate returning @c true or @c false depending on whether
   * all the required attributes for this Unit object
   * have been set.
   *
   * @note The required attributes for a Unit object are:
   * kind
   *
   * @return a boolean value indicating whether all the required
   * elements for this object have been defined.
   */
  virtual bool hasRequiredAttributes() const ;


protected:
  /** @cond doxygen-libsbml-internal */

  /* this is a constructor that takes no arguments and 
   * only exists because the validator code needs it
   */
  Unit ();


  /**
   * Subclasses should override this method to read values from the given
   * XMLAttributes set into their specific fields.  Be sure to call your
   * parents implementation of this method as well.
   */
  virtual void readAttributes (const XMLAttributes& attributes);


  /**
   * Subclasses should override this method to write their XML attributes
   * to the XMLOutputStream.  Be sure to call your parents implementation
   * of this method as well.
   */
  virtual void writeAttributes (XMLOutputStream& stream) const;

  /**
   * Predicate to test whether a given string is the name of a valid
   * base unit in SBML Level 1 (such as @c "gram" or @c "mole")
   *
   * @param name a string to be tested
   * 
   * @return @c true if name is a valid UnitKind, @c false otherwise
   */
  static bool isL1UnitKind (const std::string& name);


  /**
   * Predicate to test whether a given string is the name of a valid base
   * unit in SBML Level&nbsp;2 Version&nbsp;1 (such as @c "gram" or @c
   * "mole")
   *
   * @param name a string to be tested
   * 
   * @return @c true if name is a valid UnitKind, @c false otherwise
   */
  static bool isL2V1UnitKind (const std::string& name);

  /**
   * Predicate to test whether a given string is the name of a valid base
   * unit in SBML Level&nbsp;2 Version&nbsp;2, 3 or 4 (such as @c "gram" or @c
   * "mole")
   *
   * @param name a string to be tested
   * 
   * @return @c true if name is a valid UnitKind, @c false otherwise
   */
  static bool isL2UnitKind (const std::string& name);

  UnitKind_t  mKind;
  int         mExponent;
  int         mScale;
  double      mMultiplier;
  double      mOffset;  

  /* the validator classes need to be friends to access the 
   * protected constructor that takes no arguments
   */
  friend class Validator;
  friend class ConsistencyValidator;
  friend class IdentifierConsistencyValidator;
  friend class InternalConsistencyValidator;
  friend class L1CompatibilityValidator;
  friend class L2v1CompatibilityValidator;
  friend class L2v2CompatibilityValidator;
  friend class L2v3CompatibilityValidator;
  friend class L2v4CompatibilityValidator;
  friend class MathMLConsistencyValidator;
  friend class ModelingPracticeValidator;
  friend class OverdeterminedValidator;
  friend class SBOConsistencyValidator;
  friend class UnitConsistencyValidator;


  /** @endcond doxygen-libsbml-internal */
};



class LIBSBML_EXTERN ListOfUnits : public ListOf
{
public:
  /**
   * Creates and returns a deep copy of this ListOfUnits.
   *
   * @return a (deep) copy of this ListOfUnits.
   */
  virtual ListOfUnits* clone () const;


  /**
   * Returns the libSBML type code for this %SBML object.
   * 
   * @if clike LibSBML attaches an identifying code to every
   * kind of SBML object.  These are known as <em>SBML type codes</em>.
   * The set of possible type codes is defined in the enumeration
   * #SBMLTypeCode_t.  The names of the type codes all begin with the
   * characters @c SBML_. @endif@if java LibSBML attaches an
   * identifying code to every kind of SBML object.  These are known as
   * <em>SBML type codes</em>.  In other languages, the set of type codes
   * is stored in an enumeration; in the Java language interface for
   * libSBML, the type codes are defined as static integer constants in
   * interface class {@link libsbmlConstants}.  The names of the type codes
   * all begin with the characters @c SBML_. @endif
   *
   * @return the SBML type code for this object, or @c SBML_UNKNOWN (default).
   *
   * @see getElementName()
   */
  virtual SBMLTypeCode_t getTypeCode () const { return SBML_LIST_OF; };


  /**
   * Returns the libSBML type code for the objects contained in this ListOf
   * (i.e., Unit objects, if the list is non-empty).
   * 
   * @if clike LibSBML attaches an identifying code to every
   * kind of SBML object.  These are known as <em>SBML type codes</em>.
   * The set of possible type codes is defined in the enumeration
   * #SBMLTypeCode_t.  The names of the type codes all begin with the
   * characters @c SBML_. @endif@if java LibSBML attaches an
   * identifying code to every kind of SBML object.  These are known as
   * <em>SBML type codes</em>.  In other languages, the set of type codes
   * is stored in an enumeration; in the Java language interface for
   * libSBML, the type codes are defined as static integer constants in
   * interface class {@link libsbmlConstants}.  The names of the type codes
   * all begin with the characters @c SBML_. @endif
   * 
   * @return the SBML type code for the objects contained in this ListOf
   * instance, or @c SBML_UNKNOWN (default).
   *
   * @see getElementName()
   */
  virtual SBMLTypeCode_t getItemTypeCode () const;


  /**
   * Returns the XML element name of this object.
   *
   * For ListOfUnits, the XML element name is @c "listOfUnits".
   * 
   * @return the name of this element, i.e., @c "listOfUnits".
   */
  virtual const std::string& getElementName () const;


  /**
   * Get a Unit from the ListOfUnits.
   *
   * @param n the index number of the Unit to get.
   * 
   * @return the nth Unit in this ListOfUnits.
   *
   * @see size()
   */
  virtual Unit * get(unsigned int n); 


  /**
   * Get a Unit from the ListOfUnits.
   *
   * @param n the index number of the Unit to get.
   * 
   * @return the nth Unit in this ListOfUnits.
   *
   * @see size()
   */
  virtual const Unit * get(unsigned int n) const; 


  /**
   * Removes the nth item from this ListOfUnits items and returns a pointer to
   * it.
   *
   * The caller owns the returned item and is responsible for deleting it.
   *
   * @param n the index of the item to remove
   *
   * @see size()
   */
  virtual Unit* remove (unsigned int n);


  /** @cond doxygen-libsbml-internal */

  /**
   * Get the ordinal position of this element in the containing object
   * (which in this case is the Model object).
   *
   * @return the ordinal position of the element with respect to its
   * siblings, or @c -1 (default) to indicate the position is not significant.
   */
  virtual int getElementPosition () const;

  /** @endcond doxygen-libsbml-internal */


protected:
  /** @cond doxygen-libsbml-internal */

  /**
   * Create a ListOfUnits object corresponding to the next token
   * in the XML input stream.
   * 
   * @return the %SBML object corresponding to next XMLToken in the
   * XMLInputStream, or @c NULL if the token was not recognized.
   */
  virtual SBase* createObject (XMLInputStream& stream);

  /** @endcond doxygen-libsbml-internal */
};

LIBSBML_CPP_NAMESPACE_END

#endif  /* __cplusplus */


#ifndef SWIG

LIBSBML_CPP_NAMESPACE_BEGIN
BEGIN_C_DECLS

/*-----------------------------------------------------------------------------
 * See the .cpp file for the documentation of the following functions.
 *---------------------------------------------------------------------------*/


LIBSBML_EXTERN
Unit_t *
Unit_create (unsigned int level, unsigned int version);


LIBSBML_EXTERN
Unit_t *
Unit_createWithNS (SBMLNamespaces_t *sbmlns);


LIBSBML_EXTERN
void
Unit_free (Unit_t *u);


LIBSBML_EXTERN
Unit_t *
Unit_clone (const Unit_t* c);


LIBSBML_EXTERN
void
Unit_initDefaults (Unit_t *u);


LIBSBML_EXTERN
const XMLNamespaces_t *
Unit_getNamespaces(Unit_t *c);


LIBSBML_EXTERN
UnitKind_t
Unit_getKind (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_getExponent (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_getScale (const Unit_t *u);


LIBSBML_EXTERN
double
Unit_getMultiplier (const Unit_t *u);


LIBSBML_EXTERN
double
Unit_getOffset (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isAmpere (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isBecquerel (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isCandela (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isCelsius (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isCoulomb (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isDimensionless (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isFarad (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isGram (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isGray (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isHenry (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isHertz (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isItem (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isJoule (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isKatal (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isKelvin (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isKilogram (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isLitre (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isLumen (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isLux (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isMetre (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isMole (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isNewton (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isOhm (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isPascal (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isRadian (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isSecond (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isSiemens (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isSievert (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isSteradian (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isTesla (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isVolt (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isWatt (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isWeber (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_isSetKind (const Unit_t *u);


LIBSBML_EXTERN
int
Unit_setKind (Unit_t *u, UnitKind_t kind);


LIBSBML_EXTERN
int
Unit_setExponent (Unit_t *u, int value);


LIBSBML_EXTERN
int
Unit_setScale (Unit_t *u, int value);


LIBSBML_EXTERN
int
Unit_setMultiplier (Unit_t *u, double value);


LIBSBML_EXTERN
int
Unit_setOffset (Unit_t *u, double value);


LIBSBML_EXTERN
int
Unit_isBuiltIn (const char *name, unsigned int level);

LIBSBML_EXTERN
int 
Unit_areIdentical(Unit_t * unit1, Unit_t * unit2);

LIBSBML_EXTERN
int
Unit_areEquivalent(Unit_t * unit1, Unit_t * unit2);

LIBSBML_EXTERN
int 
Unit_removeScale(Unit_t * unit);

LIBSBML_EXTERN
void 
Unit_merge(Unit_t * unit1, Unit_t * unit2);

LIBSBML_EXTERN
UnitDefinition_t * 
Unit_convertToSI(Unit_t * unit);

END_C_DECLS
LIBSBML_CPP_NAMESPACE_END

#endif  /* !SWIG  */
#endif  /* Unit_h */
