
#include <cassert>
#include <iostream>
#include <fstream>

using namespace std;

#include <GL/glut.h>
#include <GL/gl.h>

#include <zpr.h>
#include <graphmisc.h>
#include <commandline.h>
#include <gobj.h>
#include <pointsdisplay.h>
#include <random.h>
#include <print.h>
#include <point.h>

#include <d3tess.h>
#include <d3tessdraw.h>
#include <d2func.h>
#include <d2circle.h>
#include <halfspaceD2.h>
#include <aclock.h>
#include <d3meshpointreader.h>

#include <d3minboundary.h>
#include <d3minrecursive.h>
#include <d3mincircle.h>
#include <d3mincentroid.h>
#include <d3mincentroid2.h>
#include <message.h>
#include <typedefs.h>



// Tempory
#include <trianglespace.h>

#define SHOW(x) #x << '=' << (x)
typedef point2<double> pt2;
typedef point2<double> const pt2c;

template<>
double zero<double>::val = 1E-15;

d3tess * mesh;
d3tessdraw *meshdraw;

pt2 targetcenter;
doublec targetradius = 0.6;
d2func * p2dfunc = new d2circle(targetcenter,targetradius);

bool enabletargetcurve(false);

gobjMyCircle targetcircle;
gobjMyCircleDraw targetcurve
(
  targetradius,
  pt3(targetcenter.x,targetcenter.y,0.0),
  targetcircle
);

gobjContainer xGraphics;

messagefile error("error.txt",true);

random11<double> r;

void init02();


// Superior to using cin for string input as a null string can be entered!
string getInputString()
{
  string s;
  cin >> s;
  return s;
/*
  string s;
  char ch;
  for ( ; ; )
  {
    ch = cin.peek();
    cin.ignore();

    if (ch=='\n')
      return s;

    s += ch;
  }

  assert(false);
  return s;
*/
}


// Add a point to the mesh only if it is inside.
boolc addpointinsidemesh()
{
  

  static gobjQuadric q4;
  q4.radius=0.005;

  xGraphics.push( new gobjglColor3f(1.0,0.0,0.0) );
                
  uint k= mesh->pt.size();

  pt2 x(-1.0+2.0*r(),-1.0+2.0*r());
  mesh->pt.push_back(pt3(x.x,x.y,p2dfunc->eval(x)));
  xGraphics.push( new gobjMySphereDraw( x, &q4 ) );

  if (mesh->searchminimizetowardspoint(k))
  {


messageglobal() << "addpointinsidemesh()" << "\n";
messageglobal() << *mesh << "\n\n";

messageglobal() << "k=" << k << "\n";

    mesh->addpoint(k);
messageglobal() << *mesh << "\n\n";
    return true;
  }

  return false;
}

void addrandompointtomeshptvector(pt2 & x)
{
  x = pt2(-1.0+2.0*r(),-1.0+2.0*r());
  mesh->pt.push_back(pt3(x.x,x.y,p2dfunc->eval(x)));
}


void addrandompointtomesh()
{
  static gobjQuadric q3;
  q3.radius=0.005;

  xGraphics.push( new gobjglColor3f(1.0,0.0,0.0) );
                
  uint k= mesh->pt.size();

  pt2 x;
  addrandompointtomeshptvector(x);
  //pt2 x(-1.0+2.0*r(),-1.0+2.0*r());
  //mesh->pt.push_back(pt3(x.x,x.y,p2dfunc->eval(x)));
  xGraphics.push( new gobjMySphereDraw( x, &q3 ) );

  mesh->addpoint(k);
}

void timmingexperiment04()
{
  cout << "Creating a 3D Data Set" << endl;
  cout << "Writing Points to a File" << endl;
  cout << "  Enter the filename: ";
  string fname;
  cin >> fname;
  cout << "  Enter the number of points: ";
  uint n;
  cin >> n;

  ofstream targ(fname.c_str());

  for (uint i=0; i<n; ++i)
  {
    pt2 x(-1.0+2.0*r(),-1.0+2.0*r());
    targ << x.x << " " << x.y << " " << p2dfunc->eval(x) << endl;
  }

  cout << "Finished writing file: " << fname << endl << endl;
}

