#include <iostream>
#include <set>
#include "dcel.h"
#include "ndisplay.h"



int main(int argc, char **argv)
{
  std::vector<dcel> graph(6);
  std::vector<npoint3> pts;
  std::vector<int> ele;
  
  // simple 2D case 
  
  int nn=0;
  
  double dx=0.0;
  double dy=0.0;
  double dz=0.0;
  
  pts.push_back(npoint3(0.,0.,0.));
  
  pts.push_back(npoint3(-1.,0.,0.));
  pts.push_back(npoint3(0.,-1.,0.));
  pts.push_back(npoint3(1.,0.,0.));
  pts.push_back(npoint3(0.,1.,0.));

  pts.push_back(npoint3(-2.,0.,0.));
  pts.push_back(npoint3(0.,-2.,0.));
  pts.push_back(npoint3(2.,0.,0.));
  pts.push_back(npoint3(0.,2.,0.));
  dx=0.0;
  dy=0.0;
  dz=0.0;
  for(int i=0;i<9;++i) pts[i+nn]+=npoint3(dx,dy,dz);

  ele.push_back(3);ele.push_back(0+nn);ele.push_back(1+nn);ele.push_back(2+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(2+nn);ele.push_back(3+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(3+nn);ele.push_back(4+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(4+nn);ele.push_back(1+nn);
  ele.push_back(4);ele.push_back(1+nn);ele.push_back(5+nn);ele.push_back(6+nn);ele.push_back(2+nn);
  ele.push_back(4);ele.push_back(2+nn);ele.push_back(6+nn);ele.push_back(7+nn);ele.push_back(3+nn);
  ele.push_back(4);ele.push_back(3+nn);ele.push_back(7+nn);ele.push_back(8+nn);ele.push_back(4+nn);
  ele.push_back(4);ele.push_back(4+nn);ele.push_back(8+nn);ele.push_back(5+nn);ele.push_back(1+nn);
  
  build_dcel_from_mesh(pts,ele,graph[0]);
  ele.clear();
  pts.clear();
//  nn+=9;
  
  
  
  // simple unit cube
  
  pts.push_back(npoint3(0.,0.,0.));
  pts.push_back(npoint3(1.,0.,0.));
  pts.push_back(npoint3(1.,1.,0.));
  pts.push_back(npoint3(0.,1.,0.));
  pts.push_back(npoint3(0.,0.,1.));
  pts.push_back(npoint3(1.,0.,1.));
  pts.push_back(npoint3(1.,1.,1.));
  pts.push_back(npoint3(0.,1.,1.));

 dx=2.0;
 dy=0.0;
 dz=0.0;
 for(int i=0;i<8;++i) pts[i+nn]+=npoint3(dx,dy,dz);
 
  
  ele.push_back(4);ele.push_back(3+nn);ele.push_back(2+nn);ele.push_back(1+nn);ele.push_back(0+nn);
  ele.push_back(4);ele.push_back(0+4+nn);ele.push_back(1+4+nn);ele.push_back(2+4+nn);ele.push_back(3+4+nn);
  ele.push_back(4);ele.push_back(0+nn);ele.push_back(1+nn);ele.push_back(1+4+nn);ele.push_back(4+nn);
  ele.push_back(4);ele.push_back(1+nn);ele.push_back(2+nn);ele.push_back(2+4+nn);ele.push_back(1+4+nn);
  ele.push_back(4);ele.push_back(2+nn);ele.push_back(3+nn);ele.push_back(3+4+nn);ele.push_back(2+4+nn);
  ele.push_back(4);ele.push_back(3+nn);ele.push_back(0+nn);ele.push_back(0+4+nn);ele.push_back(3+4+nn);


  build_dcel_from_mesh(pts,ele,graph[1]);
  ele.clear();
  pts.clear();

//  nn+=8; 
  // more complex shape
  
  pts.push_back(npoint3(0.,0.,1.));  //pt  0
  pts.push_back(npoint3(1.,0.,1.));  //pt  1
  pts.push_back(npoint3(2.,0.,1.));  //pt  2 
  pts.push_back(npoint3(3.,0.,1.));  //pt  3
  pts.push_back(npoint3(3.,1.,0.));  //pt  4
  pts.push_back(npoint3(2.,1.,0.));  //pt  5
  pts.push_back(npoint3(2.,2.,0.));  //pt  6
  pts.push_back(npoint3(1.,2.,0.));  //pt  7
  pts.push_back(npoint3(1.,1.,0.));  //pt  8
  pts.push_back(npoint3(0.,1.,0.));  //pt  9
  pts.push_back(npoint3(0.,0.,-1.)); //pt 10
  pts.push_back(npoint3(1.,0.,-1.)); //pt 11
  pts.push_back(npoint3(2.,0.,-1.)); //pt 12
  pts.push_back(npoint3(3.,0.,-1.)); //pt 13
  pts.push_back(npoint3(3.,1.,-1.)); //pt 14
  pts.push_back(npoint3(2.,1.,-1.)); //pt 15
  pts.push_back(npoint3(2.,2.,-1.)); //pt 16
  pts.push_back(npoint3(1.,2.,-1.)); //pt 17
  pts.push_back(npoint3(1.,1.,-1.)); //pt 18
  pts.push_back(npoint3(0.,1.,-1.)); //pt 19
  dx=4.0;
  dy=0.0;
  dz=0.0;
  for(int i=0;i<20;++i) pts[i+nn]+=npoint3(dx,dy,dz);
 
  ele.push_back(4);ele.push_back(0+nn);ele.push_back(1+nn);ele.push_back(8+nn);ele.push_back(9+nn);
  ele.push_back(4);ele.push_back(1+nn);ele.push_back(2+nn);ele.push_back(5+nn);ele.push_back(8+nn);
  ele.push_back(4);ele.push_back(2+nn);ele.push_back(3+nn);ele.push_back(4+nn);ele.push_back(5+nn);
  ele.push_back(4);ele.push_back(8+nn);ele.push_back(5+nn);ele.push_back(6+nn);ele.push_back(7+nn);

  ele.push_back(4);ele.push_back(19+nn);ele.push_back(18+nn);ele.push_back(11+nn);ele.push_back(10+nn);
  ele.push_back(4);ele.push_back(18+nn);ele.push_back(15+nn);ele.push_back(12+nn);ele.push_back(11+nn);
  ele.push_back(4);ele.push_back(15+nn);ele.push_back(14+nn);ele.push_back(13+nn);ele.push_back(12+nn);
  ele.push_back(4);ele.push_back(17+nn);ele.push_back(16+nn);ele.push_back(15+nn);ele.push_back(18+nn);
  
  ele.push_back(4);ele.push_back(9+nn);ele.push_back(8+nn);ele.push_back(18+nn);ele.push_back(19+nn);
  ele.push_back(4);ele.push_back(7+nn);ele.push_back(6+nn);ele.push_back(16+nn);ele.push_back(17+nn);
  ele.push_back(4);ele.push_back(5+nn);ele.push_back(4+nn);ele.push_back(14+nn);ele.push_back(15+nn);
  
  ele.push_back(4);ele.push_back(1+nn);ele.push_back(0+nn);ele.push_back(10+nn);ele.push_back(11+nn); 
  ele.push_back(4);ele.push_back(2+nn);ele.push_back(1+nn);ele.push_back(11+nn);ele.push_back(12+nn);
  ele.push_back(4);ele.push_back(3+nn);ele.push_back(2+nn);ele.push_back(12+nn);ele.push_back(13+nn);

  ele.push_back(4);ele.push_back(4+nn);ele.push_back(3+nn);ele.push_back(13+nn);ele.push_back(14+nn);
  ele.push_back(4);ele.push_back(6+nn);ele.push_back(5+nn);ele.push_back(15+nn);ele.push_back(16+nn);
  ele.push_back(4);ele.push_back(8+nn);ele.push_back(7+nn);ele.push_back(17+nn);ele.push_back(18+nn);
  ele.push_back(4);ele.push_back(0+nn);ele.push_back(9+nn);ele.push_back(19+nn);ele.push_back(10+nn);
//  nn+=20;
  
  build_dcel_from_mesh(pts,ele,graph[2]);
  ele.clear();
  pts.clear();
  
  pts.push_back(npoint3(0.,0.,0.));  //pt  0
  pts.push_back(npoint3(-1.,-1.,1.414));  //pt  1
  pts.push_back(npoint3(1.,-1.,1.414));  //pt  2 
  pts.push_back(npoint3(1.,1.,1.414));  //pt  3
  pts.push_back(npoint3(-1.,1.,1.414));  //pt  4
  pts.push_back(npoint3(0.,0.,1.414*2));  //pt  5
  dx=10.0;
  dy=0.0;
  dz=0.0;
  for(int i=0;i<6;++i) pts[i+nn]+=npoint3(dx,dy,dz);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(1+nn);ele.push_back(2+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(2+nn);ele.push_back(3+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(3+nn);ele.push_back(4+nn);
  ele.push_back(3);ele.push_back(0+nn);ele.push_back(4+nn);ele.push_back(1+nn);

  ele.push_back(3);ele.push_back(5+nn);ele.push_back(4+nn);ele.push_back(3+nn);
  ele.push_back(3);ele.push_back(5+nn);ele.push_back(3+nn);ele.push_back(2+nn);
  ele.push_back(3);ele.push_back(5+nn);ele.push_back(2+nn);ele.push_back(1+nn);
  ele.push_back(3);ele.push_back(5+nn);ele.push_back(1+nn);ele.push_back(4+nn);
  
//  nn+=6;

  build_dcel_from_mesh(pts,ele,graph[3]);
  ele.clear();
  pts.clear();

  
//  build_dcel_from_mesh(pts,ele,graph);
  
//  data_container data;
//  vtkdisplay display;
  ndisplay display;//(color(0,0,0),(char*)"Test FLTK");
  dcelcallbacks CB;
  display.setcallbacks(&CB);
  for (int i=0;i<graph.size();++i) CB.add_entity(&graph[i]);

//  CB.add_entity(&graph[4]);
//  graph._display(data,true,true,false);

/*

  dcel graph2;
//  loop_subdivision(graph,graph2);
//  graph2.display(data,true,true,true);
  
  dcel* gg=&graph;
  dcel* gg2=&graph2;
  for (int i=0;i<4;++i)
  {
    gg2->clear();
//    if (i%2)  
      doo_sabin_subdivision(*gg,*gg2); 
//    else
//    loop_subdivision(*gg,*gg2);
    dcel* gg3=gg2;
    gg2=gg;
    gg=gg3;
  }
*/
  
//  graph.print(std::cout);
//  CB.add_entity(gg);
//  gg->_display(data,false,true,true);
//  display.init_data(data);
  display.display();
  return 0;
}




/*
 class my_vertex : public dcel_vertex
{
public :
  my_vertex(void) : dcel_vertex() {}
  my_vertex(int i) : dcel_vertex(),id(i) {}
  int id;
};

  dcel graph;
  vertex_handle v1=graph.add_vertex(my_vertex(1));
  vertex_handle v2=graph.add_vertex(my_vertex(2));
  vertex_handle v3=graph.add_vertex(my_vertex(3));
  vertex_handle v4=graph.add_vertex(my_vertex(4));

  vertex_handle v5=graph.add_vertex(my_vertex(5));
  vertex_handle v6=graph.add_vertex(my_vertex(6));
  vertex_handle v7=graph.add_vertex(my_vertex(7));
  
  halfedge_handle e11=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e12=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e21=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e22=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e31=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e32=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e41=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e42=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e51=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e52=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e61=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e62=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e71=graph.add_halfedge(dcel_halfedge());
  halfedge_handle e72=graph.add_halfedge(dcel_halfedge());

  face_handle f1=graph.add_face(dcel_face());
  face_handle f2=graph.add_face(dcel_face());

  v1->point()=npoint3(0,4,0); v1->set_incident_halfedge(e11);
  v2->point()=npoint3(2,4,0); v2->set_incident_halfedge(e42);
  v3->point()=npoint3(2,2,0); v3->set_incident_halfedge(e21);
  v4->point()=npoint3(1,1,0); v4->set_incident_halfedge(e22);
  v5->point()=npoint3(1.5,3.5,0); v5->set_incident_halfedge(e51);
  v6->point()=npoint3(1.8,3.7,0); v6->set_incident_halfedge(e61);
  v7->point()=npoint3(1.8,3.5,0); v7->set_incident_halfedge(e71);

  f1->set_outer_loop(halfedge_handle()); // empty
  f1->add_inner_loop(e11);f1->num=1;
  f2->set_outer_loop(e41);
  f2->add_inner_loop(e51);f2->num=2;

  e11->set_origin(v1);e11->set_twin(e12);e11->set_incident_face(f1);e11->set_next_halfedge(e42);e11->set_prev_halfedge(e31);
  e12->set_origin(v2);e12->set_twin(e11);e12->set_incident_face(f2);e12->set_next_halfedge(e32);e12->set_prev_halfedge(e41);
  e21->set_origin(v3);e21->set_twin(e22);e21->set_incident_face(f1);e21->set_next_halfedge(e22);e21->set_prev_halfedge(e42);
  e22->set_origin(v4);e22->set_twin(e21);e22->set_incident_face(f1);e22->set_next_halfedge(e31);e22->set_prev_halfedge(e21);
  e31->set_origin(v3);e31->set_twin(e32);e31->set_incident_face(f1);e31->set_next_halfedge(e11);e31->set_prev_halfedge(e22);
  e32->set_origin(v1);e32->set_twin(e31);e32->set_incident_face(f2);e32->set_next_halfedge(e41);e32->set_prev_halfedge(e12);
  e41->set_origin(v3);e41->set_twin(e42);e41->set_incident_face(f2);e41->set_next_halfedge(e12);e41->set_prev_halfedge(e32);
  e42->set_origin(v2);e42->set_twin(e41);e42->set_incident_face(f1);e42->set_next_halfedge(e21);e42->set_prev_halfedge(e11);
  e51->set_origin(v5);e51->set_twin(e52);e51->set_incident_face(f2);e51->set_next_halfedge(e61);e51->set_prev_halfedge(e71);
  e52->set_origin(v6);e52->set_twin(e51);                          ;e52->set_next_halfedge(e72);e52->set_prev_halfedge(e62);
  e61->set_origin(v6);e61->set_twin(e62);e61->set_incident_face(f2);e61->set_next_halfedge(e71);e61->set_prev_halfedge(e51);
  e62->set_origin(v7);e62->set_twin(e61);                          ;e62->set_next_halfedge(e52);e52->set_prev_halfedge(e72);
  e71->set_origin(v7);e71->set_twin(e72);e71->set_incident_face(f2);e71->set_next_halfedge(e51);e71->set_prev_halfedge(e61);
  e72->set_origin(v5);e72->set_twin(e71);                          ;e72->set_next_halfedge(e62);e72->set_prev_halfedge(e52);

  
  
  std::cout << dynamic_cast<my_vertex&>(*(e11->origin())).id << std::endl;
  std::cout << dynamic_cast<my_vertex&>(*v2).id << std::endl;
  if (f1->outer_loop()==halfedge_handle()) std::cout << "f1 is the exterior face" << std::endl;

  if (f2->outer_loop()!=halfedge_handle()) // can follow the loop
  {
    std::cout << "f2 has an exterior loop" << std::endl;
    std::cout << "vertex numbers : ";
    halfedge_handle hbegin,he;
    hbegin=he=f2->outer_loop();
    do
    {
      std::cout << dynamic_cast<my_vertex&>(*(he->origin())).id << " ";
      he=he->next_halfedge();
    }
    while(he!=hbegin);
    std::cout << std::endl;
  }
*/  
  // list all faces
