#ifndef MENU01_H
#define MENU01_H

#include <sstream>
#include <string>

using namespace std;


#include <myglutgui.h>
#include <menusystem.h>
#include <primitivewindow.h>



template< typename T >
class menu01 : public menusystem
{
  T & x;
  char state;
public:

  menu01(T & _x);

  void draw();

  gobjglTranslatef meshAoffset;

protected:
  void readImmediate(char const key);
  void readBufferedTerminationAction();

  uint simplexdelete;
  uint simplexsplitting;
  uint simplexswap;
  uint simplexminedgelength;

  primitiveWindow* displaywindow;
};

template< typename T >
void menu01<T>::draw()
{
  displaywindow->draw();

  menusystem::draw();
}

template< typename T >
menu01<T>::menu01(T & _x)
  : menusystem(this,0,true,point2<int>(60,30),20), x(_x), meshAoffset(pt3())
{
  addfont12("Partitions and Miscelaneous Mesh Operations Menu");
  addnewline();
  addfont10(simplexdelete,
            "'d'      Enter simplex to delete:  ");
  addnewline();
  addfont10("'c'      Clip the mesh with the partition ");
  addnewline();
  addfont10(simplexminedgelength,
            "'e'      Minimize the simplexes edge length, enter delta:  ");
  addnewline();
  addfont10("'j' 'J'  Rotate partition anti clockwise and clockwise");
  addnewline();
  addfont10("'k' 'K'  Translate partition right and left");
  addnewline();
  addfont10("'l' 'L'  Translate partition up and down");
  addnewline();
  addfont10("'m'      Splitting the simplex on the boundies midpoint");
  addnewline();
  addfont10(simplexsplitting,
            "           Enter s p1 for the simplex and point index:  ");
  addnewline();
  addfont10("'p'      Printing the mesh (toggle to display and update)");
  addnewline();
  addfont10("'r'      Removing null simplexes");
  addnewline();
  addfont10(simplexswap,
            "'s'      Swapping two simplexes, enter i and j:  ");
  addnewline();
  addfont10("'z' 'Z'  Offset mesh A forward or backwards");

  addnewline();
  addnewline();
  addfont10("ESC      Quit");

  displaywindow = new primitiveWindow( point3<double>(6.3,7.0,0.0), 0.20 );
}




template< typename T >
void menu01<T>::readBufferedTerminationAction()
{
  stringstream ss(readBufferedResult);

  switch (state)
  {
    case 'd':
    {
      uint z;
      ss >> z;
      x.mesh->simplexdelete(z);

      break;
    }

    case 'm':
    {
      uint s;
      uint p0;
      ss >> s >> p0;
      
      x.mesh->splitmidpoint1D(s,p0);

      break;
    }

    case 's':
    {
      uint i,j;
      ss >> i >> j;
      x.mesh->simplexswap(i,j);

      break;
    }

    case 'e':
    {
      double delta;
      ss >> delta;
      maxEdgeLength op(*x.mesh,delta);

      d3meshiterrecursive<maxEdgeLength> i(x.mesh->vi,op);

      i.evallinear();

      break;
    }
  }

  x.mesh->debugcheck();
  x.meshdraw->meshupdate();
  glutPostRedisplay();
}

template< typename T >
void menu01<T>::readImmediate(char const key)
{
  switch (key)
  {
    case 27:
      exit(0);
      break;

    case 'd':
    {
      state='d';
      readBufferedSet(simplexdelete);
      break;
    }

    case 'c':
      x.clip->eval();
      x.meshdraw->meshupdate();
      break;

    case 'e':
    {
      state='e';
      readBufferedSet(simplexminedgelength);
      break;
    }
        
    case 'j':
    {
      x.hdraw->rotate(0.1);
      x.meshdraw->meshupdate();
      break;
    }

    case 'J':
    {
      x.hdraw->rotate(-0.1);
      x.meshdraw->meshupdate();
      break;
    }
 
    case 'k':
    {
      x.hdraw->translate( pt2(0.1,0.0) );
      x.meshdraw->meshupdate();
      break;
    }

    case 'K':
    {
      x.hdraw->translate( pt2(-0.1,0.0) );
      x.meshdraw->meshupdate();
      break;
    }

    case 'l':
    {
      x.hdraw->translate( pt2(0.0,0.1) );
      x.meshdraw->meshupdate();
      break;
    }

    case 'L':
    {
      x.hdraw->translate( pt2(0.0,-0.1) );
      x.meshdraw->meshupdate();
      break;
    }

    case 'm':
    {
      state='m';
      readBufferedSet(simplexsplitting);
      break;
    }

    case 'p':
    {
      // Toggle the print display.
      if (displaywindow->vg.empty()==false)
        displaywindow->nuke();
      else
      {
        displaywindow->reset();
        *displaywindow << *x.mesh;
        cout << *x.mesh << endl;
//        *displaywindow << endl;

//        string t1;
//        for (uint i=1; i<x.clip->bv.size(); ++i)
//        {
//          t1="";
//          t1 += i;
//          t1 += (" " + x.clip->bv[i]);
//          *displaywindow << t1;
//          *displaywindow << endl;
//        }
      }

//  NOTE:  I am having a lot of trouble with this code.  Streams
//    are notorious in C++ and though I have had several discussions
//    over time I have not got much but trouble from C++ streams.
//
//  Normally I would implement serialization in strings.  This time I
//  tried yet again to create an integrated solution and use streams and
//  again I have been frustrated with them.  At issue is their use.
//  I do not want to manage buffers but wish the stream to do this and
//  more.  In short I wish to read a stream and interpret it without
//  crashing.  Serialization is easy with text files where the data is
//  simply read and written too.  This is all I want to do with streams
//  - read the data as text.  I am matching them with data that writes
//  text and flushes with the endl.  After some reading and internet
//  I still have not a simple answer or met any that does this. 
//  The technology of streams seems to be in a one way direction - that
//  of favoring the user of a stream rather than the designed of a stream.
//  Why is what I am attempting to do so difficult?  I am almost at
//  the point where I will no longer use streams but write out strings.
//  Then have the stream interact with the strings.  This would solve this
//  reverse issue where I have a stream and want it back as text because
//  all the objects I use have an operator that can easily do this.
//  Further this solution is simple and generic.  If all my code does this
//  then I will only have issues with dealing with strings and not
//  streams - which are much harder to deal with.  Infact I have convinced
//  myself that this is a much more efficient path, fk the standards committee
//  for seeing the streams only at such a low level and not at all data 
//  driven.  I keep hearing about how wonderful streams are but I have
//  yet to implement them properly.  I wrote a parser with streams which
//  failed so I rewrote with strings and it succeeded.  Streams are to the
//  uninitiated a vial technology that is prohibative.  The committee needs
//  a good kick up the arse.


      //cout << *x.mesh << endl;
//      for (uint i=1; i<x.clip->bv.size(); ++i)
//        cout << i << "  " << x.clip->bv[i]  << endl;

      break;
    }

    case 'r':
    {
      x.mesh->removenullsimplexes();
      cout << *x.mesh << endl;

      x.meshdraw->meshupdate();
      break;
    }

    case 's':
    {
      state='s';
      readBufferedSet(simplexswap);
      break;
    }


    case 'z':
    {
      meshAoffset.z += 0.01;
      break;
    }

    case 'Z':
    {
      meshAoffset.z -= 0.01;
      break;
    }
  }

  glutPostRedisplay();
}





#endif



