// Lew Hill II
// MidiVizApp

#include <vrj/vrjConfig.h>

#include <math.h>
#include <GL/gl.h>
//#include <GL/glu.h>

#include <iostream>

#include <gmtl/Matrix.h> 
#include <gmtl/Generate.h>
#include <gmtl/Vec.h>

#include "MidiVizApp.h"

using namespace vrj;
using namespace gmtl;


void MidiVizApp::init() {
  std::cout << "---------- App:init() ---------------" << std::endl;
  // Initialize devices
  mWand.init("VJWand");
  mHead.init("VJHead");
  mButton0.init("VJButton0");
  mButton1.init("VJButton1");
  mButton2.init("VJButton2");
  mButton3.init("VJButton3");
  mButton4.init("VJButton4");
  mButton5.init("VJButton5");

  mForwardButton.init("VJButton0");
  mRotateButton.init("VJButton2");
  mModeButton.init("VJButton1");

  mode = COMBINED_MIDI_EQ_MODE_H;

  doAudioFrame = 1;

  initNav();

  initDrums();
  initBellTree();
  initWall();
  initLifeSim();
  initSpinner();
  initTowers();
  initField();
  initSnake();
  initPlanets();
  initStarField();

  initControllerBank();
  initControllerSphere();

  initDotPlot();
  initFractalTree();

  initGeometrizer();
  initFrequencyPlot();
  initVolumePainter();
  
  initMidiServer();
  initAudioServer();

  initEQWatcher();
  initDualHistory();

  backgroundColor[0] = 1.0;
  backgroundColor[1] = 1.0;
  backgroundColor[2] = 1.0;

  initBgColorPrefs();

  vpr::GUID new_guid("15c09c99-ed6d-4994-bbac-83587d4400d1");
  //  vpr::GUID new_guid("0c2e0281-5d20-451e-ba23-7a2d6db1e516");
  mSharedData.init(new_guid);

}

void MidiVizApp::flashBgToMidiEvent(MidiEvent event){
  if (event.getVelocity() != 0){
    int note = event.getNote();
    float* colorvec = note_color_table.getValue(note%12);
    backgroundColor[0] = colorvec[0]/2.0;
    backgroundColor[1] = colorvec[1]/2.0;
    backgroundColor[2] = colorvec[2]/2.0;
  }
}

void MidiVizApp::initBgColorPrefs(){

  setBgColorPref(WORLD_A_MODE, 0.1, 0.0, 0.0);

  setBgColorPref(WORLD_B_MODE, 0.0, 0.1, 0.0);

  setBgColorPref(WORLD_C_MODE, 0.0, 0.0, 0.1);

  setBgColorPref(WORLD_D_MODE, 0.17, 0.0, 0.31); 
  // purple space scene

  setBgColorPref(WORLD_E_MODE, 0.0, 0.0, 0.0); 
  // light grey speakerbox

  setBgColorPref(WORLD_F_MODE, 0.0, 0.0, 0.0); 
  // greenish psychedeliclollipop

  setBgColorPref(WORLD_G_MODE, 0.0, 0.0, 0.0);
  // ripple road

  setBgColorPref(WORLD_H_MODE, 0.0, 0.0, 0.2);
  // fountain

  setBgColorPref(WORLD_I_MODE, 0.05, 0.05, 0.05);
  // grey room

  setBgColorPref(COMBINED_MIDI_EQ_MODE_A, 0.0, 0.0, 0.0);
  setBgColorPref(COMBINED_MIDI_EQ_MODE_B, 0.0, 0.0, 0.0);
  setBgColorPref(COMBINED_MIDI_EQ_MODE_C, 0.0, 0.0, 0.0);

  //smet
  setBgColorPref(COMBINED_MIDI_EQ_MODE_D, 1.0, 1.0, 1.0);

  // captain
  setBgColorPref(COMBINED_MIDI_EQ_MODE_E, 1.0, 1.0, 1.0);

  // central radiation
  setBgColorPref(COMBINED_MIDI_EQ_MODE_F, 0.05, 0.05, 0.05);

  setBgColorPref(COMBINED_MIDI_EQ_MODE_G, 0.05, 0.05, 0.05);
  setBgColorPref(COMBINED_MIDI_EQ_MODE_H, 0.0, 0.0, 0.0);

}

void MidiVizApp::setBgColorPref(int mode, float r, float g, float b){
  bgColorPrefs[mode][0]= r;
  bgColorPrefs[mode][1]= g;
  bgColorPrefs[mode][2]= b;
}

float* MidiVizApp::getBgColorPref(int mode){
  return bgColorPrefs[mode];
}

void MidiVizApp::contextInit(){
  initGLState();       
  // Initialize the GL state information. (lights, shading, etc)
  initPlanetsContext();
  initWallContext();
  initLifeSimContext();
  initVolumePainterContext();
  initEQWatcherContext();
}

