/**
 * @file    SpeciesType.cpp
 * @brief   Implementation of SpeciesType and ListOfSpeciesTypes.
 * @author  Ben Bornstein
 *
 * $Id: SpeciesType.cpp 8951 2009-01-21 02:42:32Z mhucka $
 * $HeadURL: https://sbml.svn.sourceforge.net/svnroot/sbml/trunk/libsbml/src/sbml/SpeciesType.cpp $
 *
 *<!---------------------------------------------------------------------------
 * 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
 *----------------------------------------------------------------------- -->*/

#include <sbml/xml/XMLNode.h>
#include <sbml/xml/XMLAttributes.h>
#include <sbml/xml/XMLInputStream.h>
#include <sbml/xml/XMLOutputStream.h>

#include <sbml/SBO.h>
#include <sbml/SBMLVisitor.h>
#include <sbml/SBMLError.h>
#include <sbml/SBMLDocument.h>
#include <sbml/Model.h>
#include <sbml/SpeciesType.h>

/** @cond doxygen-ignored */

using namespace std;

/** @endcond doxygen-ignored */


/*
 * Creates a new SpeciesType, optionally with its id and name
 * attributes set.
 */
SpeciesType::SpeciesType (const std::string& id, const std::string& name) :
  SBase(id, name)
{
}


/** @cond doxygen-libsbml-internal */
SpeciesType::SpeciesType (unsigned int level, unsigned int version,
                          XMLNamespaces *xmlns) :
   SBase ("", "", -1)
{
  mObjectLevel = level;
  mObjectVersion = version;
  if (xmlns) setNamespaces(xmlns);;
}
/** @endcond doxygen-libsbml-internal */

                          

/*
 * Destroys this SpeciesType.
 */
SpeciesType::~SpeciesType ()
{
}


/*
 * Copy constructor. Creates a copy of this SpeciesType.
 */
SpeciesType::SpeciesType(const SpeciesType& orig) :
      SBase(orig)
{
}


/*
 * Assignment operator
 */
SpeciesType& SpeciesType::operator=(const SpeciesType& rhs)
{
  this->SBase::operator =(rhs);
  return *this;
}


/*
 * Accepts the given SBMLVisitor.
 *
 * @return the result of calling <code>v.visit()</code>, which indicates
 * whether or not the Visitor would like to visit the Model's next
 * SpeciesType (if available).
 */
bool
SpeciesType::accept (SBMLVisitor& v) const
{
  return v.visit(*this);
}


/*
 * @return a (deep) copy of this SpeciesType.
 */
SpeciesType*
SpeciesType::clone () const
{
  return new SpeciesType(*this);
}


/*
 * @return the SBMLTypeCode_t of this SBML object or SBML_UNKNOWN
 * (default).
 *
 * @see getElementName()
 */
SBMLTypeCode_t
SpeciesType::getTypeCode () const
{
  return SBML_SPECIES_TYPE;
}


/*
 * @return the name of this element ie "speciesType".
 */
const string&
SpeciesType::getElementName () const
{
  static const string name = "speciesType";
  return name;
}


/** @cond doxygen-libsbml-internal */
/*
 * 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.
 */
void
SpeciesType::readAttributes (const XMLAttributes& attributes)
{
  SBase::readAttributes(attributes);

  const unsigned int level = getLevel();
  const unsigned int version = getVersion();

  if (level < 2 || (level == 2 && version == 1))
  {
    logError(NotSchemaConformant, getLevel(), getVersion(),
	      "SpeciesType is not a valid component for this level/version.");
    return;
  }

  std::vector<std::string> expectedAttributes;
  expectedAttributes.clear();

  expectedAttributes.push_back("name");
  expectedAttributes.push_back("id");
  expectedAttributes.push_back("metaid");

  if (!(level == 2 && version < 3))
  {
    expectedAttributes.push_back("sboTerm");
  }

  // check that all attributes are expected
  for (int i = 0; i < attributes.getLength(); i++)
  {
    std::vector<std::string>::const_iterator end = expectedAttributes.end();
    std::vector<std::string>::const_iterator begin = expectedAttributes.begin();
    std::string name = attributes.getName(i);
    if (std::find(begin, end, name) == end)
    {
      logUnknownAttribute(name, level, version, "<speciesType>");
    }
  }

  //
  // id: SId  { use="required" }  (L2v2->)
  //
  bool assigned = attributes.readInto("id", mId, getErrorLog(), true);
  if (assigned && mId.size() == 0)
  {
    logEmptyString("id", level, version, "<speciesType>");
  }
  SBase::checkIdSyntax();

  //
  // name: string  { use="optional" }  (L2v2->)
  //
  attributes.readInto("name", mName);

  //
  // sboTerm: SBOTerm { use="optional" }  (L2v3->)
  //
  if (!(level == 2 && version < 3))
  {
    mSBOTerm = SBO::readTerm(attributes, this->getErrorLog());
  }
}
/** @endcond doxygen-libsbml-internal */


