#include<windows.h>


#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include <stdlib.h>
#include "evaluator.h"
#include "polygonizer.h"


/* GLUT callback Handlers */

double level = 0.0;
double scale = 4.0;
double refinement = 64.0;
double ar;

EvaluatorInterface * _evaluator = new evaluator(0.0);

Polygonizer polygonizer(level);

static void drawTriangleMesh(double startX, double startY, double endX, double endY,
                int m, int n){


  double deltaX = (endX-startX)/m;
  double deltaY = (endY-startY)/n;

  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);

      glBegin(GL_LINE_LOOP);
        glVertex2d(p0.x,p0.y);
        glVertex2d(p1.x,p1.y);
        glVertex2d(p2.x,p2.y);
      glEnd();

      glBegin(GL_LINE_LOOP);
        glVertex2d(p1.x,p1.y);
        glVertex2d(p3.x,p3.y);
        glVertex2d(p2.x,p2.y);
      glEnd();
  }
}

static void resize(int width, int height)
{
    ar = (float) width / (float) height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-scale*ar, scale*ar, -scale*ar, scale*ar, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3d(1.0,0.0,0.0);

	drawTriangleMesh(-4.0,-4.0,4.0,4.0,refinement,refinement);

	polygonizer.setLevel(level);
    vector<Line<double>> lines;
	
	polygonizer.polygonize(-4.0,-4.0,4.0,4.0,refinement,refinement,_evaluator,lines);

	glColor3d(0.0,0.0,1.0);
	glLineWidth(2.0);
	glBegin(GL_LINES);
	for(vector<Line<double>>::const_iterator it = lines.begin(); it != lines.end(); ++it){
        Line<double> line = *it;
		Point2D<double> p0 = line.p0;
		Point2D<double> p1 = line.p1;
		glVertex2d(p0.x,p0.y);
		glVertex2d(p1.x,p1.y);
    }
	glEnd();
	glLineWidth(1.0);
	glColor3d(1.0,0.0,0.0);

    glutSwapBuffers();
}


static void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;

        case 'a':
            level += 0.01;
			cout << "level:" << level  << endl;
        break;

        case 's':
			level -= 0.01;
			cout << "level:" << level  << endl;
        break;

		case '.':
            refinement *= 2.0;
        break;

        case ';':
			refinement /= 2.0;
        break;

		case 'o':
			scale *= 2.0;
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glOrtho(-scale*ar, scale*ar, -scale*ar, scale*ar, -1.0, 1.0);
		break;

		case 'p':
			scale /= 2.0;
		    glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glOrtho(-scale*ar, scale*ar, -scale*ar, scale*ar, -1.0, 1.0);
		break;
    }

    glutPostRedisplay();
}

static void idle(void)
{
    glutPostRedisplay();
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(512,512);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("GLUT Polygonizer");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
  
    glutMainLoop();

    return EXIT_SUCCESS;
}