void timmingexperiment03()
{
  cout << "Creating a 2D Data Set" << endl;
  cout << "Writing Points to a File" << endl;
  cout << "  Enter the filename: ";
  string fname;
  cin >> fname;
  cout << "  Enter the number of points: ";
  uint n;
  cin >> n;

  ofstream targ(fname.c_str());

  for (uint i=0; i<n; ++i)
    targ << -1.0+2.0*r() << " " << -1.0+2.0*r() << endl;

  cout << "Finished writing file: " << fname << endl << endl;
}

void filereadingmesh
(
  d3meshpointreader & mr 
)
{
    
  cout << "Starting insertion of points into the mesh" << endl;

  aclock c;
  c.measure();
  mr.eval();
  c.measure();

  cout << "Finished insertion of points into the mesh" << endl << endl;
  cout << "Time without graphics: ";
  cout << c.diff_s() << "s" << endl;
}

void timmingexperiment02()
{
  cout << "Reading Points from a File" << endl;
  cout << "Expecting the file to have 2 or 3 columns of numbers." << endl;
  cout << endl;
  cout << "  Enter the filename: ";
  string fname;

  //fname = "dataset2D08.txt";
  //cout << fname << endl;
  cin >> fname;

  bool res;
  d3meshpointreader mr(res,*mesh,fname);

  if (res==false)
    return;

  filereadingmesh(mr);
}



void timmingexperiment01()
{
  cout << "Multiple timing experiments" << endl;
  cout << endl;
  cout << "Enter the filename: ";
  string fname;
  cin >> fname;
  
  ofstream fil(fname.c_str());

  cout << "Enter number of measurements M: ";
  uint M;
  cin >> M;

  uint n=100;

  aclock c;

  for (uint k=0; k<M; ++k)
  {
cout << SHOW(k) << endl;
cout << SHOW(n) << endl;
    mesh->vi.reserve(n);

    c.measure();
    for (uint i=0; i<n; ++i) 
      addrandompointtomesh();
    c.measure();
    fil << n << " " << c.diff_s() << endl;

    mesh->reset();

    init02();

    n *= 2;
  }
cout << "out of loop" << endl;
exit(0);

}

void timmingexperiment05()
{
  cout << "Multiple Timing Experiments." << endl;
  cout << "The results are stored in timings.txt" << endl;

  cout << "Enter the filename with a list of 2D data files to be timed: ";
  string filenames;
  //cin >> filenames;
  filenames="dataset2Dlist.txt";
  cout << filenames << endl;

  ifstream filelist(filenames.c_str());

  ofstream filtim("timings.txt");

  if (filelist.good()==false)
  {
    cout << "error:  can not open file: " << filenames << endl;
    return;
  }

  while (filelist.eof()==false)
  {
    string f1;
    filelist >> f1;

    if (f1.empty())
      continue;

    cout << "Started reading file: " << f1 << endl;
    bool res;
    d3meshpointreader mr(res,*mesh,f1);
    if (res==false)
    {
      cout << "error:  could not read file:" << f1 << "." << endl;
      continue;
    }
    cout << "Finished reading file: " << f1 << endl;
    cout << "Timing file:" << f1 << "." << endl;

    cout << "Starting insertion of points into the mesh" << endl;
    mr.eval(filtim);
    cout << "Finished insertion of points into the mesh" << endl << endl;
  }
}