/** @cond doxygen-libsbml-internal */
/*
 * 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.
 */
void
SpeciesType::writeAttributes (XMLOutputStream& stream) const
{
  SBase::writeAttributes(stream);

  const unsigned int level = getLevel();
  const unsigned int version = getVersion();

  /* invalid level/version */
  if (level < 2 || (level == 2 && version == 1))
  {
    return;
  }

  //
  // id: SId  { use="required" }  (L2v2 ->)
  //
  stream.writeAttribute("id", mId);

  //
  // name: string  { use="optional" }  (L2v2 ->)
  //
  stream.writeAttribute("name", mName);
  //
  // sboTerm: SBOTerm { use="optional" }  (L2v3 ->)
  //
  if (!(level == 2 && version < 3)) 
  {
    SBO::writeTerm(stream, mSBOTerm);
  }
}
/** @endcond doxygen-libsbml-internal */


/*
 * @return a (deep) copy of this ListOfSpeciesTypes.
 */
ListOfSpeciesTypes*
ListOfSpeciesTypes::clone () const
{
  return new ListOfSpeciesTypes(*this);
}


/*
 * @return the SBMLTypeCode_t of SBML objects contained in this ListOf or
 * SBML_UNKNOWN (default).
 */
SBMLTypeCode_t
ListOfSpeciesTypes::getItemTypeCode () const
{
  return SBML_SPECIES_TYPE;
}


/*
 * @return the name of this element ie "listOfSpeciesTypes".
 */
const string&
ListOfSpeciesTypes::getElementName () const
{
  static const string name = "listOfSpeciesTypes";
  return name;
}


/* return nth item in list */
SpeciesType *
ListOfSpeciesTypes::get(unsigned int n)
{
  return static_cast<SpeciesType*>(ListOf::get(n));
}


/* return nth item in list */
const SpeciesType *
ListOfSpeciesTypes::get(unsigned int n) const
{
  return static_cast<const SpeciesType*>(ListOf::get(n));
}


/* return item by id */
SpeciesType*
ListOfSpeciesTypes::get (const std::string& sid)
{
  return static_cast<SpeciesType*>(ListOf::get(sid));
}


/* return item by id */
const SpeciesType*
ListOfSpeciesTypes::get (const std::string& sid) const
{
  return static_cast<const SpeciesType*>(ListOf::get(sid));
}


/* Removes the nth item from this list */
SpeciesType*
ListOfSpeciesTypes::remove (unsigned int n)
{
   return static_cast<SpeciesType*>(ListOf::remove(n));
}


/* Removes item in this list by id */
SpeciesType*
ListOfSpeciesTypes::remove (const std::string& sid)
{
   return static_cast<SpeciesType*>(ListOf::remove(sid));
}


/** @cond doxygen-libsbml-internal */
/*
 * @return the ordinal position of the element with respect to its siblings
 * or -1 (default) to indicate the position is not significant.
 */
int
ListOfSpeciesTypes::getElementPosition () const
{
  return 4;
}
/** @endcond doxygen-libsbml-internal */


/** @cond doxygen-libsbml-internal */
/*
 * @return the SBML object corresponding to next XMLToken in the
 * XMLInputStream or NULL if the token was not recognized.
 */
