/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This file contains the declaration and implementation of the        //
// CFileStream class.                                                  //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
#ifndef __CFILESTREAM_HPP__
#define __CFILESTREAM_HPP__


#include <queue>
#include <fstream>
#include <string>
#include "ILexerStream.hpp"


/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This class is the implementation of the ILexerStream interface for  //
// a normal file.                                                      //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
class CFileStream : public ILexerStream
{
public:
  CFileStream(const std::string& filename);

  inline bool failed();

  // ILexerStream implementation
  ~CFileStream();
  char get();
  void put(char c);
  bool finished();

private:
  std::ifstream    i;
  std::queue<char> putbuffer;
};




// Constructor
inline CFileStream::CFileStream(const std::string& filename)
  : i(filename.c_str(), std::ios::binary)
{
}

// This function tells if the stream is in an incorrect state and
// therefore cannot be used
inline bool CFileStream::failed()
{
  return i.fail();
}

// Destructor
inline CFileStream::~CFileStream()
{
  i.close();
}




/////////////////////////////////////////////////////////////////////////
//                                                                     //
// Implementation of the ILexerStream interface.  See the              //
// ILexerStream declaration for meaning of each function.              //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
inline char CFileStream::get()
{
  char returnValue;
  if (putbuffer.empty())
    {
      returnValue = i.get();
    }
  else
    {
      returnValue = putbuffer.front();
      putbuffer.pop();
    }
  return returnValue;
}

inline void CFileStream::put(char c)
{
  putbuffer.push(c);
}

inline bool CFileStream::finished()
{
  if (putbuffer.empty())
    {
      char c = get();
      if (!i.eof())
        putbuffer.push(c);
    }
  return putbuffer.empty();
}


#endif // __CFILESTREAM_HPP__
