
#include <vector>
using namespace std;

#include <GL/glut.h>


#include <commandline.h>
#include <cpsphere.h>
#include <delaunay3D.h>
#include <pointsdisplay.h>
#include <gobj.h>
#include <graphmisc.h>
#include <point.h>
#include <random.h>
#include <tetrahedron.h>
#include <tetrahedrondraw.h>
#include <zpr.h>


gobjContainer xGraphics(true);


cpsphere * pcpsphere = 0;

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




void test01(int argc, char** argv)
{
  vector< point3<double> > v;

  uint n=5;
    
  random11<double> r;
  for (uint i=0; i<n; ++i)
    v.push_back( point3<double>(r(),r(),r()) );
  
  delaunay3D tess(v);
  tess.eval();

  for (uint i=0; i<tess.tet.size(); ++i)
    cout << tess.tet[i] << endl;
}



void keyboard
(
  unsigned char key,
  int x,
  int y
)
{
  switch (key)
  {
    case 27:
      exit(0);

    case 'a':
      pcpsphere->stateinc();
      glutPostRedisplay();
      break;

    case 'A':
      pcpsphere->statedec();
      glutPostRedisplay();
      break;
  }
}

void display01()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  xGraphics.draw();

  glerrordisplay();
  
  glutSwapBuffers();
}

void drawspheres01
(
  vector< point3<double> > const & v,
  vector< point4<uint> > const & vi
)
{
  uintc imax = vi.size();

/*
  double radius;
  uintc slices=30;
  uintc stacks=30;

  random11<double> r;

  xGraphics.push_back( new gobjglDisable(GL_DEPTH_TEST) );
  xGraphics.push_back( new gobjglEnable(GL_BLEND) );
  xGraphics.push_back( 
    new gobjglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) );
  xGraphics.push_back( new gobjglEnable(GL_LIGHTING) );

  for (uint i=0; i<imax; ++i)
  {
    point3<double> const & P1( v[ vi[i].x ] );
    point3<double> const & P2( v[ vi[i].y ] );
    point3<double> const & P3( v[ vi[i].z ] );
    point3<double> const & P4( v[ vi[i].a ] );

    tetrahedron<double> const t(P1,P2,P3,P4);
    point3<double> const c(t.circumcenter());
    radius = (c-P1).distance();

    xGraphics.push_back( new gobjglColor4f(r(),r(),r(),0.1) );

    xGraphics.push_back( new gobjglPushMatrix() );
    xGraphics.push_back( new gobjglTranslatef(c) );
    xGraphics.push_back( 
      new gobjglutSolidSphere(radius,slices,stacks) );
      //new gobjglutWireSphere(radius,slices,stacks) );

    xGraphics.push_back( new gobjglPopMatrix() );
  }

  xGraphics.push_back( new gobjglDisable(GL_BLEND) );

*/


  for (uint i=0; i<imax; ++i)
  {
    point3<double> const & P1( v[ vi[i].x ] );
    point3<double> const & P2( v[ vi[i].y ] );
    point3<double> const & P3( v[ vi[i].z ] );
    point3<double> const & P4( v[ vi[i].w ] );

    tetrahedrondraw<point3<double>,double> td(P1,P2,P3,P4);
    td.displayedges();
  }

}


void init()
{
  GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat mat_shininess[] = { 50.0 };
  GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
  GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };
 
  glClearColor(0.0,0.0,0.0,0.0);
  glShadeModel(GL_SMOOTH);
 
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
  glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_COLOR_MATERIAL); 
}


void test02(int argc, char** argv)
{
  cout << "Denaulay Triangulation in 3D" << endl;
  cout << endl;
  cout << "Keyboard commands:" << endl;
  cout << "'a'  - iterate forwards through the tetrahedron mesh." << endl;
  cout << "'A'  - iterate backwards throuth the tetrahedron mesh." << endl;
  cout << endl;

  commandline cmd(argc,argv);

  uint n=5;
  cmd.mapvar(n,"n");

  vector< point3<double> > v;

  random11<double> r;
  for (uint i=0; i<n; ++i)
    v.push_back( point3<double>(r(),r(),r()) );
  
  delaunay3D tess(v);
  tess.eval();

/*
  for (uint i=0; i<tess.tet.size(); ++i)
    cout << tess.tet[i] << endl;
*/




  xGraphics.push( new gobjglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) );
  //xGraphics.push( new gobjglClearColor(0.0,0.0,0.0,0.0) ); 

  pcpsphere = new cpsphere(v,tess.tet);
  xGraphics.push( pcpsphere->current );
  pcpsphere->update();


  xGraphics.push( new gobjglPushAttrib(GL_LIGHTING_BIT) );
  xGraphics.push( new gobjglPushAttrib(GL_CURRENT_BIT) );
  xGraphics.push( new gobjglDisable(GL_LIGHTING) );
  xGraphics.push( new gobjglColor3ub(0,255,255) );

  pointsdisplay3D< point3<double> > ptdisp(xGraphics,v);

  //xGraphics.push( new gobjglEnable(GL_LIGHTING) );

  drawspheres01(v,tess.tet);

  xGraphics.push( new gobjglPopAttrib() );
  xGraphics.push( new gobjglPopAttrib() );


  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

  glutInitWindowSize(600,600);
  glutCreateWindow("");  
  init();
  glutDisplayFunc(display01);
  glutKeyboardFunc(keyboard);

  //zprInit();
  //OpenGLinitialisation();
  //

/*
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
*/

  zpr zz;
  glutMainLoop();
}





void display02()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  xGraphics.draw();

  glerrordisplay();
  
  glutSwapBuffers();
}

void test03(int argc, char** argv)
{
  cout << "Denaulay Triangulation in 3D" << endl;
  cout << endl;
  cout << "Keyboard commands:" << endl;
  cout << "'a'  - iterate forwards through the tetrahedron mesh." << endl;
  cout << "'A'  - iterate backwards throuth the tetrahedron mesh." << endl;
  cout << endl;

  commandline cmd(argc,argv);

  uint n=5;
  cmd.mapvar(n,"n");

  vector< point3<double> > v;

  random11<double> r;
  for (uint i=0; i<n; ++i)
    v.push_back( point3<double>(r(),r(),r()) );
  
  delaunay3D tess(v);
  tess.eval();

  xGraphics.push( new gobjglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) );
  //xGraphics.push( new gobjglClearColor(0.0,0.0,0.0,0.0) ); 

  pcpsphere = new cpsphere(v,tess.tet);
  xGraphics.push( pcpsphere->current );
  pcpsphere->update();

/*

  xGraphics.push( new gobjglPushAttrib(GL_LIGHTING_BIT) );
  xGraphics.push( new gobjglPushAttrib(GL_CURRENT_BIT) );
  xGraphics.push( new gobjglDisable(GL_LIGHTING) );
  xGraphics.push( new gobjglColor3ub(0,255,255) );

  pointsdisplay3D< point3<double> > ptdisp(xGraphics,v);

  xGraphics.push( new gobjglPopAttrib() );
  xGraphics.push( new gobjglPopAttrib() );
*/


  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

  glutInitWindowSize(600,600);
  glutCreateWindow("");
  init();
  glutDisplayFunc(display02);
  glutKeyboardFunc(keyboard);

  zpr zz;
  glutMainLoop();
}



int main(int argc, char** argv)
{
  xGraphics.set();

  test02(argc,argv);

  return 0;
}



  