void MidiVizApp::initNav(){

  // in this case the nav matrix is already initialized to identity
  gmtl::identity(nav_matrix);

}

// Clears the viewport.  Put the call to glClear() in this
// method so that this application will work with configurations
// using two or more viewports per display window.
void MidiVizApp::bufferPreDraw()
{
  glClearColor(backgroundColor[0], backgroundColor[1], 
	       backgroundColor[2], 0.0f);
  glClear(GL_COLOR_BUFFER_BIT);
}


//----------------------------------------------
//  Draw the scene.
//
// - Draws a box and a coordinate axis set on the box
// - Offset and rotate the box by a matrix that we create
//----------------------------------------------
void MidiVizApp::draw()
{

   glClear(GL_DEPTH_BUFFER_BIT);

   // --- Setup for drawing --- //
   glMatrixMode(GL_MODELVIEW);

   // apply nav matrix and draw the world //

   glPushMatrix();
   glLoadIdentity();
   glMultMatrixf(nav_matrix.mData);
   glTranslatef(0,10,-80);

   // --- Draw the Wand Box --- //
   /*
   glPushMatrix();
   glTranslatef(wand_local_pos[0],
		wand_local_pos[1],
		wand_local_pos[2]);
   glColor3f(0.7, 0.7, 0.7);
   glScalef(0.10f, 0.10f, 0.10f);
   //   drawCube();
   glPopMatrix();
   */

   if(mode == WORLD_A_MODE){

     //   drawDrums();
     drawBellTree();
     drawWall();
     drawSpinner();
     drawTowers();
     drawField();
     drawSnake();

     drawControllerBank();
     drawControllerSphere();

   } else  if (mode ==WORLD_B_MODE){
     
     drawLifeSim();
     drawFractalTree();
     drawDotPlot();
     
   } else if (mode == WORLD_C_MODE) {
     
     drawGeometrizer();
     drawFrequencyPlot();
     drawVolumePainter();
     
   } else if (mode == WORLD_D_MODE) {
     drawPlanets();
     drawStarField();
     
   } else if(mode == WORLD_E_MODE) {
     drawEQWatcher(1);

   } else if(mode == WORLD_F_MODE) {
     drawEQWatcher(2);

   } else if(mode == WORLD_G_MODE) {
     drawEQWatcher(3);

   } else if(mode == WORLD_H_MODE) {
     drawEQWatcher(4);

   } else if(mode == WORLD_I_MODE) {
     drawEQWatcher(5);

   } else if(mode == COMBINED_MIDI_EQ_MODE_A){
     drawDualHistory(0);

   } else if(mode == COMBINED_MIDI_EQ_MODE_B){
     drawDualHistory(1);

   } else if(mode == COMBINED_MIDI_EQ_MODE_C){
     drawDualHistory(2);

   } else if(mode == COMBINED_MIDI_EQ_MODE_D){
     drawDualHistory(3);

   } else if(mode == COMBINED_MIDI_EQ_MODE_E){
     drawDualHistory(4);

   } else if(mode == COMBINED_MIDI_EQ_MODE_F){
     drawDualHistory(5);

   } else if(mode == COMBINED_MIDI_EQ_MODE_G){
     drawDualHistory(6);

   } else if(mode == COMBINED_MIDI_EQ_MODE_H){
     drawDualHistory(7);
   }
   
   glPopMatrix();

}

void MidiVizApp::drawBellTree(){
  
  mvbt->draw();
}

void MidiVizApp::initBellTree(){

  mvbt = new MidiVizBellTree(/*&music*/);
  
  mvbt->setPosition(15,1,-3);
  mvbt->setRootNote(33);
  mvbt->setChannel(0);
  mvbt->assignNotes();
  mvbt->assignColors();
  mvbt->adjustTreeLeafAngles();
  mvbt->setScale(.75, .75, .75);
}

void MidiVizApp::initWall(){
  mvwall = new MidiVizWall();
  mvwall->setPosition(5,5,-10);
  mvwall->setScale(2,1,1);
  mvwall->setRotation(0, 0, 0);
}

void MidiVizApp::initLifeSim(){
  mvlifesim[0] = new MidiVizLifeSim();
  mvlifesim[0]->setPosition(0, 0, -20);
  mvlifesim[0]->setScale(1,1,1);
  mvlifesim[0]->setRotation(0, 180, 0);

  mvlifesim[1] = new MidiVizLifeSim();
  mvlifesim[1]->setPosition(-10, 0, -14);
  mvlifesim[1]->setScale(1,1,1);
  mvlifesim[1]->setRotation(0, 220, 0);

  mvlifesim[2] = new MidiVizLifeSim();
  mvlifesim[2]->setPosition(10, 0, -14);
  mvlifesim[2]->setScale(1,1,1);
  mvlifesim[2]->setRotation(0, 140, 0);
}

