#include "culooks.h"

#include <iostream>
#include <cmath>

using namespace std;

int culooks::drawing::rotcube[3];

culooks::window* culooks::drawing::getWin()
{
  for (int iwin=0; iwin<culooks::Windows.size(); iwin++)
    if ( culooks::Windows.at(iwin).first == glutGetWindow() ) {
      return culooks::Windows.at(iwin).second;
    }
  cerr << "Something terrible happened: Could not find window-id!" << endl;
  exit(1);
}

int culooks::drawing::getCubeFromPos(int x, int y)
{
  culooks::window *Win = getWin();

  int col = x / ((float)Win->w / Win->layout[0]);
  int row = Win->layout[1] - y / ((float)Win->h / Win->layout[1]);

  return col + row*Win->layout[0];
}


void culooks::drawing::motionFunc(int x, int y)
{   
  culooks::window *Win = getWin();
   
  Win->cubes.at(rotcube[0]).az += rotcube[1] - x;
  Win->cubes.at(rotcube[0]).alt += rotcube[2] - y;

  rotcube[1] = x;
  rotcube[2] = y;
   

  glutPostRedisplay();
}

void culooks::drawing::mouseFunc(int button, int state, int x, int y)
{
  culooks::window *Win = getWin();

  if (button == 0) {
    rotcube[0] = getCubeFromPos(x,y);
    rotcube[1] = x;
    rotcube[2] = y;
  }

  if (button == 4) {
    Win->cubes.at(getCubeFromPos(x,y)).zoom *= 1.1;
    glutPostRedisplay();
  }
  else if (button == 3) {
    Win->cubes.at(getCubeFromPos(x,y)).zoom *= 0.9;
    glutPostRedisplay();
  }
}


void culooks::drawing::reshapeFunc(int w, int h)
{
  culooks::window *Win = getWin();
    
  int neww;
  int newh;

  if ( w == Win->w ) {
    newh = h;
    neww = Win->aspect*h;
  }
  else if ( h == Win->h ) {
    neww = w;
    newh = w / Win->aspect;
  }
  else {
    neww = ( pow(Win->aspect,2)*w + Win->aspect*h ) / ( pow(Win->aspect,2) + 1 );
    newh = ( Win->aspect*w + h ) / ( pow(Win->aspect,2) + 1 );
  }

  glutReshapeWindow(neww,newh);
  glViewport(0,0,neww,newh);

  Win->w = neww;
  Win->h = newh;
}

void culooks::drawing::displayFunc()
{
  culooks::window *Win = getWin();

  glClearColor(Win->bgcolor[0], Win->bgcolor[1], Win->bgcolor[2], Win->bgcolor[3]);
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
    
  glScalef(1.0/Win->layout[0],1.0/Win->layout[1],1.0);
  glTranslatef(-Win->layout[0]+1, -Win->layout[1]+1, 0);
    
  for (int icube=0; icube < Win->cubes.size(); icube++) {
    Win->cubes.at(icube).draw();
    if ((icube+1)%Win->layout[0] == 0) {
      glTranslatef(-2*Win->layout[0]+2, 2, 0);
    }
    else {
      glTranslatef(2, 0, 0);
    }
  }
    
  glutSwapBuffers();
}
 
void culooks::drawing::initWindow(int winid)
{
  
  glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
  glutInitWindowSize(culooks::Windows[winid].second->w, culooks::Windows[winid].second->h);
  glutInitWindowPosition(winid*100,winid*100);
  glutCreateWindow( ("culooks / " + culooks::Windows[winid].second->name).c_str() );

  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);	
  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);	
  glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

  glutDisplayFunc(&drawing::displayFunc);
  glutReshapeFunc(&drawing::reshapeFunc);
  glutMotionFunc(&drawing::motionFunc);
  glutMouseFunc(&drawing::mouseFunc);
  glutIdleFunc(&drawing::idleFunc);

  culooks::Windows[winid].first = glutGetWindow();
  culooks::Windows[winid].second->initialized = true;
  culooks::Windows[winid].second->redisplay = true;
}

void culooks::drawing::idleFunc()
{
  int activeWindow = glutGetWindow();

  for (int iwin=0; iwin < culooks::Windows.size(); iwin++) {
    if (!culooks::Windows[iwin].second->initialized)
      initWindow(iwin);
    if (culooks::Windows[iwin].second->redisplay) {
      glutSetWindow(culooks::Windows[iwin].first);
      glutPostRedisplay();
      culooks::Windows[iwin].second->redisplay = false;
    }
  }

  glutSetWindow(activeWindow);
}

void* culooks::drawing::glutThread(void *_comArg)
{
  comarg *comArg = (comarg*)_comArg;
  glutInit(comArg->argc, comArg->argv);
  initWindow(0);
  glutMainLoop();
}