void timmingexperiment06()
{
  cout << "Simulating Multiple Timing Experiments." << endl;
  cout << "The results are stored in timings.txt" << endl;
  cout << "This is testing an algorithm not yet build." << endl;
  cout << "  It has the same complexity as this one." << endl;
  cout << "  A O(n) operation is applied after this step." << endl;
  cout << endl;
  cout << "A bounding box is first inserted.  All the points " << endl;
  cout << "  should lie well within the bounding box." << endl;
  cout << endl;
  cout << "For a preordered data set I am expecting linear results" << endl;


  cout << "Enter the filename with a list of 2D data files to be timed: ";
  string filenames;
  //cin >> filenames;
  filenames="datasetlist.txt";
  cout << filenames << endl;

  ifstream filelist(filenames.c_str());

  ofstream filtim("timings.txt");

  if (filelist.good()==false)
  {
    cout << "error:  can not open file: " << filenames << endl;
    return;
  }

  // Points defining the bounding box.
  vector< pt3 > vbox;
  vbox.push_back( pt3(-2.0,-2.0,0.0) );
  vbox.push_back( pt3(2.0,-2.0,0.0) );
  vbox.push_back( pt3(2.0,2.0,0.0) );
  vbox.push_back( pt3(-2.0,2.0,0.0) );


  while (filelist.eof()==false)
  {
    string f1;
    filelist >> f1;

    if (f1.empty())
      continue;

    cout << "Started reading file: " << f1 << endl;
    bool res;
    d3meshpointreader mr(res,*mesh,vbox,f1);
    if (res==false)
    {
      cout << "error:  could not read file:" << f1 << "." << endl;
      continue;
    }
    cout << "Finished reading file: " << f1 << endl;
    cout << "Timing file:" << f1 << "." << endl;

    cout << "Starting insertion of points into the mesh" << endl;
    mr.eval(filtim);
    cout << "Finished insertion of points into the mesh" << endl << endl;
  }
}







void timmingexperiment00()
{
  cout << "Timing experiment." << endl;
  cout << "Enter the number of points n: ";
  uint n;
  cin >> n;
  mesh->vi.reserve(n);

  aclock c;
  c.measure();
  for (uint i=0; i<n; ++i) 
    addrandompointtomesh();
  c.measure();
  cout << "Time without graphics: ";
  cout << c.diff_s() << "s" << endl;

  meshdraw->meshupdate();
}

void minimizermenu()
{
  cout << endl;
  cout << "Minimizer Menu" << endl;
  cout << endl;
  cout << "The tessellator has a minimizer."  << endl;
  cout << "Setting the minimizer affects all future mesh insertions." << endl; 
  cout << endl;
  cout << "  0: No minimizer" << endl;
  cout << "  1: minb        - minimize the boundary on insertion" << endl;
  cout << "  2: minbr" << endl;
  cout << "  3: minc" << endl;
  cout << "  4: minDT   - Delaunay Triangulation" << endl;
  cout << "  5: mincentroid" << endl;
  cout << "  6: mincentroidr" << endl;

  cout << "      Enter a choice  ";

  string const s = getInputString();
  if (s.empty())
  {
    cout << "No Choice Executed" << endl; 
    cout << "End of Minimizer Menu" << endl;
    return;
  }

  if (s=="0")
    mesh->minimizerSet( new d3minoperator(*mesh) );

  if (s=="1")
    mesh->minimizerSet( new d3minboundary(*mesh) );
 
  if (s=="2")
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3minboundary(*mesh)) 
    );

  if (s=="3")
    mesh->minimizerSet( new d3mincircle(*mesh) );

  if (s=="4")     
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3mincircle(*mesh)) 
    );

  if (s=="5")
    mesh->minimizerSet( new d3mincentroid(*mesh) );

  if (s=="6")
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3mincentroid2(*mesh)) 
    );

  cout << "End of Choice Menu" << endl;
}


void searchStats
(
  double & searchlongest,
  double & searchaverage,
  uintc n
)
{
  // Create the mesh first.
  mesh->reset();
  init02();
  
  for (uint i=3; i<n; ++i) 
    addrandompointtomesh();

  // Create a vector of points inside the mesh
  vector<uint> v;

  pt2 x;
  uint k;
  for ( ; v.size()<n; )
  {
    k = mesh->pt.size();
    addrandompointtomeshptvector(x);
    if (mesh->searchminimizetowardspoint(k))
      v.push_back(k);
  }

  // Set the cp to some random point inside the mesh
  mesh->cp = (rand()% n)+1;

  mesh->searchminimizetowardspoint(v[0]);
  double c = mesh->movecounter; 
  searchlongest = c;
  searchaverage = c;

  for (uint i=1, sz=v.size(); i<sz; ++i)
  {
#ifndef NDEBUG
    assert( mesh->searchminimizetowardspoint(v[i]) );
#else
    mesh->searchminimizetowardspoint(v[i]);
#endif

    c = mesh->movecounter; 
    if (c>searchlongest)
      searchlongest = c;

    searchaverage += c; 
  }

  searchaverage *= 1.0/n;
}

 