void MidiVizApp::initSpinner(){
  mvspinner = new MidiVizSpinnerGroup();
  mvspinner->setPosition(10,0,10);
  mvspinner->setScale(1,1,1);
  mvspinner->setRotation(0, 0, 0);
}

void MidiVizApp::initTowers(){
  mvtowers = new MidiVizTowers();
  mvtowers->setPosition(-12,0,-2);
  mvtowers->setScale(1,1,1);
  mvtowers->setRotation(0, 45, 0);
}

void MidiVizApp::initField(){
  mvfield = new MidiVizField();
  mvfield->setPosition(16,0,-5);
  mvfield->setScale(.75,.75,.75);
  mvfield->setRotation(0,-90,0);
}

void MidiVizApp::initSnake(){
  mvsnake = new MidiVizSnake();
  mvsnake->setPosition(0,3,0);
  mvsnake->setScale(0.3, 0.3, 0.3);
  mvsnake->setRotation(0, 0, 0);
}

void MidiVizApp::initPlanets(){
  mvplanets = new MidiVizPlanets();
  mvplanets->setPosition(0,-2,0);
  mvplanets->setScale(2.0,2.0,2.0);
  mvplanets->setRotation(0, 0, 0);
}

void MidiVizApp::initPlanetsContext(){
  mvplanets->contextInit();
}

void MidiVizApp::initWallContext(){
  mvwall->contextInit();
}

void MidiVizApp::initVolumePainterContext(){
  mvvolumepainter->contextInit();
}

void MidiVizApp::initLifeSimContext(){
  mvlifesim[0]->contextInit();
  mvlifesim[1]->contextInit();
  mvlifesim[2]->contextInit();
}

void MidiVizApp::initEQWatcherContext(){
  mveqwatcher->contextInit();
}

void MidiVizApp::initStarField(){
  mvstarfield = new MidiVizStarField();
  mvstarfield->setPosition(-10,0,10);
  mvstarfield->setScale(5,5,5);
  mvstarfield->setRotation(0, 0, 0);
}

void MidiVizApp::initControllerBank(){
  mvcontrollerbank = new MidiVizControllerBank();
  mvcontrollerbank->setPosition(-15,0,7);
  mvcontrollerbank->setScale(.25,.25,.25);
  mvcontrollerbank->setRotation(0, 45, 0);
}

void MidiVizApp::initControllerSphere(){
  mvcontrollersphere = new MidiVizControllerSphere();
  mvcontrollersphere->setPosition(-10,5,7);
  mvcontrollersphere->setScale(.40,.40,.40);

}

void MidiVizApp::initDotPlot(){
  mvdotplot = new MidiVizDotPlot();
  mvdotplot->setPosition(14,1,0);
  mvdotplot->setScale(2,2,2);
  mvdotplot->setRotation(-90, 0, 0);
}

void MidiVizApp::initFractalTree(){
  mvfractaltree[0] = new MidiVizFractalTree(0);
  mvfractaltree[0]->setPosition(-19,0,2);
  mvfractaltree[0]->setScale(2,2,2);

  mvfractaltree[1] = new MidiVizFractalTree(0);
  mvfractaltree[1]->setPosition(-21,0,0);
  mvfractaltree[1]->setScale(2,2,2);

  mvfractaltree[2] = new MidiVizFractalTree(0);
  mvfractaltree[2]->setPosition(-17,0,-2);
  mvfractaltree[2]->setScale(2,2,2);
}

void MidiVizApp::initGeometrizer(){
  mvgeometrizer = new MidiVizGeometrizer();
  mvgeometrizer->setPosition(-20,0,-15);
  mvgeometrizer->setScale(.35,.35,.35);
  mvgeometrizer->setRotation(0, 45, 0);
}


void MidiVizApp::initFrequencyPlot(){
  mvfrequencyplot = new MidiVizFrequencyPlot();
  mvfrequencyplot->setPosition(20,0,-15);
  mvfrequencyplot->setScale(.15,.15,.15);
  mvfrequencyplot->setRotation(0, -45, 0);
}

void MidiVizApp::initVolumePainter(){
  mvvolumepainter = new MidiVizVolumePainter();
  mvvolumepainter->setPosition(0,0,-20);
  mvvolumepainter->setScale(.20,.20,.20);
}

void MidiVizApp::initEQWatcher(){
  mveqwatcher = new MidiVizEQWatcher(fftVals, mRandomNumbers);
  mveqwatcher->setPosition(0,0,0);
  mveqwatcher->setScale(2,2,2);
  mveqwatcher->setRotation(0,0,0);
}

