#include <iostream>
#include <algorithm>
#include <vector>
#include <fstream>
using namespace std;

#include <commandline.h>
#include <keyboard.h>
#include <pathstuff.h>
#include <rpn.h>
#include <rpnfunc.h>
#include <rawinterpreter.h>
#include <scopedependentfunctions.h>
#include <singleton.h>


void print(deque<rpnbase*>& ds)
{
  cout << "size=" << ds.size();
  cout << "   depth=" << rpnprogramstackstate().ps->size() << endl;

  if (ds.empty())
    return;

  unsigned int const imax = 10;
  for (unsigned int i=min((unsigned int const)ds.size(),imax); i>0; )
  {
    --i;
    cout << i << ": " << ds[i] << endl;
  }

}


void test01()
{
  deque<rpnbase*> ds;

  rpnbase* x;

  x = new rpnreal(2.5);
  x->eval(ds);

  new rpnreal(ds,2.7);
  new rpndup(ds);
  new rpnstring(ds,"hat");
  new rpndup(ds);

  // Add dup without evaluating

  new rpndup(ds,false);

  //x = new rpnprogram();
  //ds.push_front(x);

  new rpnprogram(ds);

  deque<rpnbase*> ds2;
  new rpnreal(ds2,1.0);
  new rpnreal(ds2,2);
  new rpndup(ds2,false);
  new rpnprogram(ds,ds2,false);
  new rpndup(ds);
  new rpninteger(ds,5);
  new rpnstring(ds,"hat");

  rpnprogramstackstate().init();
  new var(ds);
  new rpnstring(ds,"mat");
  new rpndup(ds);
  new var(ds);

  new rpninteger(ds,1);
  new rpninteger(ds,27);
  new rpnstring(ds,"fat");
  new ifthenelse(ds);
 
  new rpnreal(ds,0);
  new rpnnot(ds,false);

  new rpnreal(ds,15.1);
  new rpninteger(ds,15);

  new rpnequal(ds,true);
  new rpninteger(ds,5);
  new prognew(ds,true);
  //new rpninteger(ds,3);
  //new rpndupn(ds);

  //new rpnneg(ds);


  new rpninteger(ds,0);
  new rpninteger(ds,5);
  new rpndup(ds,false);
  new rpninteger(ds,1);
  new prognew(ds);

  new rpndup(ds,false);
  new rot(ds,false);
  new rpnadd(ds,false);
  new rpnswap(ds,false);
  new rpninteger(ds,1);
  new rpnsubtract(ds,false);
  new rpninteger(ds,6);
  new prognew(ds);

  new rpnfor(ds,false);

  new rpninteger(ds,3);
  new rpndup(ds,false);
  new rpneval(ds,false);
  new rpneval(ds);

  /*
  new rpninteger(ds,8);
  new rpninteger(ds,7);
  new rpninteger(ds,6);
  new rpninteger(ds,5);
  new rpninteger(ds,4);
  new rpninteger(ds,3);
  new rpninteger(ds,2);
  new rpninteger(ds,1);
  new rpninteger(ds,8);
  new rpninteger(ds,-3);
  new rotn(ds);
  */

  new rpndup(ds,false);
  new rpnstring(ds,"cat");
  new var(ds);

  new rpninteger(ds,17);
  new rpnstring(ds,"cat");
  new varrecall(ds,false);

/*
  cout<< endl << endl;
  bool res;
  rpnprogramstackstate().exists(res,"hat");
  cout << "res=" << res << endl;
  rpnprogramstackstate().evaluate(ds,"mat");
  rpnprogramstackstate().evaluate(ds,"cat");

  rpnstring(ds,"hat");
 //new vardel(ds);


  //rpnprogramstackstate().replace(new rpnreal(2.3),"fred");
  //rpnprogramstackstate().erase("hat");
*/


/*

  new rot(ds,true);

  new rpnswap(ds,false);
  new drop(ds,false);

  new rpnreal(ds,0);
  new rpnstring(ds,"cat");
  new ifthen(ds);
  
  new rpninteger(ds,-3);
*/


 
  cout << endl << endl;
  cout << rpnprogramstackstate();
//  rpnprogramstackstate().print(cout);
  cout << endl;

  print(ds);
}

void test02()
{
  deque<rpnbase*> ds;
  rpnprogramstackstate().init();

/*
  new rpninteger(ds,2);
  new rpninteger(ds,3);
  new rpninteger(ds,1);
  new prognew(ds);
  new rpninteger(ds,2);
  new prognew(ds);
  new rpneval(ds);
*/

  new rpninteger(ds,0);
  new rpnstring(ds,"s");
  new var(ds,false);
  new rpninteger(ds,1);
  new rpnstring(ds,"i");
  new var(ds,false);

  new rpnstring(ds,"i");
  new vareval(ds,false);
  new rpninteger(ds,5);
  new rpnlessthanequal(ds,false);
  new rpninteger(ds,4);
  new prognew(ds);

  new rpnstring(ds,"i");
  new vareval(ds,false);
  new rpnstring(ds,"s");
  new vareval(ds,false);
  new rpnadd(ds,false);
  new rpnstring(ds,"s");
  new varreplace(ds,false);
  new rpnstring(ds,"i");
  new vareval(ds,false);
  new rpninteger(ds,1);
  new rpnadd(ds,false);
  new rpnstring(ds,"i");
  new varreplace(ds,false);
  new rpninteger(ds,13);
  new prognew(ds);
  new rpnfor(ds,false);
  new rpnstring(ds,"s");
  new vareval(ds,false);

  new rpninteger(ds,11);
  new prognew(ds);


  new rpndup(ds);
  new rpneval(ds);


  cout << endl << endl;
  cout << rpnprogramstackstate();
  cout << endl;

  print(ds);
}


void test03()
{
  deque<string> s;
  rpnprogramstackstate().init();

  s.push_back("2.5");
  s.push_back("dup");
  s.push_back("ahat");
  s.push_back("3");
  s.push_back("5.3");
  s.push_back("/");

  fdatainterp fd;

  inputstatescope inscp;
  SingletonPtr<inputstatescope> init(&inscp);


  for (unsigned int i=0, imax=s.size(); i<imax; ++i )
  {
    fd.eval(s.front());
    s.pop_front();
  }

  print( rpnprogramstackstate().ds() );
}

void test04(int argc, char** argv)
{
  commandline c(argc,argv);

  /* Read in an initialization file, if non specified
   * then read in the default rpnhome.txt file if it exists.
   * eg ./main load="mycalcstate.txt" */

  string load;
  c.mapvar(load,"load");
 
  if (load.empty())
    load = "rpnhome.txt";

  bool open = false;
  {
    ifstream file(load.c_str());
    if (!(!file))
      open = true;
  }


  cout << "<rpn compiler>" << endl;
  cout << "Enter quit to terminate." << endl << endl;
  cout << "0: " << endl;

  string strinit;
  if (open)
    strinit = load + " load ";

  keyboardinterface* kbd = new keyboardinterface(strinit);
  delete kbd;

}

void test05()
{
  cout << "test05" << endl;

  vector<string> v0, v1;
  string s,t;
  bool res;

  for ( ;s!="quit"; )
  {
    cin >> s;
    pathstuff().convert(v0,s);
    pathstuff().resolveparent(res,v1,v0);
    cout << "res=" << res;
    pathstuff().convert(t,v1);
    cout << " t=" << t << endl;
  }

}

int main(int argc, char** argv)
{
  test04(argc,argv); 

  /* test05(); */


}