void searchexp01()
{
  cout << "Enter the number of points: ";
  uint n;
  cin >> n;

  double searchlongest;
  double searchaverage;

  searchStats(searchlongest,searchaverage,n);

  cout << SHOW(searchlongest) << endl;
  cout << SHOW(searchaverage) << endl;

  meshdraw->meshupdate();
}

void searchexp02()
{
  uint nmax = 1000000;

  cout << "Writing search results to search.txt" << endl;
  cout << "The number of points is capped at " << nmax << endl;

  string fname("search.txt");
  ofstream f(fname.c_str());

  if (f.good()==false)
  {
    cout << "error:  can not open file: " << fname << endl;
    return;
  }

  uint n = 8;
  uint N = 3;

  cout << "Enter the initial number of points u and the number of times" << endl;
  cout << "  this is doubled." << endl;
  cin >> n;
  cin >> N;

  double searchlongest;
  double searchaverage;

  for (uint i=0; i<N; ++i)
  {
    searchStats(searchlongest,searchaverage,n);
    f << n << " " << searchaverage << endl;
    n *= 2;
  }
}

void filewritingmesh()
{
  cout << endl;
  cout << "  Writing the mesh out." << endl;
  cout << endl;
  cout << "  Enter the filename: ";

  string fname(getInputString());

  if (fname.empty())
    return;

  ofstream targ(fname.c_str());
 
  if (targ.good()==false)
  {
    cout << "error:  could not write the file out." << endl;
    return;
  }

  targ << *mesh;
}

void filereadingmesh()
{
  cout << endl;
  cout << "  Reading a mesh in." << endl;
  cout << endl;
  cout << "  Enter the filename: ";

  string fname(getInputString());

  if (fname.empty())
    return;

  ifstream targ(fname.c_str());
 
  if (targ.good()==false)
  {
    cout << "error:  could not read the file." << endl;
    return;
  }

  targ >> *mesh;
}


void filemenu()
{
  cout << endl;
  cout << "File Menu" << endl;
  cout << endl;
  cout << "  0:  Read a tessellation in from a file." << endl;
  cout << "  1:  Write a tessellation out to a file." << endl;
  cout << "  2:  Read points from file." << endl;
  cout << "  3:  Create a new data set by writing 2D random data points to a file." << endl;
  cout << "  4:  Create a new data set by writing 3D random data points to a file." << endl;

  cout << "      Enter a choice  ";

  string const s = getInputString();
  if (s.empty())
  {
    cout << "No Choice Executed" << endl; 
    cout << "End of File Menu" << endl;
    return;
  }  

  if (s=="0")
    filereadingmesh();

  if (s=="1")
    filewritingmesh();

  if (s=="2")
    timmingexperiment02();

  if (s=="3")
    timmingexperiment03();

  if (s=="4")
    timmingexperiment04();

}


void searchmenu()
{
  cout << endl;
  cout << "Search Menu" << endl;
  cout << endl;
  cout << "  0: Calculate the shortes, longest and average lengths" << endl;
  cout << "       of a n point data set with n random inside searches." << endl;
  cout << "  1: Write the average search lengths to a file search.txt ." << endl;

  cout << "      Enter a choice  ";

  string const s = getInputString();
  if (s.empty())
  {
    cout << "No Choice Executed" << endl; 
    cout << "End of Search Menu" << endl;
    return;
  }

  if (s=="0")
    searchexp01();

  if (s=="1")
    searchexp02();

  cout << "End of Search Menu" << endl;
}

void timmingsmenu()
{
  cout << endl;
  cout << "Timmings Menu" << endl;
  cout << endl;
  cout << "  0:  One tessellation with n points measured." << endl;
  cout << "  1:  Multiple timing measurements to file." << endl;
  cout << "  2:  Multiple timmings on 2D data files" << endl;
  cout << "  3:  Simulating Multiple timmings on my Bounded Algorithm" << endl;
  cout << "      Enter a choice  ";


  string const s = getInputString();
  if (s.empty())
  {
    cout << "No Choice Executed" << endl; 
    cout << "End of Timmings Menu" << endl;
    return;
  }

  if (s=="0")
    timmingexperiment00();

  if (s=="1")
    timmingexperiment01();

  if (s=="2")
    timmingexperiment05();

  if (s=="3")
    timmingexperiment06();

  cout << "End of Timmings Menu" << endl;
}




