#include <GL/glut.h>
#include <cmath>
#include <vector>
#include "Vector3D.hpp"
#include "parser.hpp"
#include "node.hpp"

std::vector<Vector3D> tri;

// Ángulos de cámara
float camYaw = 0.0f;
float camPitch = 20.0f;
float camDist = 20.0f;   // ← distancia de la cámara

void updateCamera()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    float yawRad   = camYaw   * 3.14159f / 180.0f;
    float pitchRad = camPitch * 3.14159f / 180.0f;

    float camX = camDist * cos(pitchRad) * sin(yawRad);
    float camY = camDist * sin(pitchRad);
    float camZ = camDist * cos(pitchRad) * cos(yawRad);

    gluLookAt(camX, camY, camZ,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    updateCamera();

    glBegin(GL_TRIANGLES);
	for (int k=0; k<tri.size(); k+=3) {
			if (k/3%2==0)	
	   			glColor3f(1.0f, 0.0f, 0.0f);
			else
 	  			glColor3f(0.0f, 0.0f, 1.0f);
			glVertex3f(tri[k].x(), tri[k].y(), tri[k].z());
			glVertex3f(tri[k+1].x(), tri[k+1].y(), tri[k+1].z());
			glVertex3f(tri[k+2].x(), tri[k+2].y(), tri[k+2].z());
	}
  	glEnd();

    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (float)w / h, 0.1, 100.0);

    glMatrixMode(GL_MODELVIEW);
}

// ← Flechas
void specialKeys(int key, int x, int y)
{
    const float rotSpeed = 5.0f;

    if (key == GLUT_KEY_LEFT)  camYaw -= rotSpeed;
    if (key == GLUT_KEY_RIGHT) camYaw += rotSpeed;
    if (key == GLUT_KEY_UP)    camPitch += rotSpeed;
    if (key == GLUT_KEY_DOWN)  camPitch -= rotSpeed;

    if (camPitch > 89.0f) camPitch = 89.0f;
    if (camPitch < -89.0f) camPitch = -89.0f;

    glutPostRedisplay();
}

// ← Teclas ASCII (+ y -)
void keyboard(unsigned char key, int x, int y)
{
    const float zoomSpeed = 0.1f;

    if (key == '+') camDist -= zoomSpeed;   // acercar
    if (key == '-') camDist += zoomSpeed;   // alejar

    if (camDist < 0.5f) camDist = 0.5f;     // evita cruzar el centro
    if (camDist > 20.0f) camDist = 20.0f;   // límite razonable

    glutPostRedisplay();
}

int main(int argc, char *argv[])
{
	std::string lin;
	lin= "";
	std::cout << "x(t)= \n";
	while (!std::cin.eof() && std::cin.peek()!=';')
		lin+= char(std::cin.get());
	lin+= std::cin.get();
	Parser px(lin, NULL, NULL);
	Node* x= px.Tree();
	Node* xp= x->deriv();
	std::cout << "x(t):= " <<  x->print() << std::endl;
	std::cout << "xp(t):= " <<  xp->print() << std::endl;

	lin= "";
	std::cout << "y(t)= \n";
	while (!std::cin.eof() && std::cin.peek()!=';')
		lin+= char(std::cin.get());
	lin+= std::cin.get();
	Parser py(lin, NULL, NULL);
	Node* y= py.Tree();
	Node* yp= y->deriv();
	std::cout << "y(t):= " <<  y->print() << std::endl;
	std::cout << "yp(t):= " <<  yp->print() << std::endl;

	lin= "";
	std::cout << "z(t)= \n";
	while (!std::cin.eof() && std::cin.peek()!=';')
		lin+= char(std::cin.get());
	lin+= std::cin.get();
	Parser pz(lin, NULL, NULL);
	Node* z= pz.Tree();
	Node* zp= z->deriv();
	std::cout << "z(t):= " <<  z->print() << std::endl;
	std::cout << "zp(t):= " <<  zp->print() << std::endl;

	double a, b;
	std::cout << "Dar a b:\n";
	std::cin >> a >> b;
	std::cout  << "a: " <<  a << " b: " << b << std::endl;
	int N;
	std::cout << "N:\n";
	std::cin >> N;
	std::cout  << "N: " <<  N << std::endl;
	double h= (a+b)/N;
	int M;
	std::cout << "M:\n";
	std::cin >> M;
	std::cout  << "M: " <<  M << std::endl;
	double r;
	std::cout << "r:\n";
	std::cin >> r;
	std::cout  << "r: " <<  r << std::endl;

	std::cerr << "ya lei los datos\n";
	double co[M+1];
	double si[M+1];
	double ta= 0.0;
	double tb= 2.0 * M_PI;
	double ht= (tb-ta) / M;
	for (int k=0; k<=M; ++k) {
		double th= ta + k*ht;
		co[k]= r*cos(th);
		si[k]= r*sin(th);
	}

	Vector3D G[N+1][M+1];
	Vector3D sky(0,0,1);
	for (int i=0; i<=N; ++i) {
		double t= a + i*h;
		Vector3D p(x->eval(t), y->eval(t), z->eval(t));
		Vector3D u= unit(Vector3D(xp->eval(t), yp->eval(t), zp->eval(t)));
		Vector3D v= unit(sky - (sky*u)*u);
		Vector3D w= u % v;
        for (int j=0; j<=M; ++j) {
            G[i][j]= p+ co[j]*v + si[j]*w;
            std::cerr << "t: " << t
                << " G[" << i <<"][" << j <<"]= " << G[i][j] << std::endl;
        }
	}

	std::cerr << "ya calcule los triangulos\n";

	delete zp;
	delete yp;
	delete xp;
	delete z;
	delete y;
	delete x;

	std::cout << 2*N*M << std::endl;
	for (int i=0; i<N; ++i)
		for (int j=0; j<M; ++j) {
			tri.push_back(G[i][j]);
			tri.push_back(G[i+1][j+1]);
			tri.push_back(G[i+1][j]);

			tri.push_back(G[i][j]);
			tri.push_back(G[i][j+1]);
			tri.push_back(G[i+1][j+1]);
		}
	std::cerr << "ya construi el vector\n";
	for ( auto t : tri )
		std::cerr << t << std:: endl;

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Camara con Flechas + Zoom (+ -)");

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutSpecialFunc(specialKeys);
    glutKeyboardFunc(keyboard);

    glutMainLoop();
	return EXIT_SUCCESS;
}