SBase*
ListOfSpeciesTypes::createObject (XMLInputStream& stream)
{
  const string& name   = stream.peek().getName();
  SBase*        object = 0;


  if (name == "speciesType")
  {
    object = new SpeciesType();
    mItems.push_back(object);
  }

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



/** @cond doxygen-c-only */


/**
 * Creates a new, empty SpeciesType and returns a pointer to it.
 *
 * It is worth emphasizing that the structure returned by this constructor
 * is empty and that there are no default values assigned to such things as
 * identifiers and names.  Note that in SBML Level 2 and beyond, the
 * "id" (identifier) attribute of a SpeciesType is required to have a
 * value.  Thus, callers are cautioned to assign a value after calling this
 * constructor, for example using SpeciesType_setName().
 *
 * @return a pointer to the newly created SpeciesType structure.
 */
LIBSBML_EXTERN
SpeciesType_t *
SpeciesType_create ()
{
  return new(nothrow) SpeciesType;
}


/**
 * Creates a new SpeciesType with the given @p id and @p name attribute
 * values.
 *
 * In SBML Level 2 and beyond, the identifier attribute of a
 * SpeciesType is required to have a value, but the name is optional.
 * Programs calling this function can legitimately use an empty string for
 * the @p name argument.
 *
 * @param sid the value to assign as the identifier of this SpeciesType
 * @param name the value to assign as the name of this SpeciesType
 *
 * @return a pointer to the newly created SpeciesType_t structure.
 */
LIBSBML_EXTERN
SpeciesType_t *
SpeciesType_createWith (const char *sid, const char *name)
{
  return new(nothrow) SpeciesType(sid ? sid : "", name ? name : "");
}


/** @cond doxygen-libsbml-internal */
/**
 * Creates a new SpeciesType_t structure using the given SBML @p 
 * level and @p version values and a set of XMLNamespaces.
 *
 * @param level an unsigned int, the SBML Level to assign to this 
 * SpeciesType
 *
 * @param version an unsigned int, the SBML Version to assign to this
 * SpeciesType
 * 
 * @param xmlns XMLNamespaces, a pointer to an array of XMLNamespaces to
 * assign to this SpeciesType
 *
 * @return a pointer to the newly created SpeciesType_t structure.
 *
 * @note Once a SpeciesType 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 SpeciesType.  Despite this, the ability 
 * to supply the values at creation time is an important aid to creating 
 * valid SBML.  Knowledge of the intended 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.
 */
LIBSBML_EXTERN
SpeciesType_t *
SpeciesType_createWithLevelVersionAndNamespaces (unsigned int level,
              unsigned int version, XMLNamespaces_t *xmlns)
{
  return new(nothrow) SpeciesType(level, version, xmlns);
}
/** @endcond doxygen-libsbml-internal */


/**
 * Frees the given SpeciesType_t structure.
 *
 * @param ct the SpeciesType_t structure to be freed.
 */
LIBSBML_EXTERN
void
SpeciesType_free (SpeciesType_t *st)
{
  delete st;
}


/**
 * Creates a deep copy of the given SpeciesType_t structure
 * 
 * @param ct the SpeciesType_t structure to be copied
 * 
 * @return a (deep) copy of this SpeciesType_t structure.
 */
LIBSBML_EXTERN
SpeciesType_t *
SpeciesType_clone (const SpeciesType_t *st)
{
  return static_cast<SpeciesType*>( st->clone() );
}


/**
 * Returns a list of XMLNamespaces_t associated with this SpeciesType_t
 * structure.
 *
 * @param st the SpeciesType_t structure
 * 
 * @return pointer to the XMLNamespaces_t structure associated with 
 * this SBML object
 */
LIBSBML_EXTERN
const XMLNamespaces_t *
SpeciesType_getNamespaces(SpeciesType_t *st)
{
  return st->getNamespaces();
}


/**
 * Takes a SpeciesType_t structure and returns its identifier.
 *
 * @param ct the SpeciesType_t structure whose identifier is sought
 * 
 * @return the identifier of this SpeciesType_t, as a pointer to a string.
 */
LIBSBML_EXTERN
const char *
SpeciesType_getId (const SpeciesType_t *st)
{
  return st->isSetId() ? st->getId().c_str() : NULL;
}


/**
 * Takes a SpeciesType_t structure and returns its name.
 *
 * @param ct the SpeciesType_t whose name is sought.
 *
 * @return the name of this SpeciesType_t, as a pointer to a string.
 */
LIBSBML_EXTERN
const char *
SpeciesType_getName (const SpeciesType_t *st)
{
  return st->isSetName() ? st->getName().c_str() : NULL;
}


/**
 * Predicate returning @c true or @c false depending on whether the given
 * SpeciesType_t structure's identifier has been set.
 *
 * @param ct the SpeciesType_t structure to query
 * 
 * @return @c non-zero (true) if the "id" field of the given
 * SpeciesType has been set, zero (false) otherwise.
 */
LIBSBML_EXTERN
int
SpeciesType_isSetId (const SpeciesType_t *st)
{
  return static_cast<int>( st->isSetId() );
}


/**
 * Predicate returning @c true or @c false depending on whether the given
 * SpeciesType_t structure's name has been set.
 *
 * @param ct the SpeciesType_t structure to query
 * 
 * @return @c non-zero (true) if the "name" field of the given
 * SpeciesType has been set, zero (false) otherwise.
 */
LIBSBML_EXTERN
int
SpeciesType_isSetName (const SpeciesType_t *st)
{
  return static_cast<int>( st->isSetName() );
}


/**
 * Assigns the identifier of a SpeciesType_t structure.
 *
 * This makes a copy of the string passed as the argument @p sid.
 *
 * @param ct the SpeciesType_t structure to set.
 * @param sid the string to use as the identifier.
 */
LIBSBML_EXTERN
void
SpeciesType_setId (SpeciesType_t *st, const char *sid)
{
  (sid == NULL) ? st->unsetId() : st->setId(sid);
}


/**
 * Assign the name of a SpeciesType_t structure.
 *
 * This makes a copy of the string passed as the argument @p name.
 *
 * @param ct the SpeciesType_t structure to set.
 * @param name the string to use as the name.
 */
LIBSBML_EXTERN
void
SpeciesType_setName (SpeciesType_t *st, const char *name)
{
  (name == NULL) ? st->unsetName() : st->setName(name);
}


/**
 * Unsets the name of a SpeciesType.
 * 
 * @param ct the SpeciesType_t structure whose name is to be unset.
 */
LIBSBML_EXTERN
void
SpeciesType_unsetName (SpeciesType_t *st)
{
  st->unsetName();
}



/** @endcond doxygen-c-only */