void displaymenu()
{
  cout << endl;
  cout << "Display Menu" << endl;
  cout << endl;
  cout << "  0:  points numbering toggle" << endl;
  cout << "  1:  triangles numbering toggle" << endl;
  cout << "  2:  winding toggle" << endl;
  cout << "  3:  grid toggle" << endl;
  cout << "  4:  cp toggle" << endl;
  cout << "  5:  surface toggle" << endl;
  cout << "  6:  cp circle toggle" << endl;
  cout << "  7:  circles through triangles" << endl;
  cout << "  8:  cp voronoi local polygons about base vertices" << endl;
  cout << "  9:  multicolored triangles" << endl;
  cout << " 10:  voronoi diagram" << endl;
    
  cout << "      Enter a choice  ";

  string const s = getInputString();
  if (s.empty())
  {
    cout << "No Choice Executed" << endl; 
    cout << "End of Display Menu" << endl;
    return;
  }

  if (s=="0")
  {
    meshdraw->graphicsDeffered.gswitch[0]->toggle();
    meshdraw->meshupdate();
  }

  if (s=="1")
  {
    meshdraw->graphicsDeffered.gswitch[1]->toggle();
    meshdraw->meshupdate();
  }

  if (s=="9")
  {
    meshdraw->graphicsDeffered.gswitch[2]->toggle();
    meshdraw->meshupdate();
  }

  if (s=="10")
  {
    meshdraw->graphicsDeffered.gswitch[3]->toggle();
    meshdraw->meshupdate();
  }

  if (s=="2")
    meshdraw->graphicsImmediate.gswitch[0]->toggle();

  if (s=="3")
    meshdraw->graphicsImmediate.gswitch[1]->toggle();
  
  if (s=="4")
    meshdraw->graphicsImmediate.gswitch[2]->toggle();

  if (s=="5")
    meshdraw->graphicsImmediate.gswitch[3]->toggle();

  if (s=="6")
    meshdraw->graphicsImmediate.gswitch[4]->toggle();

  if (s=="7")
    meshdraw->graphicsImmediate.gswitch[5]->toggle();

  if (s=="8")
    meshdraw->graphicsImmediate.gswitch[6]->toggle();



  cout << "End of Display Menu" << endl;
}


void mainmenu()
{
  for (; ; )
  {

    cout << endl;
    cout << "Main Menu" << endl;
    cout << endl;
    cout << "  0:  Timmings Menu" << endl;
    cout << "  1:  Display Menu" << endl;
    cout << "  2:  File Menu" << endl;

    cout << "  5:  Change the Minimizer." << endl;
    cout << "  6:  Reset the mesh." << endl;
    cout << "  9:  Search Menu" << endl;
    
    cout << "      Enter a choice  ";


    string const s = getInputString();
    if (s.empty())
    {
      cout << "No Choice Executed" << endl; 
      cout << "End of Main Menu" << endl;
      return;
    }

    if (s=="0")
      timmingsmenu();

    if (s=="1")
      displaymenu();

    if (s=="2")
      filemenu();

    if (s=="5")
      minimizermenu();

    if (s=="6")
    {
      mesh->reset();
      init02();
      meshdraw->meshupdate();
    }

    if (s=="9")
      searchmenu();

  }
}


void keyboard(unsigned char key, int x, int y)
{
  switch (key)
  {
    case 27:
      delete mesh;
      mesh=0;
      delete meshdraw;
      meshdraw=0;
      delete p2dfunc;
      p2dfunc=0;
      
      exit(0);
      break;

    case 'a':
      mesh->vs.anticlockwise();
      break;

    case 'A':
      mesh->vs.clockwise();
      break;

    case 'j':
      mesh->moveleft();
      break;

    case 'k':
      mesh->moveright();
      break;

    case 'm':
      mesh->movedown();
      break;

    case 'b':
      mesh->boundaryorient();
      break;

    case 'w':
      mesh->surfaceleft();
      break;
    case 'e':
      mesh->surfaceright();
      break;

    case 'R':
      {
        for (; !addpointinsidemesh(); );

        meshdraw->meshupdate();
      }
      break;


    case 'r':
      addrandompointtomesh();
      meshdraw->meshupdate();
      break;

    case 't':
      for (uint i=0; i<100; ++i) 
        addrandompointtomesh();
      meshdraw->meshupdate();
      break;

    case 'T':
      mainmenu();
      break;

    case 'p':
      cout << endl;
      cout << *mesh;
      break;

    case 'z':
      mesh->flip();
      meshdraw->meshupdate();
      break;

    case 'l':
      cout << "l=" << mesh->cpbasemeasure() << endl;
      break;

  }

  glutPostRedisplay();
}

