/**@file shape.h: Prototypes of some graphical shapes. */
#ifndef __SHAPE_H__
#define __SHAPE_H__

#include <deque>

#include "points.h"
#include "images/csext.h"


/** Basic transformation class for linear 1D transformation. */
class Transform1D
{
public:
  double Start;			///< begin in logical coordinates
  double End;			///< end in logical coordinates
  double CanvasStart;		///< begin in physical coordinates
  double CanvasEnd;		///< end in physical coordinates

  Transform1D(void)  {}
  Transform1D(const Transform1D & CopyT): Start(CopyT.Start), End(CopyT.End), CanvasStart(CopyT.CanvasStart), CanvasEnd(CopyT.CanvasEnd) {}

  double Log2Canvas(double X) const  ///< Convert logical to physical coordinates
    {
    if(End==Start) return CanvasStart; 
    return CanvasStart + (CanvasEnd-CanvasStart)*(X-Start)/(End-Start);
    };

  double Canvas2Log(double CanX) const ///< Convert physical to logical coordinates
    {
    if(CanvasEnd==CanvasStart) return Start;
    return Start + (End-Start)*(CanX-CanvasStart)/(CanvasEnd-CanvasStart);
    };
};


/** Transform object transforms physical coordinates to a canvas for charts. */
class Transform2D
{
public:
  Transform1D X;
  Transform1D Y;  

  Transform2D(void)  {}
  Transform2D(const Transform2D & CopyT): X(CopyT.X), Y(CopyT.Y) {}
};


/** Predecesor of all shapes that implements Paint function. */
class BaseShape
{
public:
  BaseShape(void): Visible(true) {};

  bool Visible;
  virtual void Paint(wxDC &)  {};  ///< Repaint contents. All childs should implement this function.
};


/** Predecessor for both vertical & horizontal axes. */
class Axis: public BaseShape
{
public:
  Transform2D *Tx;
  double  Start;
  double  End;
  double  Depth;

  wxPen LinePen;		///< The appearance of the axes line.  
};


/** Horizontal axis object. */
class XAxis: public Axis
{
public:
  virtual void Paint(wxDC &); 
};


/** Vertical axis object. */
class YAxis: public Axis
{
public:
  virtual void Paint(wxDC &); 
};


/** Predecessor for both vertical & horizontal grids. */
class Grid: public BaseShape
{
public:
  Grid(void): Tx(NULL), Start(0), End(0) {};

  Transform2D *Tx;

  int Ticks;
  wxPen LinePen;
  double Start;
  double End;
};


/** Horizontal grid. */
class HGrid: public Grid
{
public:
  virtual void Paint(wxDC &);
};


/** Vertical grid. */
class VGrid: public Grid
{
public:
  virtual void Paint(wxDC &);
};


/** Predecessor for both vertical & horizontal cursor lines. */
class Cursor: public BaseShape
{
public:
  Transform2D *Tx;	  ///< Transformation physical to charting coordinates
  wxPen LinePen;
  double Position;
};


/** Vertical cursor line. */
class VCursor: public Cursor
{
public:
  virtual void Paint(wxDC & dc);  
};


/** Virtual predecessor fot both vertical and horizontal axis labels. */
class Labels: public BaseShape
{
public:  
  int ticks;
  wxColour TextColor;
  wxFont LabelFont;		///< Font for label.
};


/** Horizontal axis labels. */
class XLabels: public Labels
{
public:
  XAxis *Ax;
  virtual void Paint(wxDC & dc);        
};


/** Vertical axis labels. */
class YLabels: public Labels
{
public:
  YAxis *Ay;  
  virtual void Paint(wxDC & dc);        
};


/** Storage for history of data. It could be used for painting charts. */
class DataBuffer
{
protected:
  std::deque<double> data;

public:
  double GetValue(int Position);
  int GetSize(void)  {return data.size();};
  void DeleteItem(int Position=-1); 
  void Clear(void); 
  void AppendItem(double NewVal, int Position=-1);

  friend class Serie;
};


/** Thread safe circular buffer of doubles. */
class CircularBuffer: private CriticalSectionExt
{
private:
  double *array;
  unsigned Size;
  unsigned First;
  unsigned Last;

public:
  CircularBuffer(unsigned IniSize);
  ~CircularBuffer();

  double Pop(void);
  void Push(double Value);
  unsigned Elements(void);
  void Clear(void);
};


/** Paintable chart line. */
class Serie: public BaseShape
{
public:
  DataBuffer *XValues;		///< X coordinates for line.
  DataBuffer *YValues;		///< Y coordinates for line.

  wxPen LinePen;		///< Pen of line.
  Transform2D *Tx;		///< Transformation physical to charting coordinates.

  virtual void Paint(wxDC & dc);
};


/** "Shape class"
*  This class basicly holds the current and old positions of the circle and also its type. */
class CircRTShape: public BaseShape
{
public:
    Point *xPos;	  ///< X position of painted object from real time
    Point *yPos;          ///< Y position of painted object from real time 
    double Radius;	  ///< Radius of painted object in logical coordinates.

    Transform2D *Tx;	  ///< Transformation physical to charting coordinates

    int      style;
    wxColour color;	  ///< Color of painted object.
    bool     PaintCross;  ///< Paint cross inside circle.

    /** Create an instance with the type parameter.    
    *  @param[in] xHook - x coordinate real time wrapper
    *  @param[in] yHook - y coordinate real time wrapper */
    CircRTShape(Point *xHook, Point *yHook): xPos(xHook), yPos(yHook), PaintCross(false) {};
       
    ~CircRTShape() {};

    virtual void Paint(wxDC & dc);        
};

const char *GetFormatStr(double Distance);

#endif  // __SHAPE_H__