#include <semaphore.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

#include "../DataInterface.h"
#include "../RobotViewData.h"
#include "../StreamProcessor.h"
#include "../WaveServer.h"


#include <FL/Fl.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include "ChokeChainCP.h"
#include "RLEViewer.h"

//====================================================================

extern sem_t GuiDataSemaphore;
extern DataInterface *DataControl;

//====================================================================

static void quit_callback(Fl_Widget*, void*) {
  exit(0);
}

//====================================================================

/*
 * Open a log file
 */
void ChokeChainCP::openLogMenuitemCB() {
  char * fn_ptr = fl_file_chooser("Choose log file",NULL,NULL);
  if (NULL!=fn_ptr) {
#if 0
    DataControl->setLog(fn_ptr);
#else
    DataControl->cacheLog(fn_ptr);
    log_slider->maximum(DataControl->logLength());
    log_slider->value(0);
    DataControl->gotoLogPosition(0);
#endif
    update();
  }
}

/*
 * Open a connection to a new robot
 */
void ChokeChainCP::openConnectionMenuitemCB() {
  cout << "ChokeChainCP::openConnectionMenuitemCB()" << endl;
  cout << "This is not implemented yet" << endl;
  // This should pop open a dialog box which returns a string
  // for the new hostname
}

/* 
 * This method will close all of the other fltk windows and will
 * hide itself.  This should shut down fltk.
 */
void ChokeChainCP::quitMenuitemCB() {
  // This is probably a bit of an overkill, but when we call a quit, we
  // _really_ want this thing to quit!
  exit(0);
}

//====================================================================

/*
 * Show/hide the ego view window
 */
void ChokeChainCP::egoViewMenuitemCB() {
  cout << "ChokeChainCP::egoViewMeniitemCB()" << endl;
  cout << "This is not implemented yet" << endl;
}

//====================================================================
// Show/hide the world view window
void ChokeChainCP::showGlobal() {
  global_view_win->show();
  global_view_menuitem->set();
}

void ChokeChainCP::hideGlobal() {
  global_view_win->hide();
  global_view_menuitem->clear();
}

void ChokeChainCP::globalViewMenuitemCB() {
  if (global_view_win->visible()){
    hideGlobal();
  } else {
    showGlobal();
  }
}

void ChokeChainCP::autoRunButtonCB() {
  if (1==auto_run_button->value()) {
    Fl::repeat_timeout(0,autorun,this);
    //Fl::add_idle(autorun,this);
  } else {
    Fl::remove_timeout(autorun,this);
    //Fl::remove_idle(autorun,this);
  }
}

//====================================================================
// Show/hide the RLE view window
void ChokeChainCP::showRLE() {
  RLE_win->show();
  vision_RLE_view_menuitem->set();
}

void ChokeChainCP::hideRLE() {
  RLE_win->hide();
  vision_RLE_view_menuitem->clear();
}

// Show/hide the RLE view window
void ChokeChainCP::visionRLEViewMenuitemCB() {
  if(RLE_win->visible()) { hideRLE(); } else { showRLE(); }
}

//====================================================================

void ChokeChainCP::logSliderCB() {
  DataControl->gotoLogPosition((int)log_slider->value());
  update();
}

//====================================================================

void ChokeChainCP::visionActiveButtonCB() {global_view_win->redraw();}
void ChokeChainCP::visionBallButtonCB() {global_view_win->redraw();}
void ChokeChainCP::visionMarkersButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelActiveButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelOldBallButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelTeammateBallButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelRobotsButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelTeammatesButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldModelTeammateRobotsButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerActiveButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerSelfBallButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerSelfBallEllipsesButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerTeammateBallButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerTeammateBallEllipsesButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerSelfBallHypothesesButtonCB() {global_view_win->redraw();}
void ChokeChainCP::worldTrackerTeammateBallHypothesesButtonCB() {global_view_win->redraw();}
void ChokeChainCP::wmDebugActiveButtonCB(){global_view_win->redraw();}
//====================================================================

