/*
 *  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, G1K 7P4
 *  http://vision.gel.ulaval.ca
 *
 */

/*!
 *  \file   beagle/Tokenizer.hpp
 *  \brief  Definition of class Tokenizer.
 *  \author Marc Parizeau
 *  \author Christian Gagne
 *  $Revision: 1.3 $
 *  $Date: 2004/04/25 23:12:21 $
 */

#ifndef Beagle_Tokenizer_hpp
#define Beagle_Tokenizer_hpp

#include <iostream>
#include <string>
#include <set>
#include <stdlib.h>

#include "beagle/config.hpp"
#include "beagle/macros.hpp"
#include "beagle/Object.hpp"


namespace Beagle {

// Forward declarations
template <class T, class BaseType> class PointerT;
template <class T, class BaseType> class AllocatorT;
template <class T, class BaseType> class ContainerT;


/*!
 *  \class Tokenizer beagle/Tokenizer.hpp "beagle/Tokenizer.hpp"
 *  \brief Input stream tokenizer.
 *  \ingroup OOF
 *  \ingroup IO
 *  \ingroup Utils
 *  \note  This class is mostly based on class XML::Tokenizer of Marc Parizeau, with some
 *    minor modifications to comply with Open BEAGLE conventions.
 *
 *  This class is for tokenizing an input stream. Tokens are either strings of characters seperated 
 *  by white space, or special single characters. By default, there are no special single character
 *  tokens, and white space characters are spaces, tabs, cariage returns, and line feeds. But these 
 *  can be changed using the Tokenizer::setSingleCharTokens and Tokenizer::setWhiteSpace functions,
 *  respectively. Multiple character tokens can also be specified using function
 *  Tokenizer::addStringToken. However, these have lower priority than single character tokens. For
 *  instance, if "a" is a single character token and "ab" is a multiple character token, than string
 *  "abcd" will be tokenized in "a"+"bcd". But, if "bc" is also a multiple character token, than 
 *  "abcd" will be tokenized in "a"+"bc"+"d".
 */
class Tokenizer : public Object {

public:

  //! Tokenizer allocator type.
  typedef AllocatorT< Tokenizer, Object::Alloc >
          Alloc;
  //! Tokenizer handle type.
  typedef PointerT< Tokenizer, Object::Handle >
          Handle;
  //! Tokenizer bag type.
  typedef ContainerT< Tokenizer, Object::Bag >
          Bag;

           Tokenizer();
  explicit Tokenizer(std::istream& inStream);
  virtual ~Tokenizer() { }
  
  std::string getNextToken();
  bool        getNextToken(std::string& outToken);

  /*!
   *  \brief Add string \c inToken to the multiple character token set.
   *  \param inToken Token added to the string token pool.
   */
  void addStringToken(const std::string& inToken)
  {
    mStringTokens.insert(inToken);
  }

  /*!
   *  \brief Remove all multiple character tokens.
   */
  void clearStringTokens()
  {
    mStringTokens.clear();
  }

  /*!
   *  \return Current line number.
   */
  unsigned int getLineNumber() const
  {
    return mLine;
  }

  /*!
   *   \return Pointer to the default input stream.
   */
  std::istream* getStreamPtr()
  {
    return mStream;
  }

  /*!
   *  \return Name of default input stream.
   */
  const std::string& getStreamName() const
  {
    return mName;
  }

  /*!
   *  \return Single character delimiters.
   */
  const std::string& getSingleCharTokens() const
  {
    return mSingleCharTokens;
  }

  /*!
   *  \return White space delimiters.
   */
  const std::string& getWhiteSpace() const
  {
    return mWhiteSpace;
  }

  /*!
   *  \brief Remove multiple character token \c inToken from string token pool.
   *  \param inToken Token to remove.
   */
  void removeStringToken(const std::string& inToken)
  {
    mStringTokens.erase(inToken);
  }

  /*!
   *  \brief Set current line number.
   *  \param inLine new current line number
   */
  void setLineNumber(unsigned int inLine)
  {
    mLine = inLine;
  }

  /*!
   *  \brief Set default input stream.
   *  \param inStream Input stream to use.
   */
  void setStream(std::istream& inStream)
  {
    mStream = &inStream;
  }

  /*!
   *  \brief Set name of default input stream.
   *  \param inName New name of the input stream.
   */
  void setStreamName(const std::string& inName)
  {
    mName = inName;
  }

  /*!
   *  \brief Set single character delimiters to \c inTokens.
   *  \param inTokens New single character delimiters.
   */
  void setSingleCharTokens(const std::string &inTokens)
  {
    mSingleCharTokens = inTokens;
  }

  /*!
   *  \brief Set white space delimiters to \c inWhite.
   *  \param inWhite New white space delimiters.
   */
  void setWhiteSpace(const std::string &inWhite)
  {
    mWhiteSpace = inWhite;
  }

protected:
  unsigned int          mLine;              //!< Current line number.
  std::string           mName;              //!< Name of default input stream.
  std::istream*         mStream;            //!< Default input stream.
  std::string           mWhiteSpace;        //!< White space delimiters.
  std::string           mSingleCharTokens;  //!< Single character tokens.
  std::set<std::string> mStringTokens;      //!< Multiple character tokens.

};

}

#endif // Beagle_Tokenizer_hpp