void MidiVizApp::initDualHistory(){
  history.setPosition(0,0,0);
  history.setScale(1,1,1);
  history.setRotation(0,0,0);
}

void MidiVizApp::intersectBellTree(){

  /*
        if (mButton0->getData() == gadget::Digital::TOGGLE_ON){
      mvbt->intersect(wand_global_pos, 0);
    }
    
    if (mButton1->getData() == gadget::Digital::TOGGLE_ON){
      mvbt->intersect(wand_global_pos, 1);
    }
    
    if (mButton2->getData()  == gadget::Digital::TOGGLE_ON){
      mvbt->intersect(wand_global_pos, 2);
    }
    
    if (mButton3->getData() == gadget::Digital::TOGGLE_ON ){
      mvbt->intersect(wand_global_pos, 3);
    }
    
    if (mButton4->getData() == gadget::Digital::TOGGLE_ON ){
      mvbt->intersect(wand_global_pos, 4);
    }
    
    if (mButton5->getData() == gadget::Digital::TOGGLE_ON ){
      mvbt->intersect(wand_global_pos, 5);
    }
    
  */
}

void MidiVizApp::processAudio(){
  mveqwatcher->storeSample();

}

void MidiVizApp::processMidiEvent(MidiEvent event){
  
  //event.printData();

  if (event.isKeyOnEvent()){  

    if (mode == WORLD_A_MODE){ 
    
      mvbt->processMidiEvent(event);
      mvwall->processMidiEvent(event);
      mvspinner->processMidiEvent(event);
      mvtowers->processMidiEvent(event);
      mvfield->processMidiEvent(event);
      mvsnake->processMidiEvent(event);
      
      //      flashBgToMidiEvent(event);

    } else if (mode == WORLD_B_MODE){
      
      mvdotplot->processMidiEvent(event);
      mvfractaltree[0]->processMidiEvent(event);
      mvfractaltree[1]->processMidiEvent(event);
      mvfractaltree[2]->processMidiEvent(event);
      mvlifesim[0]->processMidiEvent(event);
      //mvlifesim[1]->processMidiEvent(event);
      //mvlifesim[2]->processMidiEvent(event);
      
    } else if (mode == WORLD_C_MODE){
      
      mvgeometrizer->processMidiEvent(event);
      mvfrequencyplot->processMidiEvent(event);
      mvvolumepainter->processMidiEvent(event);

    } else if (mode == WORLD_D_MODE){

      mvplanets->processMidiEvent(event);
      mvstarfield->processMidiEvent(event);
      
    } else if (mode == WORLD_E_MODE) {
     
      //      flashBgToMidiEvent(event);
    }

  } else if (event.isControlChangeEvent()){
   
    mvcontrollerbank->processMidiEvent(event);
    mvcontrollersphere->processMidiEvent(event);
   
    history.processCCEvent(event);
    
    //    cout << "CCEvent " 
    // << event.getControllerNumber() << " "  
    // << event.getControllerValue() << endl;
    
  } else if (event.isPitchBendEvent()){
    
    cout << "PitchBendEvent " 
	 << event.getPitchBendValueA() << " "
	 << event.getPitchBendValueB() << endl; 
    
  } else if (event.isActiveSensingEvent()){
    // who knows what to do with these...???
    
  }
	     
}

void MidiVizApp::frameAudioServer(){
  
  int value = 0;
  // If mSharedData is not local, we want to skip this process.
  if (!mSharedData.isLocal())
    {
      return;
    }
  
  mSharedData->generateRandomNumbers();
  
  while (value > -1){
    
    for (int i = 0; i < NUM_BANDS+1; i++){
      fftChars[i] = 0x00;
    }
    
    value = audioServer->recvString(fftChars);
    

    if (value > 0){
      
      for (int i = 0; i < NUM_BANDS; i++){
	
	// convert packets info from [1-125] into float information.
        fftVals[i] = ((((float) fftChars[i])-1)/125.0);
	
	/*
	// print
	cout << "{ i = "  << i;
	printf(" %u ", fftChars[i]);	  
	cout << " " << fftVals[i] << " }" << endl;
	*/

      }

      mSharedData->takeSnapshot(fftVals);
      
    }
  }
}

void MidiVizApp::latePreFrame(){

    mSharedData->getRandomNumbers(mRandomNumbers);

  int numSamples = mSharedData->getNumSamples();

  //std::cout << "retreiving num: " << numSamples << " samples." << std::endl;
  for (int i = 0 ; i < numSamples ; i++) {
    mSharedData->retrieveSample(fftVals, i);
    mveqwatcher->storeSample();
    history.storeSample(fftVals);
  }
  
  int eventInts[9];
  
  int numEvents = mSharedData->getNumEvents();
  //std::cout << "retreiving num: " << numEvents << " events." << std::endl;
  for (int i = 0 ; i < numEvents ; i++) {
    mSharedData->retrieveEvent(eventInts, i);
    incomingEvent.setData(eventInts[0], eventInts[1],  
			  eventInts[2], eventInts[3]);
    incomingEvent.setTimeStamp(eventInts[4], eventInts[5], 
			       eventInts[6], eventInts[7],
			       eventInts[8]);
    //incomingEvent.printData();
    processMidiEvent(incomingEvent);      
    

    if (incomingEvent.isKeyOnEvent()){
      history.processMidiEvent(incomingEvent);
    }
  }

  //  history.nextFrame();

  mSharedData->clear();

}


