/*
 * Program:
 *   clio.cpp
 * Summary:
 *   Experiments in visualizing page usage.
 * Authors:
 *   Samuel A. Rebelsky
 * Version:
 *   0.1 of July 2003.
 * Warning:
 *   The organization of this program is totally ad-hoc.
 */

/********************************************************/
/*                      Headers                         */
/*******************************************************/

#include "clio.h"
#include "cliographics.h"

//for glui
#include <string.h>
#include <GL/glut.h>
#include "glui.h"

/****************************************************/
/*                   Constants                      */
/****************************************************/

/* The "unit" of translation. */
#define TRANSLATE_UNIT 5
 
/* The "unit" of rotation (in degrees). */
#define ROTATE_UNIT 5

/* The width and height of the main widnow. */
#define WIDTH 600
#define HEIGHT 600


/**************************************************/
/*                   Globals                      */
/**************************************************/

int mainWin;		/* The id of the main window. */
int xtrans;	/* The amount translated in the X dimension. */
int ytrans;	/* The amount translated in the Y dimension. */
int ztrans;	/* The amount translated in the Z dimension. */

/**************************************************/
/*              GLUI Controls                     */
/**************************************************/
String name= {" ", "Category", "URL", "Time Spent",
              "Time Accessed", "Session","User","Windows"};
String users= {"Lindseyd", "Rebelsky", "Brantley", "Bearywes",
               "ToTue"}
int numberOfStudents = 5;
char *start_time, *end_time;

int i;

/* "Live variables */
float scale = 1.0;
int   show_axes = 1;

/* Controls */
GLUI_RadioGroup *curr_vis_choices;
GLUI_Button *load_saved, *save_curr, *time_button;
GLUI_Listbox *x_list, *y_list, *z_list, *w_list, *h_list,
  *d_list, *c_list, *t_list, *l_list, *s_list, *user1, *user2, *user3
  ,*time_panel;

enum {DAY_ALL=500, DAY_60, DAY_30, DAY_7, DAY_1, DAY_OTHER};


/* Callback ID's - passed to control func*/
enum {CHANGE_VISUALIZATION_ID=100, LOAD_SAVED_ID, SAVE_BUTTON_ID,CHANGE_X_ID
      ,CHANGE_Y_ID, CHANGE_Z_ID, CHANGE_W_ID, CHANGE_H_ID, 
      CHANGE_D_ID, CHANGE_C_ID, CHANGE_T_ID, CHANGE_L_ID, CHANGE_S_ID
      , CHANGE_USER_1_ID,CHANGE_USER_2_ID,CHANGE_USER_3_ID, CHANGE_TIME_ID
      , TIME_BUTTON_ID}

/**************************************************/
/*           Lighting Attributes                  */
/**************************************************/
GLfloat light0_ambient[]= {0.0f, 0.0f, 0.0f, 0.3f};
GLfloat light0_diffuse[]= {1.0f,1.0f, 1.0f, 0.3f};
GLfloat light0_position[]= {0.5f, 0.5f, 1.0f, 0.0f};

/**************************************************/
/*           Material Attributes                  */
/**************************************************/
GLfloat mat_diff_spec[]= {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};

/*************************************************/
/*               Predeclarations                 */
/*************************************************/

/* GLUT CALLBACKS */


/* Display the current world. */
void display(void);

/* Handle keyboard input. */
void keyboard(unsigned char, int, int);

/* Handle a change in size to the window */
void resize(int, int);
void reshape2D(int, int);

/* Set up everything. */
void clioInit(void);

/* Set up GLUI Interface */
void setUpUserInterface(void);


/********************************************/
/*          Local Functions                 */
/********************************************/


/*******************************************/
/*                   Main                  */
/*******************************************/

int 
main (int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); //set up buffers
  glutInitWindowSize(WIDTH, HEIGHT);               
  glutInitWindowPosition(0,0);                //upper left corner of window
  mainWin = glutCreateWindow("Exploring Clio's Worlds"); //returns int (unique window id), not 
                                                         //displayed until glutMainLoop() is called
  clioInit();                                           //sets initial conditions that don't need to be
  

  glutDisplayFunc( display );
  GLUI_Master.set_glutReshapeFunc( reshape );  
  GLUI_Master.set_glutKeyboardFunc( keyboard );
  GLUI_Master.set_glutSpecialFunc( NULL );
  GLUI_Master.set_glutMouseFunc( mouse );
  glutMotionFunc( motion );

  /****************************************/
  /*       Set up OpenGL lights           */
  /****************************************/                                                     
  glEnable(GL_LIGHTING);
  glEnable(GL_NORMALIZE);

  glEnable(GL_LIGHT0);
  glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  glLightfv(GL_LIGHT0, GL_POSITION, light0_position);

  /******************************************************/
  /*            Set up Material Properties              */
  /******************************************************/
  glEnable(GL_COLOR_MATERIAL);
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diff_spec);


  /***************************************************/
  /*            Enable z-buffering                   */
  /***************************************************/

  glEnable(GL_DEPTH_TEST);

  /***************************************************/
  /*       Set up user Interface controls            */
  /***************************************************/
  setupUserInterface();
  
  // Register the idle callback with GLUI, *not* with GLUT 
  GLUI_Master.set_glutIdleFunc( NULL );

  glutMainLoop();
  return 0;
} //main

