/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This file contains the declaration of the CScanner class.           //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
#ifndef __CSCANNER_HPP__
#define __CSCANNER_HPP__


#include <memory>
#include <string>
#include <vector>
#include "CSurface.hpp"

class CLexer;
class CScene;


/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This class is the actual parser of the langage used to describe     //
// scenes.  It is an implementation of a top-down recursive predictive //
// parser of a very simple grammer.  It does not handle strings        //
// directly, it uses the tokens given to it by a lexer.                //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
class CScanner
{
public:
  CScanner(CLexer *pLexer) : m_pLexer(pLexer) {}
  CScene* parse();

private:
  std::auto_ptr<CLexer>   m_pLexer;
  std::vector<CSurface*>  m_vSurfaces;

  inline void      addSurface(CSurface *pSurface);
  inline CSurface* getSurface(const std::string& name) const;
  inline CSurface* instance(const std::string& strSurfaceName) const;

  // Grammar rules
  CScene* scene();
  int     modes();
  void    statement_list(CScene *pCScene);
  void    surfaceproperty_list(CSurface *pSurface);
  void    property_list(CPropertyObject *pObject);

  CColor  color();
  CVector vector();
  int     integer();
  real_t  number();
};




// This function adds a surface to the list of created surfaces held
// by the parser
inline void CScanner::addSurface(CSurface *pSurface)
{
  POP_ASSERT(pSurface != NULL, "Trying to add NULL surface");
  m_vSurfaces.push_back(pSurface);
}

// This function tries to instanciate a object with a given name, if
// this object has already been created by previous definitions in the
// scene description
inline CSurface* CScanner::instance(const std::string& strObjectName) const
{
  std::vector<CSurface*>::const_iterator it;
  for (it = m_vSurfaces.begin(); it != m_vSurfaces.end(); ++it)
    if ((*it)->getName() == strObjectName)
      {
        POP_ASSERT((*it) != NULL, "Trying to instance NULL surface");
        return (*it)->Copy();
      }

  std::string message = "No object named \"";
  message += strObjectName;
  message += "\"";
  throw message;
}


// This function returns a surface from the list held by the parser,
// identified by its name
inline CSurface *CScanner::getSurface(const std::string& name) const
{
  std::vector<CSurface*>::const_iterator it;
  for (it = m_vSurfaces.begin();
       it != m_vSurfaces.end();
       ++it)
    {
      if ((*it)->getName() == name)
        return (*it);
    }

  // If we are here, the surface was not found
  std::string message = "Surface \"";
  message += name;
  message += "\" does not exist.";
  throw message;
}


#endif // __CSCANNER_HPP__