void MidiVizApp::frameMidiServer(){
  
  int value = 0;
  
  while (value > -1){
    
    for (int i = 0; i < 11; i++){
      packet[i] = 0x00;
    }
    
    value = midiServer->recvString(packet);

    if(value > 0){
      //      cout << "Value = " << value << endl; 
      // printf("Midi Packet Hex Contents = ");
      // for(int i = 0; i < 6; i++){
      // printf("%02x ", packet[i]);
      // }
      
      // create midievent
      // format is
      
      // packet[0] = 0x7f;
      // packet[1] = event type
      // packet[2] = channel + 1   // can't send a zero through the socket
      // packet[3] = note number
      // packet[4] = velocity+1

      // packet[5] = h+1
      // packet[6] = mn+1;
      // packet[7] = sec+1;
      // packet[8] = ms_high + 1;
      // packet[9] = ms_low + 1;

      // packet[10] = 0x00; // end character

      int eventInts[9];

      eventInts[0] =packet[1];  // event type
      eventInts[1] =packet[2]-1; // chanel
      eventInts[2] =packet[3]; // note number
      eventInts[3] =packet[4]-1; // velocity

      eventInts[4] = packet[5] - 1; // hr
      eventInts[5] = packet[6] - 1; // mn
      eventInts[6] = packet[7] - 1; // sec
      eventInts[7] = packet[8] - 1; // ms_high
      eventInts[8] = packet[9] - 1; // ms_low

      mSharedData->takeEvent(eventInts);

	/* defer processing now till after shared data  sync. in late preframe
      incomingEvent.setData(packet[1], 
			    packet[2]-1, 
			    packet[3], 
			    packet[4] -1);
      processMidiEvent(incomingEvent);
	*/


    }
  }
  //  cout << "End Frame Server" << endl;
}

void MidiVizApp::sendToClient(){
   
  char packet[8];
  
  packet[0] = 0x3;
  packet[1] = 0x6;
  packet[2] = 0x9;
  packet[3] = 0x12;
  packet[4] = 0x22;
  packet[5] = 0x44;
  packet[6] = 0x7f;
  packet[7] = 0x00;

  midiServer->sendString(packet);

}

void MidiVizApp::frameBellTree(){
  mvbt->frame(10);
}

void MidiVizApp::frameWall(){
  mvwall->frame();
}

void MidiVizApp::frameLifeSim(){
  mvlifesim[0]->frame();
  //  mvlifesim[1]->frame();
  //mvlifesim[2]->frame();
}

void MidiVizApp::frameSpinner(){
  mvspinner->frame();
}

void MidiVizApp::frameTowers(){
  mvtowers->frame();
}

void MidiVizApp::frameField(){
  mvfield->frame();
}

void MidiVizApp::frameSnake(){
  mvsnake->frame();
}

void MidiVizApp::framePlanets(){
  mvplanets->frame();
}

void MidiVizApp::frameStarField(){
  mvstarfield->frame();
}

void MidiVizApp::frameControllerBank(){
  mvcontrollerbank->frame();
}

void MidiVizApp::frameControllerSphere(){
  mvcontrollersphere->frame();
}

void MidiVizApp::frameDotPlot(){
  mvdotplot->frame();
}

void MidiVizApp::frameFractalTree(){
  mvfractaltree[0]->frame();
  mvfractaltree[1]->frame();
  mvfractaltree[2]->frame();
}

void MidiVizApp::frameGeometrizer(){
  mvgeometrizer->frame();
}

void MidiVizApp::frameFrequencyPlot(){
  mvfrequencyplot->frame();
}

void MidiVizApp::frameVolumePainter(){
  mvvolumepainter->frame();
}

void MidiVizApp::frameEQWatcher(){
  mveqwatcher->frame();
}


void MidiVizApp::initDrums(){

  mvt1.setNote(36);
  mvt1.setChannel(9);
  mvt1.setColor(1.0,0.0,0.0);
  mvt1.setPosition(4, 3, -4);

}

void MidiVizApp::drawWall(){
  mvwall->draw();
}

void MidiVizApp::drawLifeSim(){
  mvlifesim[0]->draw();
  //mvlifesim[1]->draw();
  //mvlifesim[2]->draw();
}

