#ifndef POINTSGRAPH_H
#define POINTSGRAPH_H

#include <deque>
#include <vector>
using namespace std;

#include <graphmisc.h>
#include <gobj.h>
#include <point.h>
#include <windowscaleD2.h>


/*!
\brief Graphics window, so can change viewing window
  without changing the data.
*/
class pointsgraph : public gobj
{
public:

  /** Construct in a bad state. */
  pointsgraph();

  /** Screen projects onto world. */
  pointsgraph
  (
    windowscaleD2 const & screen_,
    windowscaleD2 const & world_,
    boolc clipwindow_=false
  );

  /** Screen space. */
  deque< point2<double> > pts;

  /** Screen window, often changes for what is 
      being displayed. */
  windowscaleD2 screen;

  /** The fixed window. One-one with OpenGL 
      coordinate systmem. */
  windowscaleD2 world;

  /** Do not display points outside the screen. */
  bool clipwindow;
  /** Default draw checks conversions are inside world window. */
  static bool isinside;

  /** Draw the object. */
  void draw();

  /** Using the screen space sample N points 
      of a function. Endpoints included. */
  template< typename FN >
  void samplefunction(FN & fn, uintc N)
  {
    double dx = (double)1.0;
    dx /= ((double)N-(double)1.0);

    double x;
    double y;
    for (uint i=0; i<N; ++i)
    {
      x = dx*i;
      screen.unitscaleInverse_x(x);
      fn(y,x);
    
      pts.push_back( point2<double>(x,y) ); 
    }
  }

  /** Reset the x-axis domain and update. */
  void domain(doublec x0, doublec x1);

  /** Can change domain and need to rescale graph. */
  void screen_rescaley();

  /** Update the windows. */
  void update();

};

/*!
\brief Graph in time.
  X-axis [0,1].  Client adds y-values through 
  push_front/push_back.
*/ 
class pointsgraphtime : public pointsgraph
{
  /** N-1 divisions. */
  uint N;
  /** 1/(N-1) */
  double dx;
public:

  /** Create N subdivision including endpoints. */
  pointsgraphtime(uintc N_);

  /** Start adding to the front. */
  void push_front(double yval);
  /** Start adding to the back. */
  void push_back(double yval);

};



// TODO - implement axes.
/*
class pointsgraph_tick
{
public:

  // Default enabled, major spacing 1.0, length .05
  //  minor spacing .2, length .02 

  double hairlength;
  double period;
  bool enabled;
  double offset;

  pointsgraph_tick
  (
    doublec hairlength_,
    doublec period_,
    boolc enabled_,
    doublec offset_
  );

}; 

class pointsgraph_axes : public gobj
{
public:

  pointsgraph & pg;

  pointsgraph_axes(pointsgraph & pg_);

  pointsgraph_tick xaxis1;
  pointsgraph_tick xaxis2;
  pointsgraph_tick yaxis1;
  pointsgraph_tick yaxis2;

  void draw();

};
*/


/*!
\brief Circle point axes.
*/
class pointsgraph_axes_circle : public gobj
{
public:

  /** Container holding realized graphics. */
  gobjContainer* graphics;

  /** Can move the axes origin. */
  point3<double> origin;

  /** Assumes created with new, adds to graphics. */
  void push(gobj* g);

  pointsgraph_axes_circle();
  /** Cleanup deleting graphics. */
  ~pointsgraph_axes_circle();

  gobjQuadric quadric;
  /** X-axis color */
  gobjglColor3d xaxiscolor;
  /** Y-axis color */
  gobjglColor3d yaxiscolor;
  /** Points on x-axis. */ 
  vector<double> xaxis;
  /** Points on y-axis. */ 
  vector<double> yaxis;
  
  /** Uniform colored points? */
  bool disablelighting;

  /** Write graphics. */
  void update();
  /** Draw graphics. */
  void draw();

};


#endif


