#ifndef POLYGONIZER_H_INCLUDED
#define POLYGONIZER_H_INCLUDED

#include <vector>
#include <GL/gl.h>
#include "auxmath.h"
#include "EvaluatorInterface.h"

using namespace std;


class Polygonizer{
public:
double level;


private:


bool signalChange(double a, double b, double c){
  if (((a>=0)&&(b>=0)&&(c>=0))||((a<=0)&&(b<=0)&&(c<=0)))
     return false;
  else
     return true;
}


void trianglePlaneIntersection(Point3D<double> q0, Point3D<double> q1, Point3D<double> q2,Point3D<double> r0,Point3D<double> r1,
	Point3D<double> r2, double f0, double f1, double f2, Point2D<double> p[2]){

   Vector3D<double> v0(q1.x-q0.x,q1.y-q0.y,q1.z-q0.z);
   Vector3D<double> v1(q2.x-q0.x,q2.y-q0.y,q2.z-q0.z);

   Vector3D<double> _normal = v0.crossProduct(v1);
   _normal = _normal._normalize();

   Plane<double> plane(_normal,q0);

   if ((f0*f1<=0)&&(f0*f2<=0)&&((f0*f1!=0.0)||(f0*f2!=0))){
      p[0] = plane.intersect(r0,r1);
      p[1] = plane.intersect(r0,r2);
   }
   else if ((f0*f1<=0)&&(f1*f2<=0)&&((f0*f1!=0.0)||(f1*f2!=0))){
      p[0] = plane.intersect(r0,r1);
      p[1] = plane.intersect(r1,r2);
   }
   else if ((f1*f2<=0)&&(f0*f2<=0)&&((f1*f2!=0.0)||(f0*f2!=0))){
      p[0] = plane.intersect(r1,r2);
      p[1] = plane.intersect(r0,r2);
   }
}

public:

Polygonizer(){};

Polygonizer(double level){
    this->level = 0.0;
}

void setLevel(double level){
	this->level = level;
}

void polygonize(double startX, double startY, double endX, double endY,
                int m, int n, EvaluatorInterface * evaluator, vector<Line<double>>& lines){

  double deltaX = (endX-startX)/m;
  double deltaY = (endY-startY)/n;
  evaluator->setLevel(level);
  

  for (int i = 0;i<n;i++)
    for (int j = 0;j<m;j++){

      Point2D<double> p0(startX+j*deltaX,startY+i*deltaY);
      Point2D<double> p1(startX+j*deltaX,startY+(i+1)*deltaY);
      Point2D<double> p2(startX+(j+1)*deltaX,startY+i*deltaY);
      Point2D<double> p3(startX+(j+1)*deltaX,startY+(i+1)*deltaY);

      double f0 = evaluator->eval(p0.x,p0.y);    
      double f1 = evaluator->eval(p1.x,p1.y);
      double f2 = evaluator->eval(p2.x,p2.y);
      double f3 = evaluator->eval(p3.x,p3.y);

      Point3D<double> q0(p0.x,p0.y,f0);
      Point3D<double> q1(p1.x,p1.y,f1);
      Point3D<double> q2(p2.x,p2.y,f2);
      Point3D<double> q3(p3.x,p3.y,f3);

      Point3D<double> r0(p0.x,p0.y,0);
      Point3D<double> r1(p1.x,p1.y,0);
      Point3D<double> r2(p2.x,p2.y,0);
      Point3D<double> r3(p3.x,p3.y,0);

      Point2D<double> p[2];

	  if (signalChange(f0,f1,f2)){
	     trianglePlaneIntersection(q0,q1,q2,r0,r1,r2,f0,f1,f2,p);
		 lines.push_back(Line<double>(p[0],p[1]));
	  }

	  if (signalChange(f1,f2,f3)){
		trianglePlaneIntersection(q1,q3,q2,r1,r2,r3,f1,f2,f3,p);
		lines.push_back(Line<double>(p[0],p[1]));
	  }
	}
  }
};





#endif // POLYGONIZER_H_INCLUDED