void MidiVizApp::drawSpinner(){
  mvspinner->draw();
}

void MidiVizApp::drawTowers(){
  mvtowers->draw();
}

void MidiVizApp::drawField(){
  mvfield->draw();
}

void MidiVizApp::drawSnake(){
  mvsnake->draw();
}

void MidiVizApp::drawPlanets(){
  mvplanets->draw();
}

void MidiVizApp::drawStarField(){
  mvstarfield->draw();
}

void MidiVizApp::drawControllerBank(){
  mvcontrollerbank->draw();
}

void MidiVizApp::drawControllerSphere(){
  mvcontrollersphere->draw();
}

void MidiVizApp::drawDotPlot(){
  mvdotplot->draw();
}

void MidiVizApp::drawFractalTree(){

  glPushMatrix();
  glColor3f(0.5, 0, 0);
  mvfractaltree[0]->draw();
  glPopMatrix();

  /*  
  glPushMatrix();
  glColor3f(0, 0.5, 0);
  mvfractaltree[1]->draw();
  glPopMatrix();

  glPushMatrix();
  glColor3f(0, 0, 0.5);
  mvfractaltree[2]->draw();
  glPopMatrix();
  */

}

void MidiVizApp::drawGeometrizer(){

  mvgeometrizer->drawAll();

}

void MidiVizApp::drawFrequencyPlot(){
  mvfrequencyplot->draw();
}

void MidiVizApp::drawVolumePainter(){
mvvolumepainter->draw();
}

void MidiVizApp::drawEQWatcher(int mode){
  
  if (mode == 1){
    mveqwatcher->drawWatcher();
    mveqwatcher->drawBackground();
  } else if (mode == 2){
    mveqwatcher->drawLollipop();
  } else if (mode == 3){
    mveqwatcher->drawHistory();
  } else if (mode == 4){
    mveqwatcher->drawWaterFountain();
  } else if (mode == 5){
    mveqwatcher->drawDiscRoom();
  }
}

void MidiVizApp::drawDualHistory(int mode){

  history.drawDualHistoryVolume(mode);
}


// drum block

void MidiVizApp::drawDrums(){
  mvt1.draw();
}

void MidiVizApp::frameDrums(){
  mvt1.frame(10);
}


void MidiVizApp::intersectDrums(){
  
    
    if (mButton0->getData() ||
	mButton1->getData() ||
	mButton2->getData() ||
	mButton3->getData() ||
	mButton4->getData() ||
	mButton5->getData()) {
      
      if (mvt1.intersect(wand_global_pos)){
	
	if(mButton0->getData()  == gadget::Digital::TOGGLE_ON){	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),36, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
	
	if(mButton1->getData() == gadget::Digital::TOGGLE_ON ){	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),38, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
	
	if(mButton2->getData() == gadget::Digital::TOGGLE_ON ){	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),42, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
	
	if(mButton3->getData()  == gadget::Digital::TOGGLE_ON){	  
	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),46, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
	
	if(mButton4->getData() == gadget::Digital::TOGGLE_ON ){	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),51, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
	
	if(mButton5->getData() == gadget::Digital::TOGGLE_ON){	  
	  MidiEvent* event = new MidiEvent(0, mvt1.getChannel(),49, 100);
	  //music.playSound(event);
	  mvt1.startAnimation(event);
	  delete(event);
	}
      }
    }
}