ChokeChainCP::ChokeChainCP(int _gui_read_fd,
			   int _rle_width,
			   int _rle_height,
			   int log_position) : ChokeChainCP_fl() { 
  gui_read_fd = _gui_read_fd;
  rle_width = _rle_width;
  rle_height = _rle_height;

  choke_chain_win->callback(quit_callback);

  RLE_win = new RLEViewer(rle_width,rle_height);
  // Uncomment this to be able to resize the window
  RLE_win->size_range(rle_width,rle_height);
  RLE_win->end();

  global_view_win = new GlobalView(this,500,300);
  global_view_win->end();

  if (DataControl->activeLog()) {
    log_slider->maximum(DataControl->logLength());
    if (-1!=log_position) {
      log_slider->value(log_position);
      DataControl->gotoLogPosition((int)log_slider->value());
    }
  }
}

ChokeChainCP::~ChokeChainCP() {
}

void ChokeChainCP::show() {
  choke_chain_win->show();
  showRLE();
  showGlobal();
}

void ChokeChainCP::hide() {
  choke_chain_win->hide();
}

void ChokeChainCP::update() {
  /// Update the RLE image
  RLE_win->redraw();
  global_view_win->redraw();
}

void ChokeChainCP::run() {
  // Show the interfaces
  show();
  // This listens to the pipe and invokes the function when it gets called
  Fl::add_fd(gui_read_fd,FL_READ,fdCB,this);
  // Start the graphics event loop
  Fl::run();
}

//==========================================================================

void ChokeChainCP::fdCB(int fd, void *a) {
  ChokeChainCP * cp = (ChokeChainCP*)a;
  char buf[256];
  bool got_byte=false;
  while(read(fd,buf,256)>0) { got_byte=true; }
  if(got_byte) { 
    // If we're reading from a logfile, don't update the gui
    // We'll do that from within the GUI
    if (!DataControl->activeLog()) {
      cp->update(); 
    }
  }
}

//==========================================================================
// This function doesn't work quite as advertised.  It appears that if the 
// next callback occurs too quickly, this routine will run potentially
// multiple times before the data is actually displayed.
//
// Better synchronization is needed between this function and the graphics
// output

void ChokeChainCP::autorun(void *a) {
  ChokeChainCP * cp = (ChokeChainCP*)a;
  if (cp->log_slider->value() < DataControl->logLength()) {
    double time1,time2;

    time1 = (double)DataControl->getPacketTimestamp((int)cp->log_slider->value())/(double)1E6;
    cp->log_slider->value((int)cp->log_slider->value()+1);
    time2 = (double)DataControl->getPacketTimestamp((int)cp->log_slider->value())/(double)1E6;
    
    DataControl->gotoLogPosition((int)cp->log_slider->value());
    cp->update(); 

    if (1==cp->auto_run_button->value()) {
      Fl::repeat_timeout(time2-time1,autorun,cp);
    }
  } else {
    cp->auto_run_button->value(0);
  }
}

//============================================================================
bool ChokeChainCP::visionActive() {return (1==vision_active_button->value());}
bool ChokeChainCP::visionBall() {return (1==vision_ball_button->value());}
bool ChokeChainCP::visionMarkers() {return (1==vision_markers_button->value());}
bool ChokeChainCP::worldModelActive() {return (1==world_model_active_button->value());}
bool ChokeChainCP::worldModelOldBall() {return (1==world_model_old_ball_button->value());}
bool ChokeChainCP::worldModelTeammateBall() {return (1==world_model_teammate_ball_button->value());}
bool ChokeChainCP::worldModelRobots() {return (1==world_model_robots_button->value());}
bool ChokeChainCP::worldModelTeammates() {return (1==world_model_teammates_button->value());}
bool ChokeChainCP::worldModelTeammateRobots() {return (1==world_model_teammate_robots_button->value());}
bool ChokeChainCP::worldTrackerActive() {return (1==world_tracker_active_button->value());}
bool ChokeChainCP::worldTrackerSelfBall() {return (1==world_tracker_self_ball_button->value());}
bool ChokeChainCP::worldTrackerSelfBallEllipses() {return (1==world_tracker_self_ball_ellipses_button->value());}
bool ChokeChainCP::worldTrackerTeammateBall() {return (1==world_tracker_teammate_ball_button->value());}
bool ChokeChainCP::worldTrackerTeammateBallEllipses() {return (1==world_tracker_teammate_ball_ellipses_button->value());}
bool ChokeChainCP::worldTrackerSelfBallHypotheses() {return (1==world_tracker_self_ball_hypotheses_button->value());}
bool ChokeChainCP::worldTrackerTeammateBallHypotheses() {return (1==world_tracker_teammate_ball_hypotheses_button->value());}
bool ChokeChainCP::wmDebugActive() {return (1==wmdebug_active_button->value());}
