// Lew Hill II
// MidiVizApp

#ifndef _MIDI_VIZ_APP_
#define _MIDI_VIZ_APP_

#include <vrj/vrjConfig.h>

#include <iostream>
#include <iomanip>

//#include "midiLew.h"

#include "MidiVizTrapezoid.h"
#include "MidiVizBellTree.h"
#include "MidiEvent.h"
#include "MidiVizWall.h"
#include "MidiVizLifeSim.h"
#include "MidiVizSpinnerGroup.h"
#include "MidiVizTowers.h"
#include "MidiVizField.h"
#include "MidiVizSnake.h"
#include "MidiVizPlanets.h"
#include "MidiVizStarField.h"
#include "MidiVizControllerBank.h"
#include "MidiVizControllerSphere.h"
#include "MidiVizDotPlot.h"
#include "MidiVizFractalTree.h"

#include "MidiVizGeometrizer.h"
#include "MidiVizFrequencyPlot.h"
#include "MidiVizVolumePainter.h"

#include "MidiVizEQWatcher.h"

#include "MidiVizDualHistory.h"

#include <SharedData.h>

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

#include <vrj/Display/Projection.h>

#include <vrj/Draw/OGL/GlApp.h>
#include <gmtl/Vec.h>
#include <gadget/Type/PositionInterface.h>
#include <gadget/Type/DigitalInterface.h>

#include "udpServerClass.h"

#define TRUE 1
#define FALSE 0

#define WORLD_A_MODE 0
#define WORLD_B_MODE 1
#define WORLD_C_MODE 2
#define WORLD_D_MODE 3
#define WORLD_E_MODE 4
#define WORLD_F_MODE 5
#define WORLD_G_MODE 6
#define WORLD_H_MODE 7
#define WORLD_I_MODE 8
#define COMBINED_MIDI_EQ_MODE_A 9
#define COMBINED_MIDI_EQ_MODE_B 10
#define COMBINED_MIDI_EQ_MODE_C 11
#define COMBINED_MIDI_EQ_MODE_D 12
#define COMBINED_MIDI_EQ_MODE_E 13
#define COMBINED_MIDI_EQ_MODE_F 14
#define COMBINED_MIDI_EQ_MODE_G 15
#define COMBINED_MIDI_EQ_MODE_H 16

#define NUM_BARS 16

using namespace vrj;
using namespace gmtl;
using namespace std;

// Utiity function to draw a cube
void drawbox( GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
              GLdouble z0, GLdouble z1, GLenum type );

/**
 * Simple OGL Demonstration application.
 *
 * This application intialized and recieves positional
 * and digital intput from the wand.
 *
 * It also has basic code that draws a box centered on
 * the origin.
 */
class MidiVizApp : public GlApp
{
public:
  MidiVizApp()
   {;}

   virtual ~MidiVizApp (void) {
     
     finalize();
   }

public: // ---- INITIALIZATION FUNCTIONS ---- //
   /**
    * Executes any initialization needed before the API is started.
    *
    * @post Device interfaces are initialized with the device names
    *       we want to use.
    * @note This is called once before OpenGL is initialized.
    */
   

   void finalize(){
     cout << "Closing the socket" << endl;
     midiServer->closeSocket();
     delete(midiServer);

     audioServer->closeSocket();
     delete(audioServer);
   }

   virtual void init();

   void initBgColorPrefs();
   void setBgColorPref(int mode, float r, float g, float b);
   float* getBgColorPref(int mode);

   void initNav();

   void initMidiServer(){
     midiServer = new udpServerClass(midiPort);
     midiServer->setBlocking(FALSE);
   }

   void initAudioServer(){
     audioServer = new udpServerClass(audioPort);
     audioServer->setBlocking(FALSE);
   }
  
   void sendToClient();

   void setMidiPort(int in_port){
     midiPort = in_port;
     cout << "Port set to: " << midiPort << endl;
   }

   void setAudioPort(int in_port){
     audioPort = in_port;
     cout << "Port set to: " << audioPort << endl;
   }

   /**
    * Executes any initialization needed after API is started but before the
    * drawManager starts the drawing loops.
    *
    * This is called once after OGL is initialized.
    */
   virtual void apiInit()
   {;}

public:
   // ----- Drawing Loop Functions ------
   //
   //  The drawing loop will look similar to this:
   //
   //  while (drawing)
   //  {
   //        preFrame();
   //       draw();
   //        intraFrame();      // Drawing is happening while here
   //       sync();
   //        postFrame();      // Drawing is now done
   //
   //       UpdateDevices();
   //  }
   //------------------------------------

   /**
    * Function that is called upon entry into a buffer of an OpenGL context
    * (window).
    *
    * @note This function is designed to be used when you want to do something
    *       only once per buffer (ie.once for left buffer, once for right
    *       buffer).
    */
   virtual void bufferPreDraw();

   /**
    * Called before start of frame.
    *
    * @note Function called after device updates but before start of drawing.
    */
   virtual void preFrame();
   
   virtual void latePreFrame();
   
   void frameNav();
   void resetNav();

   void frameWand();

   void flashBackground(int new_mode);
   // causes a color flash to indicate a mode change


   void frameBackground();

   void frameMidiServer(); 
   // read input communication and send notes to appropriate viz component

   void frameAudioServer(); 
   // read input communication and send notes to appropriate viz component