void MidiVizApp::frameWand(){

   // -- Get Wand matrix --- //
   wand_local_matrix = mWand->getData();

   wand_local_pos[0] = wand_local_matrix.mData[12]; 
   wand_local_pos[1] = wand_local_matrix.mData[13];
   wand_local_pos[2] = wand_local_matrix.mData[14];

 
   // wired to button 2 of the set (0,1,2,3,4,5);

   if (mModeButton->getData()  == gadget::Digital::TOGGLE_ON){
     // passed button test

     if (mode == WORLD_A_MODE){ 
       
       mode = WORLD_B_MODE;
       flashBackground(WORLD_B_MODE);
       initNav();
       cout << "Mode B" << endl;

     } else if (mode == WORLD_B_MODE){
       
       mode = WORLD_C_MODE;
       flashBackground(WORLD_C_MODE);
       initNav();
       cout << "Mode C" << endl;
       
     } else if (mode == WORLD_C_MODE){
       
       mode = WORLD_D_MODE;
       flashBackground(WORLD_D_MODE);
       initNav();
       cout << "Mode D" << endl;
    
     } else if (mode == WORLD_D_MODE){
       
       mode = WORLD_E_MODE;
       flashBackground(WORLD_E_MODE);
       initNav();
       cout << "Mode E" << endl;

     } else if (mode == WORLD_E_MODE){

       mode = WORLD_F_MODE;
       flashBackground(WORLD_F_MODE);
       initNav();
       cout << "Mode F" << endl;

     } else if (mode == WORLD_F_MODE){

       mode = WORLD_G_MODE;
       flashBackground(WORLD_G_MODE);
       initNav();
       cout << "Mode G" << endl;

     } else if (mode == WORLD_G_MODE){

       mode = WORLD_H_MODE;
       flashBackground(WORLD_H_MODE);
       initNav();
       cout << "Mode H" << endl;

     } else if (mode == WORLD_H_MODE){

       mode = WORLD_I_MODE;
       flashBackground(WORLD_I_MODE);
       initNav();
       cout << "Mode I" << endl;

     }  else if (mode == WORLD_I_MODE){
       
       mode = COMBINED_MIDI_EQ_MODE_A;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode A" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_A){
       
       mode = COMBINED_MIDI_EQ_MODE_B;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode B" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_B){

       mode = COMBINED_MIDI_EQ_MODE_C;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode C" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_C){

       mode = COMBINED_MIDI_EQ_MODE_D;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode D" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_D){

       mode = COMBINED_MIDI_EQ_MODE_E;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode E" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_E){

       mode = COMBINED_MIDI_EQ_MODE_F;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode F" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_F){

       mode = COMBINED_MIDI_EQ_MODE_G;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode G" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_G){

       mode = COMBINED_MIDI_EQ_MODE_H;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Combined Midi EQ Mode H" << endl;

     }  else if (mode == COMBINED_MIDI_EQ_MODE_H){
       mode = WORLD_A_MODE;
       flashBackground(WORLD_A_MODE);
       initNav();
       cout << "Mode A" << endl;

     }

   } // end button test.
   
   previousModeButtonState = mModeButton->getData();
   
}

void MidiVizApp::flashBackground(int new_mode){

  if (new_mode == WORLD_A_MODE){
    backgroundColor[0] = 0.3;
    backgroundColor[1] = 0.3;
    backgroundColor[2] = 0.0;

  } else if (new_mode == WORLD_B_MODE){
    backgroundColor[0] = 0.0;
    backgroundColor[1] = 0.3;
    backgroundColor[2] = 0.3;

  } else if (new_mode == WORLD_C_MODE){
    backgroundColor[0] = 0.3;
    backgroundColor[1] = 0.0;
    backgroundColor[2] = 0.3;

  } else if (new_mode == WORLD_D_MODE){
    backgroundColor[0] = 0.0;
    backgroundColor[1] = 0.3;
    backgroundColor[2] = 0.0;

  } else if (new_mode == WORLD_E_MODE){
    backgroundColor[0] = 0.3;
    backgroundColor[1] = 0.5;
    backgroundColor[2] = 0.2;

  }  else if (new_mode == WORLD_F_MODE){
    backgroundColor[0] = 0;
    backgroundColor[1] = 0;
    backgroundColor[2] = 1;
    
  }   else if ((new_mode == WORLD_G_MODE)||
	       (new_mode == WORLD_H_MODE)||
	       (new_mode == WORLD_I_MODE)){

    backgroundColor[0] = 1;
    backgroundColor[1] = .5;
    backgroundColor[2] = 0;
 }

}

void MidiVizApp::frameBackground(){
  
  float* bgcolorpref = getBgColorPref(mode);

  for (int i = 0; i < 3; i++){
    backgroundColor[i] = backgroundColor[i]*.9 + bgcolorpref[i] *.1;
  }

}

void MidiVizApp::frameNav(){
  
  // Update navigation
  // - Find forward direction of wand
  // - Translate along that direction
  
  float velocity(0.20f);
  float rotation(0.0f);
  if(mForwardButton->getData()){
    gmtl::Vec3f Zdir = gmtl::Vec3f(0.0f, 0.0f, velocity);
    gmtl::Vec3f direction(wand_local_matrix * Zdir);
    gmtl::preMult(nav_matrix, 
		  gmtl::makeTrans<gmtl::Matrix44f>(direction));
  }   
  
  if(mRotateButton->getData()) {
    cout <<"Rotate button" << endl;
    freeze_unfreeze_audio();

    const float rot_scale(0.01f);
    float y_rot = gmtl::makeYRot<float, 4, 4>(wand_local_matrix);
    rotation = -1.0f * y_rot * rot_scale;
    gmtl::preMult(nav_matrix,
		  gmtl::makeRot<gmtl::Matrix44f>(gmtl::EulerAngleXYZf(0.0f,rotation,0.0f)));
  }
  
  // ---- RESET ---- //
  // If the reset button is pressed, reset the state of the application.
  // This button takes precedence over all others.
  if (mForwardButton->getData() &&  mRotateButton->getData()){
    this->resetNav();
  }
  
  // update wand_navxform_matrix
  
  Matrix44f inv_nav_matrix;
  gmtl::invert(inv_nav_matrix, nav_matrix);
  gmtl::mult(wand_global_matrix, wand_local_matrix, inv_nav_matrix);
  
  wand_global_pos[0] = wand_global_matrix.mData[12]; 
  wand_global_pos[1] = wand_global_matrix.mData[13];
  wand_global_pos[2] = wand_global_matrix.mData[14];
  
}

