#ifndef RAWINTERPRETER_H
#define RAWINTERPRETER_H

#include <cassert>
#include <string>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

#include <rpn.h>
#include <singleton.h>


// Helper class for fdatainterp.
// Funtion builder - build function and instanciate. 
class fbuildbase
{
public:

  virtual ~fbuildbase() {}

  // Name of function. 
  virtual string const name() const { return string(); }
  // Create a function and transfer/execute on the data stack.
  virtual void make() const = 0;

  // Make a copy of the class through new. 
  virtual fbuildbase* copy() const = 0;

};

// Helper class for fdatainterp. 
// Automate code generation for rpn functions. 
template< typename F >
class fbuild : public fbuildbase
{
public:

  string const name() const
    { return F().name(); }
  void make() const;

  fbuildbase* copy() const
    { return new fbuild<F>(); }

};

// Helper class for fdatainterp.
// Allow rpn data type functions which are runtime in nature. 
class fbuilduser : public fbuildbase
{
  rpnbase* x;
  string nm;
public:

  fbuilduser(rpnbase* _x, string const & _nm);
  ~fbuilduser();

  string const name() const;
  void make() const;

  fbuildbase* copy() const;

};


// Function templates need type passed through arguments. 
//  Avoid construction of T as is the case with dummy arguments.
template< typename T >
class passtype
{
public:

  typedef T type;
};

//
//  Brief:  function/data interpreter. Contains the dictionary. 
//
class fdatainterp
{
  // Load dicttable and build the dictionary.
  void init();

  void dictionarydelete();

  // Conversions. 
  rpnreal::type const real(string const & word) const;
  rpninteger::type const integer(string const & word) const;
public:

  // The dictionary table can be used to build the dictionary.
  vector< fbuildbase* > dicttable;
  // The dictionary. 
  map<string,fbuildbase*> dict;

  // Construct an instance.
  fdatainterp();
  ~fdatainterp();

  // From the dictionary table build the dictionary.
  void reset();

  // Interpret the word. 
  void eval(string const &word);

  // Process the input. 
  void process2_silent( istream & is);
  template< typename T >
  void process2( istream & is, T& prnt );

  // Add a function to the dictionary. 
  void add(fbuildbase* x)
    { dict.insert( make_pair(x->name(),x) ); }
  
  // Add a function to the dictionary table and dictionary. 
  template< typename T >
  void addtodictionary(T)
  {
    // No support for inc() dec() with building
    // functions. fn is copied twice and the
    // functions themselves are not persistant
    // with a reset.
    fbuildbase* fn = new fbuild< typename T::type>();
    dicttable.push_back(fn);
    add(fn->copy());
  }

};

class inputstate;
class innerinput;
class outerinput;

// Brief: The interface and state machine for token parsing.
//

// <TODO> The difference in the two states is trivial and
// they could be merged to one.  This was made possible by
// a change in design where the dhome directory/program 
// is treated like anyother directory and doesn't get
// a special evaluation mode.  Instead the client is responsible
// for the evaluation mode.
//
// Implemented as a singleton state machine interface. 
class inputstatescope
{
  innerinput* inner;  // Inner input state. 
  outerinput* outer;  // Outer input state.
public:

  static inputstatescope* cscope;  // The current scope. 
  static inputstate*      cstate;  // The current state.

  bool evaloverride;
  bool evalpreserved;
  bool evalimmediate; // The evaluation mode is either immediate or not. 

  bool error;         // Was there an error in processng the token? 
  
  inputstatescope();   // Initialize the scope. 
  ~inputstatescope();  // Release the scopes rescources.

  // Forward the processing of the word to the current state. 
  void eval(string const & word);

  fdatainterp fd; // The states need to access the interpreter. 

  // Change states.
  void setinner();
  void setouter();

};

  
// The input state is contained within a scope. 
class inputstate
{
public:

  inputstate() {}

  // Process the word in the current state. 
  virtual void eval(string const & word) = 0;

};

class innerinput : public inputstate
{
public:

  void eval(string const & word);
};

class outerinput : public inputstate
{
public:

  void eval(string const & word);
};

// 
// Functions derived from rpnfunction can call this class to
// add themselves to the dictoinary and hence the interpreters scope.
//
template< typename T >
class addtothedictionary
{
public:

  addtothedictionary();
};




// ---------------------------------------------------------------
// Implementation


template< typename T >
addtothedictionary<T>::addtothedictionary()
{
  fdatainterp& fd = SingletonPtr<inputstatescope>()->fd;
  fd.addtodictionary(passtype<T>());
}


template< typename F >
void fbuild<F>::make() const
{ 
  new F
  ( 
    rpnprogramstackstate().ds(), 
    inputstatescope::cscope->evalimmediate 
  ); 
}


template< typename T >
void fdatainterp::process2( istream & is, T& prnt )
{
  char c;
  char const quote('"');
  char const space(' ');
  char const ret('\n');

  string s;

  string const quit("quit");

  while ((c = is.peek()))
  {
    s.clear();

    if (c==quote)
    {
      is.get(c);
      is.get(c);
      while (c!=quote)
      {
        s += c;
        is.get(c);
      }

      new rpnstring( rpnprogramstackstate().ds(), s );
    }
    else
    if (c=='(')
    {
      complex< long double > x;
      is >> x;
     
      new rpncomplex( rpnprogramstackstate().ds(), x );


    }
    else
    {
      is.get(c);
      if ((c!=space)&&(c!=ret))
      {
        s += c;
        is.get(c);
        while ((c!=space)&&(c!=ret))
        {
          s += c;
          is.get(c);
        }
      }

      if (!s.empty())
        SingletonPtr<inputstatescope>()->eval(s);

    }

    if (s==quit)
      break;

    prnt();
  }
}




#endif