/*****************************************************/
/*               setUpUserInterface()                */
/*****************************************************/

/*
 * Procedure:
 *     setUpUserInterface()
 * Purpose:
 *     Sets up the GLUI user interface user in Clio 3D
 *     and establishes the call back fuctions or "live
 *     variables" used to react to user input
 */

void setUpUserInterface(void)
{
  glPushMatrix();

  /*****************************************************/
  /*              GLUI Left Panel                      */
  /*****************************************************/
  glui = GLUI_Master.create_glui_subwindow(mainWin,
                                           GLUI_SUBWINDOW_LEFT);

  GLUI_Panel *nav= glui->add_panel("Navigation Controls"); 
  
  GLUI_Rotation *rotation= glui->add_rotation_to_panel(nav,"Rotation",
                                                       view_rotate); 

 
  GLUI_Translation *xy= glui->add_translation_to_panel(nav,"Translation",
                                                       GLUI_TRANSLATION_XY, 
                                                       obj_pos);

  GLUI_Translation *z= glui->add_translation_to_panel(nav,"Zoom",
                                                      GLUI_TRANSLATION_Z, 
                                                      &obj_pos[2]);
  z->set_speed( .005);

  GLUI_Spinner *scale_spinner = 
    glui->add_spinner_to_panel( nav, "Scale:",
				GLUI_SPINNER_FLOAT, &scale);
  scale_spinner->set_float_limits( .2f, 4.0 );
  scale_spinner->set_alignment( GLUI_ALIGN_LEFT );

  glui->add_checkbox_to_panel( nav, "Draw axes", &show_axes );

  glui->set_main_gfx_window(main_window_id);

  /*****************************************************/
  /*              GLUI Bottom Panel                    */
  /*****************************************************/
  
  glui2 = GLUI_Master.create_glui_subwindow( mainWin, 
					     GLUI_SUBWINDOW_BOTTOM );
 
   /***************************************/
  /*   Current Visualization Selection    */
  /****************************************/
  GLUI_Panel *currVisSelection = 
    glui2->add_panel("Current Visualization");

  curr_vis_choices=
    glui2->add_radiogroup_to_panel(currVisSelection,
                                  NULL,CHANGE_VISUALIZATION_ID,control_cb);
  glui2->add_radiobutton_to_group( curr_vis_choices, "Boxes in Space" );
  glui2->add_radiobutton_to_group( curr_vis_choices, "City Scape" );
  glui2->add_radiobutton_to_group( curr_vis_choices, "Other" );

  load_saved =
    glui2->add_button_to_panel(currVisSelection, "Load Saved", 
                               LOAD_SAVED_ID, control_cb);
  load_saved->disable();


  /***************************************/
  /*     Visualization Attributes        */
  /***************************************/
  GLUI_Panel *currVisAttributes =
    glui2->add_panel("Visualization Attributes");
  
  x_list = glui2->add_listbox_to_panel(currVisAttributes, "X Position",
                                       NULL, CHANGE_X_ID, control_cb);
  for(i=0; i < 7; ++i)
    x_list->add_item(200+i,name[i]);
      
  y_list = glui2->add_listbox_to_panel(currVisAttributes, "Y Position",
                                       NULL, CHANGE_Y_ID, control_cb);
  for(i=0; i < 7; ++i)
    y_list->add_item(200+i,name[i]);

  z_list = glui2->add_listbox_to_panel(currVisAttributes, "Z Position",
                                       NULL, CHANGE_Z_ID, control_cb);
  
  glui2->add_column(false);

  for(i=0; i < 7; ++i)
    z_list->add_item(200+i,name[i]);

  w_list = glui2->add_listbox_to_panel(currVisAttributes, "Width",
                                       NULL, CHANGE_W_ID, control_cb);
  for(i=0; i < 7; ++i)
    w_list->add_item(200+i,name[i]);

  h_list = glui2->add_listbox_to_panel(currVisAttributes, "Height",
                                       NULL, CHANGE_H_ID, control_cb);
  for(i=0; i < 7; ++i)
    h_list->add_item(200+i,name[i]);
 
  d_list = glui2->add_listbox_to_panel(currVisAttributes, "Depth",
                                       NULL, CHANGE_D_ID, control_cb);
  
  glui2->add_column(false);

  for(i=0; i < 7; ++i)
    d_list->add_item(200+i,name[i]);

  c_list = glui2->add_listbox_to_panel(currVisAttributes, "Color",
                                       NULL, CHANGE_C_ID, control_cb);
  for(i=0; i < 7; ++i)
    c_list->add_item(200+i,name[i]);

  t_list = glui2->add_listbox_to_panel(currVisAttributes, "Texture",
                                       NULL, CHANGE_T_ID, control_cb);
  for(i=0; i < 7; ++i)
    t_list->add_item(200+i,name[i]);

  l_list = glui2->add_listbox_to_panel(currVisAttributes, "Lighting",
                                       NULL, CHANGE_L_ID, control_cb);
  for(i=0; i < 7; ++i)
    l_list->add_item(200+i,name[i]);
  
  glui2->add_column(false);

  s_list = glui2->add_listbox_to_panel(currVisAttributes, "Shape",
                                       NULL, CHANGE_S_ID, control_cb);
  for(i=0; i < 7; ++i)
    s_list->add_item(200+i,name[i]);

  save_curr =
    glui2->add_button_to_panel(currVisAttributes, "Save Current Settings",
                               SAVE_BUTTON_ID, control_cb);

  /***************************************/
  /*      Current Student Selection      */
  /***************************************/
  GLUI_Panel *currStudents = 
    glui2->add_panel("Students Visualized");
  
  /*callback id's for list of students = 300 + position 
    in array*/
  user1 = add_listbox_to_panel(currStudents, "Student 1", NULL
                               ,CHANGE_USER_1_ID, control_cb);
  for(i=0; i < numberOfStudents; ++i)
    user1->add_item(300+i, users[i]); 

  user2 = add_listbox_to_panel(currStudents, "Student 2", NULL
                               ,CHANGE_USER_2_ID, control_cb);
  for(i=0; i < numberOfStudents; ++i)
    user2->add_item(300+i, users[i]); 


 user3 = add_listbox_to_panel(currStudents, "Student 3", NULL
                               ,CHANGE_USER_3_ID, control_cb);
  for(i=0; i < numberOfStudents; ++i)
    user3->add_item(300+i, users[i]); 
  
  GLUI_Panel *dataSelect = 
    glui2->add_panel("Data Selection");
  
  time_panel =
    glui->add_listbox_to_panel(dataSelect, "Time Period", NULL,
                               CHANGE_TIME_ID, control_cb);
  time_panel->add_item(DAY_ALL, "All");
  time_panel->add_item(DAY_60,"Last 60 days");
  time_panel->add_item(DAY_30,"Last 30 days");
  time_panel->add_item(DAY_7,"Last week");
  time_panel->add_item(DAY_1,"Today only");
  time_panel->add_item(DAY_OTHER, "Other");

  GLUI_EditText *s_box=
    glui2->add_edittext_to_panel(time_panel, "Start time",
                                 GLUI_EDITTEXT_TEXT, &start_time); 
  s_box->disable();

  GLUI_EditText *e_box=
    glui2->add_edittext_to_panel(time_panel, "End time",
                                 GLUI_EDITTEXT_TEXT, &end_time); 
  e_box->disable();

  time_button =
    glui2->add_button_to_panel(time_panel, "Ok",
                               TIME_BUTTON_ID, control_cb);
  time_button->disable();

  glui2->set_main_gfx_window( main_window );

  glPopMatrix();

}  
/*****************************************************/
/*              clioInit()                           */ 
/*****************************************************/

