// Plots successive diagrams of the manipulator to a PostScript file, showing
// the motion of the arm over time.
//
// Modification history
// --------------------
//
// 02/04/03: Weyn Ong: C++ version for Linux.
// 04/01/98: K.C. Change: created.

#ifndef PRPLOTTER_H
#define PRPLOTTER_H

#include <stdio.h>
#include <pthread.h>
#include "PrGlobalDefn.h"

class TextUI;

/** \ingroup utility
* \brief Plots successive diagrams of the manipulator to a PostScript file,
* showing the motion of the arm over time.
*
* This class creates a single-page PostScript file.  During construction, a
* reference to the TextUI object using this class is passed in.  Setting this
* object's state to START will then kicks off an internal thread that polls
* the TextUI object for the current joint angles of the manipulator at regular
* intervals (specified by TimeBetweenFrames).  The Postscript file is written
* when the state is set to STOP.
*/

class PrPlotter {
public:
  /// Defines the active/inactive state of this class.
  enum PlotterState { START, STOP };

  /**
  * \brief Constructs this object with a reference to the TextUI object.
  *
  * Before setting this object's state to START, the filename and time
  * between frames must be set using the Filename() and TimeBetweenFrames()
  * functions.
  *
  * \param textUI A reference to the parent TextUI object where the
  * manipulator joint angles will be gathered from.
  */

  PrPlotter( TextUI * textUI );

  /**
  * \brief Sets the .ps filename to write to.
  *
  * \param filename Name of the Postscript file to write to.
  */

  void Filename( char * filename );

  /**
  * \brief Specifies the time interval between successive frames.
  *
  * \param milliseconds Time interval at which the internal thread will
  * collect joint angles.
  */

  void TimeBetweenFrames( int milliseconds );

  /**
  * \brief Controls gathering.
  *
  * \param state Kicks off the gathering thread if START, stops gathering
  * and writes the collected images to the Postscript file if STOP.
  */

  void State( PlotterState state );
  PlotterState GetState() { return stopSignalled ? STOP : START; }

private:
  friend void * plotterThread( void * );

  void InitRobot( void );
  void InitPlotter( void );
  void NewFrame( void );
  void PlotLine( Float v1[2], Float v2[2] );
  void PlotString( double xloc, double yloc, int justx, int justy, char * s );
  void PlotCircle( Float pt[2], Float r );
  void PlotPoly( Float f[2][3], int n, Float p[1][2] );
  void rotvec( Float b[2], Float r[2][3], Float a[2] );
  void SetFrame( Float f[2][3], Float, Float, Float, Float, Float, Float );
  void UpdateFrames( Float rq[3] );
  void PlotFooter( void );
  void PlotHeader( void );
  void PlotRobot( Float q[3] );
  void PlotWorld( Float q[3] );

  FILE * psfile;
  TextUI * textUI;
  pthread_t plotterThreadID;
  bool stopSignalled;
  static const int NUMFRAMES = 4;
  Float frame[NUMFRAMES][2][3];
  int frameCount;
  bool init;
  int millisecsBetweenFrames;
};

#endif