void display()
{ 
  //glMatrix temp;
  myglPushMatrix temp;

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  //axes(0.5);

  meshdraw->draw();

  xGraphics.draw();

  glerrordisplay();

  {
    glPushMatrix();

    glPushAttrib(GL_CURRENT_BIT);
    glPushAttrib(GL_LIGHTING_BIT);
 
    glColor3f(1.0,1.0,0.0);
    glEnable(GL_LIGHTING);
  
    if (enabletargetcurve)
      targetcurve.draw();

    glPopAttrib();
    glPopAttrib();

    glPopMatrix();
  }
  glerrordisplay();
  
  glutSwapBuffers();
}

void addpoint(pt2 const & x)
{
  mesh->pt.push_back(p2dfunc->make(x.x,x.y));
}

void addpoint(doublec x, doublec y)
{
  mesh->pt.push_back(p2dfunc->make(x,y));
}

void init00()
{
  cout << endl;
  cout << "Test Mesh" << endl;

  mesh->pt.push_back(p2dfunc->make(0.0,0.0));
  mesh->pt.push_back(p2dfunc->make(1.0,0.0));
  mesh->pt.push_back(p2dfunc->make(1.0,1.0));

  mesh->vi.push_back( simplexD2linked(1,2,3, 0,0,0) );
}

void init02()
{
  cout << endl;
  cout << "Test Mesh" << endl;
  cout << "Adding three random points to make the first" << endl;
  cout << "  simplex or triangle in the mesh." << endl;

  for (uint i=0; i<3; ++i)
    mesh->pt.push_back( 
      p2dfunc->make(-1.0+2.0*r(),-1.0+2.0*r()) );

  mesh->initialize();
}



void help()
{
  cout << "Command Line Options" << endl;
  cout << "For boolean values true and 1, false and 0 are equivalent" << endl;
  cout << "file=filename  - read in points from a file" << endl;
  cout << "cp=true        - current pointer" << endl;
  cout << "winding=true   - display the triangle windings" << endl;
  cout << "surface=true   - draw the surface" << endl;
  cout << "grid=true      - draw the triangles as blue grid" << endl;
  cout << "points=true    - number each point with its integer index" << endl;
  cout << "debug=0        - only use when NDEBUG is undefined so checkdebug() is not excecuted" << endl;
  cout << "triangles=1    - number each triangle with its integer index" << endl;
  cout << "cpcircle=1     - draw a circle through the cp's simplex." << endl;
  cout << "circles=1      - draw circles through every simplex." << endl;
  cout << "cpvoronoi=1    - display voronoi polygons about the cp."  << endl;
  cout << "multcolor=1    - display the triangles with random colorings" << endl;
  cout << "voronoi=1      - display strict voronoi polygons" << endl;


  cout << endl;
  cout << "Keyboard Commands" << endl;
  cout << "'T' enters you into the main menu which is displayed at the" << endl;
  cout << "  command line rather than the application." << endl << endl;
  cout << "'a' 'A' - rotate anticlockwise or clockwise the cp triangle." << endl;
  cout << "'j' 'k' - move left, right and down on current triangle" << endl;
  cout << "  'm'" << endl;
  cout << "'b'     - orient the current triangle to the boundary if possible" << endl;
  cout << "'w' 'e' - First orient the cp to the boundary with 'b'.  Then move" << endl;
  cout << "         on the surface left and right respectively." << endl;
  cout << "'z'     - the flip operator" << endl;

  cout << endl;
  cout << "Minimizers" << endl;
  cout << "  Explore mesh balancing." << endl;
  cout << "  By default no mesh balancing is performed." << endl;
  cout << "minb=1        - boundary minimization on insertion" << endl;
  cout << "minbr=1       - boundary minimization with recursion" << endl;
  cout << "minc=1        - circle minimization on insertion" << endl;
  cout << "minDT=1       - Delauny Triangulation - recursive circle minimization" << endl;
  cout << "mincentroid=1 - circle by average points and radius, insertion" << endl;
  cout << "mincentroid2r=1 - circle by average points and min radius, recursive" << endl;
  //cout << "greedy=true    - very bad mesh generated." << endl;
  //cout << "greedy2=true   - very experimental, do I know what I am doing?" << endl;

}