/*
 * Procedure:
 *   clioInit
 * Purpose:
 *   Initializes everything for this version of Clio 3D to work.
 */
void clioInit(void)
{
  // Open GL Initialization
  glViewport(0,0,WIDTH,HEIGHT);	// Sets the viewport.
  glMatrixMode(GL_PROJECTION);	//sets 'camera' or field of view matrix
  glLoadIdentity();		//loads current matrix
  glOrtho(-10.0, 110.0, -10.0, 110.0, -10.0, 110.0);   
				
  glMatrixMode(GL_MODELVIEW);

  // Clear the world.
  glClearColor(0.0, 0.0, 0.0, 0.0); //clear to black
  glClear(GL_COLOR_BUFFER_BIT);
  glFlush();

  // Prepare test values
  loadData(NULL);
  // Set up default visualization
  cityScape();
} // clioInit




/* Displays main world */

void display(void)
{
  int i,j,k;
  glClear(GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 0.0);

  /* Show X, Y, and Z axis (R,G,B) so that I can tell what's going on. */
  glBegin(GL_LINES);
  glColor3f(1.0, 0.0, 0.0);
  glVertex3f(0.0, 0.0, 0.0);
  glVertex3f(500.0, 0.0, 0.0);
  glColor3f(0.0, 1.0, 0.0);
  glVertex3f(0.0, 0.0, 0.0);
  glVertex3f(0.0, 500.0, 0.0);
  glColor3f(0.0, 0.0, 1.0);
  glVertex3f(0.0, 0.0, 0.0);
  glVertex3f(0.0, 0.0, 500.0);
  glEnd();

#ifdef BOXES
  for (i = 0; i <= 3; i++) {
    for (j = 0; j <= 3; j++) {
      for (k = 0; k <= 3; k++) {
        clioBox(1,MAXC,
                500-500*i, 500-500*j, 500-500*k,
                50, 50, 50);
      }
    }
  }
#endif /* BOXES */
 
  for (i = 0; i < numvisits; ++i) {
    clioBox(getColor(visits+i), getShade(visits+i),
            getX(visits+i), getY(visits+i), getZ(visits+i),
            getW(visits+i), getH(visits+i), getD(visits+i));
  } /* for */

  glFlush();  //forces previously issued commands to begin execution
  glutSwapBuffers();
} //display

