//Mike Maxim, Roland Flury
//Simple graphics functions using OpenGL/GLUT

#include "l3graphics.h"

void* glut_thread(void*);
void renderScene();

static int g_x,g_y,g_cx,g_cy;
static char* g_screen=NULL;
static pthread_mutex_t g_slock;
static int g_inited=0;

static int mouse_up_x, mouse_down_x, mouse_up_y, mouse_down_y, mouse_button;
static int update_flag;

/**
 * Creates a new window with the left upper corner at (x,y). The 
 * size of the window is cx pixels on the horizontal line and cy pixels
 * on the vertical line. 
 **/
void create_window(int x, int y, int cx, int cy) {
  pthread_t thread;
  int i;
  int* params;
  char** argv;

  if (g_screen != NULL) return;

  g_screen = (char*) malloc(cx*cy*3);
  for (i = 0; i < cx*cy*3; i++) { g_screen[i] = 0; }
  
  params = (int*) malloc(2 * sizeof(int));
  argv = (char**) malloc(1);
  argv[0] = (char*) malloc(256);
  strcpy(argv[0], "leetness");
  params[0] = 1; params[1] = (int)argv;
  g_x = x; g_y = y; g_cx = cx; g_cy = cy;

  pthread_mutex_init(&g_slock, NULL);
  pthread_create(&thread, NULL, glut_thread, (void*)params);

}

/**
 * Sets a pixel at position (x,y) in a previously created window to 
 * the color specified by r (red) , g (green), b (blue), each of which 
 * should be in the range 0 .. 255.
 */
void set_pixel(int x, int y, int r, int g, int b) {
  if (x >= g_cx || y >= g_cy || x < 0 || y < 0) return;

  pthread_mutex_lock(&g_slock);
  g_screen[(y*g_cx*3) + (x*3)] = (char)r;
  g_screen[(y*g_cx*3) + (x*3) + 1] = (char)g;
  g_screen[(y*g_cx*3) + (x*3) + 2] = (char)b;
  pthread_mutex_unlock(&g_slock);
}

/**
 * Refreshes the image - might not work propperly
 */
void refresh() {
  if (!g_inited) return;
  pthread_mutex_lock(&g_slock);
  glutPostRedisplay();
  pthread_mutex_unlock(&g_slock);
}

void renderScene(void) {
  pthread_mutex_lock(&g_slock);
  glClear(GL_COLOR_BUFFER_BIT);
  glDrawPixels(g_cx, g_cy, GL_RGB, GL_UNSIGNED_BYTE, g_screen);
  glFlush();
  pthread_mutex_unlock(&g_slock);
  g_inited = 1;
}

// The mouse-click-handler
void mousefn(int button, int updown, int x, int y) {
  //  printf("mouse ");
  if(updown == 0) {
    //    printf("down ");
    mouse_down_x = x;
    mouse_down_y = y;
  } else {
    //    printf("up ");
    mouse_up_x = x;
    mouse_up_y = y;
  }
  mouse_button = button;
  //  printf("x:%i y:%i button %i\n", x, y, button);
}



/**
 * Allows to retrieve informations about the last mouse-click event.
 * Set updown to 0 to retrieve the 'on-click-down' position, set it 
 * to 1 to retrieve the 'on-click-up' positoin.
 * Set xy to 0 to retrieve the x-position or 1 for the y-position.
 */
int getMouse(int updown, int xy) {
  if(updown == 0) { // down
    if(xy == 0) { // x
      return mouse_down_x;
    } else {
      return mouse_down_y;
    }
  } else { // up
    if(xy == 0) { // x
      return mouse_up_x;
    } else {
      return mouse_up_y;
    }
  }
}

/**
 * Returns which mouse-button was pressed. 
 * 0 = Please figure out yourself... 
 * 1 = 
 * 2 = 
 */
int getMouseButton() {
  return mouse_button;
}


// A simple way to refresh the image every val milliseconds. 
void glut_update(int val) {
  refresh();
  if(val != 0 && update_flag != 0)
    glutTimerFunc(val, glut_update, val);
}

// A simple way to refresh the image every val milliseconds. 
void glut_start_update(int val) {
  refresh();
  update_flag = 1;
  if(val != 0 && update_flag != 0)
    glutTimerFunc(val, glut_update, val);
}


// Stops to update the screen
void glut_stop_update() {
  update_flag = 0;
}

// The main glut thread
void* glut_thread(void* params) {

  int* iparams = (int*) params;

  glutInit(&iparams[0], (char**) iparams[1]);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
  glutInitWindowPosition(g_x,g_y);
  glutInitWindowSize(g_cx,g_cy);
  glutCreateWindow("L3 Graphics Scene");
  glutDisplayFunc(renderScene);

  glutMouseFunc (mousefn);

  glutMainLoop();

  return NULL;
}