int main(int argc, char** argv )
{
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  uintc wx=800;
  uintc wy=800;

  glutInitWindowSize(wx,wy);

  glutCreateWindow("");

  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);

  OpenGLinitialisation();

  glEnable(GL_DEPTH_TEST);

  //glDisable(GL_CULL_FACE);
  glEnable(GL_CULL_FACE);

  glEnable(GL_NORMALIZE);

  xGraphics.set();

  //error.setMessageGlobal();
  error.globalset();

  help();

  commandline cmd(argc,argv);

  uint N(1000);
  cmd.mapvar(N,"N");
  
  mesh = new d3tess(N);

  cmd.mapvar(mesh->debugenable,"debug");

  meshdraw = new d3tessdraw(*mesh);

  cmd.mapvar(meshdraw->graphicsDeffered.gswitch[d3tessdraw::points]->isdrawn,"points");
  cmd.mapvar(meshdraw->graphicsDeffered.gswitch[d3tessdraw::simplexes]->isdrawn,"triangles");
  cmd.mapvar(meshdraw->graphicsDeffered.gswitch[d3tessdraw::multicolor]->isdrawn,"multicolor");
  cmd.mapvar(meshdraw->graphicsDeffered.gswitch[d3tessdraw::voronoi]->isdrawn,"voronoi");


  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::winding]->isdrawn,"winding");
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::grid]->isdrawn,"grid",true);
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::cp]->isdrawn,"cp",true);
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::surface]->isdrawn,"surface");
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::circle]->isdrawn,"cpcircle");
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::circles]->isdrawn,"circles");
  cmd.mapvar(meshdraw->graphicsImmediate.gswitch[d3tessdraw::voronoip]->isdrawn,"cpvoronoi");



  bool enableminb(false);
  cmd.mapvar(enableminb,"minb");
  if (enableminb)
    mesh->minimizerSet( new d3minboundary(*mesh) );

  bool enableminbr(false);
  cmd.mapvar(enableminbr,"minbr");
  if (enableminbr)
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3minboundary(*mesh)) 
    );

  bool enableminc(false);
  cmd.mapvar(enableminc,"minc");
  if (enableminc)
    mesh->minimizerSet( new d3mincircle(*mesh) );

  bool enableminDT(false);
  cmd.mapvar(enableminDT,"minDT");
  if (enableminDT)
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3mincircle(*mesh)) 
    );

  bool enablemincentroid(false);
  cmd.mapvar(enablemincentroid,"mincentroid");
  if (enablemincentroid)
    mesh->minimizerSet( new d3mincentroid(*mesh) );

  bool enablemincentroid2r(false);
  cmd.mapvar(enablemincentroid2r,"mincentroid2r");
  if (enablemincentroid2r)
    mesh->minimizerSet
    ( 
      new d3minrecursiveoperator(*mesh,new d3mincentroid2(*mesh)) 
    );

  cmd.mapvar(enabletargetcurve,"targetcurve");

  //test01();

  r.rg.seed(17);

  string fname;
  cmd.mapvar(fname,"file");
  bool fileread(false);

  if (fname.empty()==false)
  {
    d3meshpointreader mr(fileread,*mesh,fname);
 
    if (fileread)
      filereadingmesh(mr);
    else
      cout << "error:  could not read file " << fname << endl;
  }

  if (fileread==false)
    init02();

  meshdraw->meshupdate();

  zpr zz;

  glutPostRedisplay();

  glutMainLoop();

  return 0;
}





