/*
 *  Open BEAGLE
 *  Copyright (C) 2001-2004 by Christian Gagne and Marc Parizeau
 *
 *  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; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *  Laboratoire de Vision et Systemes Numeriques
 *  Departement de genie electrique et de genie informatique
 *  Universite Laval, Quebec, Canada, G1V 4J7
 *  http://vision.gel.ulaval.ca
 *
 */

/*!
 *  \file   beagle/GP/TokenT.hpp
 *  \brief  Definition of the templated class GP::TokenT.
 *  \author Christian Gagne
 *  \author Marc Parizeau
 *  $Revision: 1.2 $
 *  $Date: 2004/01/15 21:08:56 $
 */

/*!
 *  \defgroup FunctPrimit Functional GP Primitives
 *  \ingroup Primit
 *  \brief Various GP primitives for different purpose (terminals, ADF, randomly generated
 *    ephemerals), part of the GP primitives module.
 */

#ifndef Beagle_GP_TokenT_hpp
#define Beagle_GP_TokenT_hpp

#include <string>

#include "beagle/config.hpp"
#include "beagle/macros.hpp"
#include "beagle/Object.hpp"
#include "beagle/AllocatorT.hpp"
#include "beagle/PointerT.hpp"
#include "beagle/ContainerT.hpp"
#include "beagle/GP/Primitive.hpp"
#include "beagle/GP/PrimitiveInline.hpp"
#include "beagle/GP/Context.hpp"
#include "beagle/GP/Datum.hpp"

#ifdef BEAGLE_HAVE_RTTI
#include <typeinfo>
#endif // BEAGLE_HAVE_RTTI


namespace Beagle {
namespace GP {

/*!
 *  \class TokenT beagle/GP/TokenT.hpp "beagle/GP/TokenT.hpp"
 *  \brief GP simple token terminal primitive class.
 *  \param T Type of the token contained.
 *  \ingroup GPF
 *  \ingroup Primit
 *  \ingroup FunctPrimit
 */
template <class T>
class TokenT : public Primitive {

public:

  //! GP::TokenT allocator type.
  typedef AllocatorT<TokenT<T>,Primitive::Alloc>
          Alloc;
  //! GP::TokenT handle type.
  typedef PointerT<TokenT<T>,Primitive::Handle>
          Handle;
  //! GP::TokenT bag type.
  typedef ContainerT<TokenT<T>,Primitive::Bag>
          Bag;

  explicit TokenT(std::string inName="TOKEN");
  explicit TokenT(std::string inName, const T& inToken);
  virtual ~TokenT() { }

  virtual std::string getReturnType() const;
  virtual void        getValue(Object& outValue);
  virtual void        execute(GP::Datum& outResult, GP::Context& ioContext);
  virtual void        setValue(const Object& inValue);

  /*!
   *  \brief Get the value of the token (const version).
   *  \return The token value.
   */
  inline const T& getToken() const
  {
    return mToken;
  }

  /*!
   *  \brief Get the value of the token.
   *  \return The token value.
   */
  inline T& getToken()
  {
    return mToken;
  }

  /*!
   *  \brief Set the value of the token.
   *  \param inToken Value of the token.
   */
  inline void setToken(const T& inToken)
  {
    mToken = inToken;
  }

protected:
  T mToken;  //!< Value of the token.

};

}
}


/*!
 *  \brief Construct a new token terminal primitive.
 *  \param inName Name of the token terminal primitive.
 */
template <class T>
Beagle::GP::TokenT<T>::TokenT(std::string inName) :
  Beagle::GP::Primitive(0, inName)
{ }


/*!
 *  \brief Construct a new token terminal primitive.
 *  \param inName Name of the token terminal primitive.
 *  \param inToken Initial value of the token terminal.
 */
template <class T>
Beagle::GP::TokenT<T>::TokenT(std::string inName, const T& inToken) :
  Beagle::GP::Primitive(0, inName),
  mToken(inToken)
{ }


/*!
 *  \brief Return the string tagging the type of data returned but the primitive TokenT.
 *  \return String tagging the type of data returned.
 *  \throw InternalException If RTTI is disabled and the method is not properly overdefined.
 */
template <class T>
std::string Beagle::GP::TokenT<T>::getReturnType() const
{
#ifdef BEAGLE_HAVE_RTTI
  return typeid(T).name();
#else  // BEAGLE_HAVE_RTTI
  throw Beagle_UndefinedMethodInternalExceptionM("getReturnType","GP::TokenT");
  return "";
#endif // BEAGLE_HAVE_RTTI
}


/*!
 *  \brief Get the primitive value.
 *  \param outValue Object in which the actual primitive value is written.
 */
template <class T>
void Beagle::GP::TokenT<T>::getValue(Beagle::Object& outValue)
{
  T& lValueT = castObjectT<T&>(outValue);
  lValueT = mToken;
}


/*!
 *  \brief Execute the characteristic operation of the token terminal.
 *  \param outResult Result of the operation (copy of the token).
 *  \param ioContext Evolutionary context.
 */
template <class T>
void Beagle::GP::TokenT<T>::execute(Beagle::GP::Datum& outResult, Beagle::GP::Context& ioContext)
{
  T& lResult = castObjectT<T&>(outResult);
  lResult = mToken;
}


/*!
 *  \brief Set the value of the variable, in this case the value of the token.
 *  \param inValue Value of the variable.
 */
template <class T>
void Beagle::GP::TokenT<T>::setValue(const Beagle::Object& inValue)
{
  const T& lValueT = castObjectT<const T&>(inValue);
  mToken = lValueT;
}


#endif // Beagle_GP_TokenT_hpp