/*
 * Procedure:
 *   keyboard
 * Purpose:
 *   React to the user's choice of keyboard key.
 * Possibilities:
 *   a/A: translate in x axis
 *   w/W: translate in y axis
 *   s/S: translate in z axis
 *   x/X: rotate around x axis
 *   d/D: rotate around y axis
 *   c/C: rotate around z axis
 *   1-2: select a display scheme
 */
void keyboard(unsigned char key, int x, int y)
{
  printf("%c\n", key);
  switch (key) {
    // Restore
    case ' ': 
      glTranslatef(-xtrans, -ytrans, -ztrans);
      xtrans = 0;
      ytrans = 0;
      ztrans = 0;

    // Translations
    case 'a': 
      glTranslatef(TRANSLATE_UNIT, 0.0, 0.0); 
      xtrans += TRANSLATE_UNIT;
      break;
    case 'A': 
      glTranslatef(-TRANSLATE_UNIT, 0.0, 0.0); 
      xtrans -= TRANSLATE_UNIT;
      break;
    case 'w': 
      glTranslatef(0.0, TRANSLATE_UNIT, 0.0); 
      ytrans += TRANSLATE_UNIT;
      break;
    case 'W': 
      glTranslatef(0.0, -TRANSLATE_UNIT, 0.0); 
      ytrans -= TRANSLATE_UNIT;
      break;
    case 's': 
      glTranslatef(0.0, 0.0, TRANSLATE_UNIT); 
      ztrans += TRANSLATE_UNIT;
      break;
    case 'S': 
      glTranslatef(0.0, 0.0, -TRANSLATE_UNIT); 
      ztrans -= TRANSLATE_UNIT;
      break;

    // Rotations
    case 'x': glRotatef(ROTATE_UNIT, 1.0, 0.0,0.0); break;
    case 'X': glRotatef(-ROTATE_UNIT, 1.0, 0.0, 0.0); break;
    case 'd': glRotatef(ROTATE_UNIT, 0.0, 1.0, 0.0); break;
    case 'D': glRotatef(-ROTATE_UNIT, 0.0, 1.0, 0.0); break;
    case 'c': glRotatef(ROTATE_UNIT, 0.0, 0.0, 1.0); break;
    case 'C': glRotatef(-ROTATE_UNIT, 0.0, 0.0, 1.0); break;
    
    // Display Schemes 
    case '1': cityScape(); break;
    case '2': boxesInSpace(); break;
  } // switch
  
  display();
} // keyboard

/*********************************Resize Routines****************************/

void resize(int width, int height)
{
#ifdef RESIZE_CODE 
  if (height == 0) height = 1;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, width / height, 0.5, 1600.0);
  glViewport(0, 0, width, height);
  glTranslatef(0.0, -5.0, -150.0);
  
  glMatrixMode(GL_MODELVIEW);
#endif /* RESISE_CODE */
} // resize

void reshape2D(int w, int h)	/* generic 2D reshape callback */
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0,w,0,h);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
} //reshape2D

