#include <iostream>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <pic.h>
#include <svl/Vec2.h>
#include <svl/Vec3.h>
#include <math.h>
#include "texture.h"

GLuint texname;
Pic *texture;


void initializeTexture() {

  // read the texture from a file
  texture = jpeg_read("water.jpg", NULL);

  if (texture == NULL) {
    printf ("error loading texture\n");
    exit(1);
  }

  glGenTextures(1, &texname);
  glBindTexture(GL_TEXTURE_2D, texname);

  glTexImage2D(GL_TEXTURE_2D, 0, 3, texture->nx, texture->ny, 0, GL_RGB, 
	       GL_UNSIGNED_BYTE, texture->pix);

  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}

void drawGround(void)
{	
  // set the texture map for the ground plane to water
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, texname);

  // begin drawing polygon
  glBegin(GL_POLYGON);

  glTexCoord2f(1.0, 1.0);
  glVertex3f(1.0, 0.0, 1.0);

  glTexCoord2f(1.0, -1.0);
  glVertex3f(1.0, 0.0, -1.0);

  glTexCoord2f(-1.0, -1.0);
  glVertex3f(-1.0, 0.0, -1.0);

  glTexCoord2f(-1.0, 1.0);
  glVertex3f(-1.0, 0.0, 1.0);

  glEnd();
  glDisable(GL_TEXTURE_2D);
}



void initializeGL()
{
  glClearColor(0.5, 0.5, 0.5, 0.0);
  glEnable(GL_DEPTH_TEST);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(FOV, ((double)WIDTH) / HEIGHT, 1, 100);
}

void display()
{

  rotateAmount += rotateStep;

  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity();
  glTranslatef(0.0,0.0,-5.0);	
  //  glRotatef(rotateAmount, 0.0, 1.0, 0.0);
  glTranslatef(0.0, -1.0, 0.0);


  // translations for mouse control
  glTranslatef(g_vLandTranslate[0], g_vLandTranslate[1], g_vLandTranslate[2]);

  glRotatef(g_vLandRotate[0], 1, 0, 0);
  glRotatef(g_vLandRotate[1], 0, 1, 0);
  glRotatef(g_vLandRotate[2], 0, 0, 1);

  glScalef(g_vLandScale[0], g_vLandScale[1], g_vLandScale[2]);

  // draw the ground plane
  glPushMatrix();
  drawGround();
  glPopMatrix();

  glFlush();
  glutSwapBuffers();
}

void menufunc(int value)
{
  switch (value)
    {
    case 0:
      exit(0);
      break;
    }
}

void idle()
{
  glutPostRedisplay();
}

void reshape(int x, int y)
{
  if (y == 0 || x == 0) return;
  
  glMatrixMode(GL_PROJECTION);  
  glLoadIdentity();
  gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.5,20.0);
  glMatrixMode(GL_MODELVIEW);
  glViewport(0,0,x,y);
  glPointSize(GLfloat(x)/200.0);
}


void mousedrag(int x, int y)
{
  Vec2 vMouseNew;
  Vec2 vMouseDelta;
  
  vMouseNew[0] = x;
  vMouseNew[1] = y;

  vMouseDelta = vMouseNew-g_vMousePos;
  
  switch (g_ControlState)
  {
    case TRANSLATE:  
      if (g_iLeftMouseButton)
      {
        g_vLandTranslate[0] += vMouseDelta[0]*0.01;
        g_vLandTranslate[1] -= vMouseDelta[1]*0.01;
      }
      if (g_iMiddleMouseButton)
      {
        g_vLandTranslate[2] += vMouseDelta[1]*0.01;
      }
      break;
    case ROTATE:
      if (g_iLeftMouseButton)
      {
        g_vLandRotate[0] += vMouseDelta[1];
        g_vLandRotate[1] += vMouseDelta[0];
      }
      if (g_iMiddleMouseButton)
      {
        g_vLandRotate[2] += vMouseDelta[1];
      }
      break;
    case SCALE:
      if (g_iLeftMouseButton)
      {
        g_vLandScale[0] *= 1.0-vMouseDelta[1]*0.01;
        g_vLandScale[2] *= 1.0-vMouseDelta[1]*0.01;
        g_vLandScale[1] *= 1.0-vMouseDelta[1]*0.01;
      }
      if (g_iMiddleMouseButton)
      {
        g_vLandScale[1] *= 1.0-vMouseDelta[1]*0.01;
      }
      break;
    
    
  }
  g_vMousePos = vMouseNew;
}

void mouseidle(int x, int y)
{
  Vec2 vMouseNew;
  
  vMouseNew[0] = x;
  vMouseNew[1] = y;

  g_vMousePos = vMouseNew;
}

void mousebutton(int button, int state, int x, int y)
{
  Vec2 vMouseNew;
  
  vMouseNew[0] = x;
  vMouseNew[1] = y;

  switch (button)
  {
    case GLUT_LEFT_BUTTON:
      g_iLeftMouseButton = (state==GLUT_DOWN);
      break;
    case GLUT_MIDDLE_BUTTON:
      g_iMiddleMouseButton = (state==GLUT_DOWN);
      break;
    case GLUT_RIGHT_BUTTON:
      g_iRightMouseButton = (state==GLUT_DOWN);
      break;
  }
 
  switch(glutGetModifiers())
  {
    case GLUT_ACTIVE_CTRL:
      g_ControlState = TRANSLATE;
      break;
    case GLUT_ACTIVE_SHIFT:
      g_ControlState = SCALE;
      break;
    default:
      g_ControlState = ROTATE;
      break;
  }

  g_vMousePos = vMouseNew;
}

void initializeMenu() {
  g_iMenuId = glutCreateMenu(menufunc);
  glutSetMenu(g_iMenuId);
  glutAddMenuEntry("Quit",0);
  glutAttachMenu(GLUT_RIGHT_BUTTON);
}


int main (int argc, char ** argv)
{

  glutInit(&argc, argv);
	
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(640,480);
  
  glutCreateWindow("Texture Map");

  initializeGL();
  initializeMenu();
  initializeTexture();
	
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutIdleFunc(idle);

  glutMotionFunc(mousedrag);
  glutPassiveMotionFunc(mouseidle);
  glutMouseFunc(mousebutton);

  glutMainLoop();
  return 0;

}