void MidiVizApp::freeze_unfreeze_audio(){
  if (doAudioFrame == 1){
    doAudioFrame = 0;
  } else {
    doAudioFrame = 1;
  }

}


void MidiVizApp::resetNav(){
  gmtl::identity(nav_matrix);
}


void MidiVizApp::preFrame(){
       
    frameMidiServer();

  if (doAudioFrame){
    frameAudioServer();
  }

  frameBackground();

  frameWand();
  frameNav();

  //  intersectDrums();
  //  frameDrums();
  
  //  intersectBellTree();

  if (mode == WORLD_A_MODE){
    
    frameBellTree();
    frameWall();

    frameSpinner();
    frameTowers();
    frameField();
    frameSnake();

    
    frameControllerBank();
    frameControllerSphere();
    
  } else if (mode == WORLD_B_MODE){
    
    frameLifeSim();
    frameDotPlot();
    frameFractalTree();

  } else if (mode == WORLD_C_MODE){
    
    frameGeometrizer();
    frameFrequencyPlot();
    frameVolumePainter();

  } else if (mode == WORLD_D_MODE){

    framePlanets();
    frameStarField();

  } else if ((mode == WORLD_E_MODE) || 
	     (mode == WORLD_F_MODE) || 
	     (mode == WORLD_G_MODE)){
    frameEQWatcher();
  }

  // now store previous mouse button status
     // must be done at the end of a frame
  
  previous_mButton0 = mButton0->getData();
  previous_mButton1 = mButton1->getData();
  previous_mButton2 = mButton2->getData();
  previous_mButton3 = mButton3->getData();
  previous_mButton4 = mButton4->getData();
  previous_mButton5 = mButton5->getData();
  
}


void MidiVizApp::initGLState()
{
   GLfloat light0_ambient[] = { 0.3f,  0.3f,  0.3f,  1.0f};
   GLfloat light0_diffuse[] = { 1.0f,  1.0f,  1.0f,  1.0f};
   GLfloat light0_specular[] = { 1.0f,  1.0f,  1.0f,  1.0f};
   GLfloat light0_position[] = {0.0f, 0.75f, 0.75f, 0.0f};

   GLfloat mat_ambient[] = { 1.0, 1.0,  1.0,  1.0};
   GLfloat mat_diffuse[] = { 1.0,  1.0,  1.0,  1.0};
   GLfloat mat_specular[] = { 1.0,  1.0,  1.0,  1.0};
   GLfloat mat_shininess[] = { 80.0};
//   GLfloat mat_emission[] = { 1.0,  1.0,  1.0,  1.0};
   GLfloat no_mat[] = { .05,  .05,  .05,  1.0};

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

   glMaterialfv( GL_FRONT, GL_AMBIENT, mat_ambient );
   glMaterialfv( GL_FRONT,  GL_DIFFUSE, mat_diffuse );
   glMaterialfv( GL_FRONT, GL_SPECULAR, mat_specular );
   glMaterialfv( GL_FRONT,  GL_SHININESS, mat_shininess );
   glMaterialfv( GL_FRONT,  GL_EMISSION, no_mat);

   glEnable(GL_DEPTH_TEST);
   glEnable(GL_NORMALIZE);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_COLOR_MATERIAL);
   glShadeModel(GL_SMOOTH);
}

/// Utility function for drawing a cube
void drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
             GLdouble z0, GLdouble z1, GLenum type)
{
   static GLdouble n[6][3] = {
      {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
      {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
   };
   static GLint faces[6][4] = {
      { 0, 1, 2, 3}, { 3, 2, 6, 7}, { 7, 6, 5, 4},
      { 4, 5, 1, 0}, { 5, 6, 2, 1}, { 7, 4, 0, 3}
   };
   GLdouble v[8][3], tmp;
   GLint i;

   if (x0 > x1)
   {
      tmp = x0; x0 = x1; x1 = tmp;
   }
   if (y0 > y1)
   {
      tmp = y0; y0 = y1; y1 = tmp;
   }
   if (z0 > z1)
   {
      tmp = z0; z0 = z1; z1 = tmp;
   }
   v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
   v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
   v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
   v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
   v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
   v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;

   for (i = 0; i < 6; i++)
   {
      glBegin(type);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][0]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][1]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][2]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][3]][0]);
      glEnd();
   }
}