   void initDrums();
   void drawDrums();
   void intersectDrums();
   void frameDrums();

   void drawBellTree();
   void intersectBellTree();
   void frameBellTree();
   void initBellTree();
    
   void initWall();
   void initWallContext();
   void frameWall();
   void drawWall();

   void initLifeSim();
   void initLifeSimContext();
   void frameLifeSim();
   void drawLifeSim();

   void initSpinner();
   void frameSpinner();   
   void drawSpinner();

   void initTowers();
   void frameTowers();   
   void drawTowers();

   void initField();
   void frameField();   
   void drawField();

   void initSnake();
   void frameSnake();   
   void drawSnake();

   void initPlanets();
   void initPlanetsContext();
   void framePlanets();   
   void drawPlanets();

   void initStarField();
   void frameStarField();   
   void drawStarField();

   void initControllerBank();
   void frameControllerBank();
   void drawControllerBank();

   void initControllerSphere();
   void frameControllerSphere();
   void drawControllerSphere();

   void initDotPlot();
   void frameDotPlot();
   void drawDotPlot();

   void initFractalTree();
   void frameFractalTree();
   void drawFractalTree();

   void initGeometrizer();
   void frameGeometrizer();
   void drawGeometrizer();

   void initFrequencyPlot();
   void frameFrequencyPlot();
   void drawFrequencyPlot();

   void initVolumePainter();
   void initVolumePainterContext();
   void frameVolumePainter();
   void drawVolumePainter();

   void processMidiEvent(MidiEvent event);
   void processAudio();

   void flashBgToMidiEvent(MidiEvent event);

   // audio modules
   void initEQWatcher();
   void frameEQWatcher();
   void drawEQWatcher(int mode);
   void initEQWatcherContext();

   // combined modules
   void initDualHistory();
   void drawDualHistory(int mode);

   /**
    * Called during the Frame.
    *
    * @note Function called after drawing has been triggered but BEFORE it
    *       completes.
    */
   virtual void intraFrame() {;}

   /**
    * Called at end of frame.
    *
    * @note Function called before updating trackers but after the frame is
    *       drawn.
    */
   virtual void postFrame() {;}

public: // ----- OpenGL FUNCTIONS ---- //
   /**
    * Function that is called immediately after a new OGL context is created.
    * Initialize GL state here. Also used to create context specific
    * information.
    *
    * This is called once for each context.
    */
   virtual void contextInit();

   /**
    * Function to draw the scene.
    *
    * @pre OpenGL state has correct transformation and buffer selected.
    * @post The current scene has been drawn.
    *
    * @note Called 1 or more times per frame.
    */
   virtual void draw();
   

private:
   void initGLState();

   void drawCube()
   {
      drawbox(-0.5, 0.5, -0.5, 0.5, -0.5, 0.5, GL_QUADS);
   }

   void freeze_unfreeze_audio();


 public:
   NoteColorLookupTable note_color_table;
   
   gadget::PositionInterface  mWand;    
   gadget::PositionInterface  mHead; 

   gadget::DigitalInterface   mButton0; 
   gadget::DigitalInterface   mButton1; 
   gadget::DigitalInterface   mButton2; 
   gadget::DigitalInterface   mButton3; 
   gadget::DigitalInterface   mButton4; 
   gadget::DigitalInterface   mButton5; 

   gadget::DigitalInterface   mForwardButton;
   gadget::DigitalInterface   mRotateButton;

   gadget::DigitalInterface   mModeButton;

   bool previous_mButton0, 
     previous_mButton1,
     previous_mButton2, 
     previous_mButton3,
     previous_mButton4, 
     previous_mButton5;

   bool previousModeButtonState;
   
   //   midiLew music;

   MidiVizTrapezoid  mvt1, mvt2, mvt3;
   MidiVizBellTree *mvbt;
   MidiVizWall *mvwall;
   MidiVizLifeSim *mvlifesim[3];
   MidiVizSpinnerGroup *mvspinner;
   MidiVizTowers *mvtowers;
   MidiVizField *mvfield;
   MidiVizSnake *mvsnake;
   MidiVizPlanets *mvplanets;
   MidiVizStarField *mvstarfield;

   MidiVizControllerBank *mvcontrollerbank;
   MidiVizControllerSphere *mvcontrollersphere;

   MidiVizDotPlot *mvdotplot;
   MidiVizFractalTree *mvfractaltree[3];

   MidiVizGeometrizer *mvgeometrizer;
   MidiVizFrequencyPlot *mvfrequencyplot;
   MidiVizVolumePainter *mvvolumepainter;

   udpServerClass* midiServer;
   int midiPort;
   MidiEvent incomingEvent;
   char packet[12];   

   MidiVizEQWatcher* mveqwatcher;

   MidiVizDualHistory history;

   udpServerClass* audioServer;
   int audioPort;
   float fftVals[NUM_BARS+1];
   int mRandomNumbers[NUM_BARS];
   char fftChars[NUM_BARS+1];
   int numBars;

   float wand_local_pos[3];
   float wand_global_pos[3];

   Matrix44f nav_matrix;	   			
   Matrix44f wand_local_matrix;
   Matrix44f wand_global_matrix;

   int mode;

   float backgroundColor[3];
   float bgColorPrefs[17][3];

   int doAudioFrame;
   cluster::UserData< SharedData > mSharedData;
   
};


#endif

