/*
 * ===========================
 * VDK Component Library
 * Version 0.2
 * ===========================
 * Copyright (C) 1998, Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 * ===========================================
 * This library is a component of:
 * VDK Visual Development Kit
 * Version 0.4.1
 * Copyright (C) 1998, Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 * ===========================================
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-130
 */ 

#ifndef CHART_H
#define CHART_H
#include <vdk/vdk.h>
/*!
  \class Coord
  \brief provides a 2D object
 */
class Coord 
{ 
public:
double x,y; 
 Coord(double x = 0.0, double y = 0.0):x(x),y(y) {}
 ~Coord() {}
};

typedef VDKValueList<Coord> CoordList;
typedef VDKValueListIterator<Coord> CoordListIterator;
typedef VDKArray<double>    Darray;

class VDKChart;
////////////////////////////////
/*!
  \class Series
  \brief Is a list of 2D points with some propreties and behaviours added
 */
class Series: public CoordList
{
  Coord max,min;
  VDKString title;
 public:
  /*!
    Sets/gets color (defaults to black)
   */
  VDKReadWriteValueProp<Series,VDKRgb> Color;
  /*!
    Sets/gets line style (defaults to GDK_LINE_SOLID)
    can be:
    \arg GDK_LINE_SOLID
    \arg GDK_LINE_ON_OFF_DASH
    \arg GDK_LINE_DOUBLE_DASH
   */
  VDKReadWriteValueProp<Series,GdkLineStyle> LineStyle;
  /*!
    Sets/gets line width (defaults to 1)
   */
  VDKReadWriteValueProp<Series,int> LineWidth;
  /*!
    Sets/gets line cap style (defaults to GDK_CAP_NOT_LAST)
    can be:
    \arg GDK_CAP_NOT_LAST
    \arg GDK_CAP_BUTT
    \arg GDK_CAP_ROUND
    \arg GDK_CAP_PROJECTING
   */
  VDKReadWriteValueProp<Series,GdkCapStyle> LineCapStyle;
  /*!
    Sets/gets line join style (defaults to GDK_JOIN_MITER)
    can be:
    \arg GDK_JOIN_MITER
    \arg GDK_JOIN_ROUND
    \arg GDK_JOIN_BEVEL
   */
  VDKReadWriteValueProp<Series,GdkJoinStyle> LineJoinStyle;
  /*!
    Constructor
    \param title series title (should be unique)
   */
  Series(char* title): 
    CoordList(),
    title(title),
    Color("Color",this,VDKRgb(0,0,0)),
    LineStyle("LineStyle",this,GDK_LINE_SOLID),
    LineWidth("LineWidth",this,1),
    LineCapStyle("LineCapStyle",this,GDK_CAP_NOT_LAST),
    LineJoinStyle("LineJoinStyle",this,GDK_JOIN_MITER)
    {}
  /*!
    Destructor
   */
  ~Series() {}
  /*!
    Adds a 2D point to a series
    \param x x coordinate
    \param y y coordinate
   */
  void Add(double x, double y);
  /*!
    Adds an array of 2D points to series
    \param x array
    \param y array
    \param n array length
   */
  void Add(double* x, double* y, int n);
  /*!
    Returns minimum 2D point of a series
   */
  Coord Min() { return min; }
  /*!
    Returns maximum 2D point of a series
   */
  Coord Max() { return max; }
  /*!
    Returns series title
   */
  char* Title() { return (char*) title; }
  /*!
    Equality operator
   */
  bool operator==(Series& s) { return title == s.title; }
};

typedef VDKList<Series> SeriesList;
typedef VDKListiterator<Series> SeriesListIterator;

///////////////////////////////////
/*!
  \class ChartAxis
  \internal
*/
class ChartAxis
{
  VDKRect  domain;
  VDKChart* owner;
 public:
  ChartAxis():owner((VDKChart*) NULL) {}
  ChartAxis(VDKChart* owner,int w, int h);
  ChartAxis(ChartAxis& a);
  ~ChartAxis() {}
  void Draw();
  VDKRect& Domain() { return domain; }
};

enum 
{
  chart_class = 4096,
  linechart_class,
  scatteredchart_class,
  barchart_class
};

///////////////////////////////////
/*!
  \class VDKChart
  \brief Provides a char base class

  VDKChart is a component that allows to plot 2D data in various format,
  is a base class that implements common functionalities to all subclasses
  actually supported:
  \arg VDKLineChart
  \arg VDKScatteredChart
  \arg VDKBarChart
  \par Usage
  Use of VDKChart is straigthforward, user adds 2D points to a Series,
  eventually sets some series font and properties. VDKChart will assure
  data plotting and takes care of rescaling/resizing stuff.
  \par Subclassing VDKChart
  Normally user should override only Plot() in order to draw data in desired
  format.
  \par EXAMPLES
  Into ./testvdk/chart.cc
 */
class VDKChart: public VDKCanvas
{
  
 protected:
  GtkWidget *tip_window;
  VDKPoint size;
  double xn1,yn1,xn2,yn2,xv1,yv1,xv2,yv2,kx,ky;
  Coord domainmax,domainmin;
  SeriesList series;
  bool OnConfigure(VDKObject* sender, GdkEvent* event);
  bool OnClick(VDKObject* sender, GdkEvent* event);
  bool OnClickRelease(VDKObject* sender, GdkEvent* event);
  ChartAxis axis;
  void ComputeDomainLimits(Series* s);
  virtual void DrawChart();
  void DrawTitle();
  void DrawTicks();
  void DrawLabels();
 public:
  /*!
    Sets/gets char border, this area is left to draw axis, 
    title and labels. Defaults to 20 but a larger border is often better.
   */
  VDKReadWriteValueProp<VDKChart, int> ChartBorder;
  /*!
    Sets/gets chart title
   */
  VDKReadWriteValueProp<VDKChart, VDKString> Title;
  /*!
    Sets/gets x axis label
   */
  VDKReadWriteValueProp<VDKChart, VDKString> LabelX;
  /*!
    Sets/gets y axis label
   */
  VDKReadWriteValueProp<VDKChart, VDKString> LabelY;
  /*!
    Sets get how many decimal digits are displayed int x labels
   */
  VDKReadWriteValueProp<VDKChart, int> LabelXDigits;
  /*!
    Sets get how many decimal digits are displayed int y labels
   */
  VDKReadWriteValueProp<VDKChart, int> LabelYDigits;
  /*!
    Constructor
    \param owner
    \param w width
    \param h height
   */
  VDKChart(VDKForm* owner, int w = 100, int h = 100);
  /*!
    Destructor
   */
  virtual ~VDKChart();
  /*!
    Returns chart_class
   */
  virtual int isA() { return chart_class; }
  /*!
    Adds a series to chart
    \param s series to be added.
    Series name is checked for unicity, if a match is found
    <s> will substitute the old series that will be destroyed.
    So series to be added should be always constructed in the heap
    with new operator.
   */
  void AddSeries(Series* s);
  /*!
    Clears chart destroying all series
   */
  void Clear();
  void SetChartBorder(int b);
  int  GetChartBorder() { return ChartBorder; }
  /*!
    Returns chart gc
   */
  GdkGC* GC() { return gc; }
  /*!
    Sets drawing color, this affects plottin area only, to change
    axiz, titles and labels color use Foreground property
   */
  void SetColor(VDKRgb rgb);
  /*!
    Sets line attributes
   */
  void SetLineAttributes(gint lineWidth, 
			 GdkLineStyle lineStyle,
			 GdkCapStyle capStyle,
			 GdkJoinStyle joinStyle);
  /*!
    Plots data,placeholder for subclasses.
    \param p point to be plotted
    \param i i-th point of the series
    \param s series address
    \par Programming tips
    Items p contains coordinates ready to be plotted, scaled or resized
    to chart size and data domain.
  */
  virtual void Plot(VDKPoint& p , int i, Series* s) {}
  DECLARE_EVENT_LIST(VDKChart);
};
///////////////////////////////////////
/*!
  \class VDKLineChart
  \provides a line chart
 */
class VDKLineChart: public VDKChart
{
 public:
  VDKLineChart(VDKForm* owner, int w = 100, int h = 100):
    VDKChart(owner,w,h) {}
  virtual ~VDKLineChart() {}
  /*!
    Plots data
   */
  virtual void Plot(VDKPoint& p, int t, Series*);
  /*!
    Returns linechart_class
   */
  virtual int isA() { return linechart_class; }
};
///////////////////////////////////////
/*!
  \class VDKScatteredChart
  \provides a line chart
 */
class VDKScatteredChart: public VDKChart
{
 public:
  VDKScatteredChart(VDKForm* owner, int w = 100, int h = 100):
    VDKChart(owner,w,h) {}
  virtual ~VDKScatteredChart() {}
  virtual void Plot(VDKPoint& p, int t, Series*);
  virtual int isA() { return scatteredchart_class; }
};

///////////////////////////////////////
/*!
  \class VDKBarChart
  \brief Provides a bar chart

 */
class VDKBarChart: public VDKChart
{
 public:
  /*!
    Sets/gets bar width
   */
  VDKReadWriteValueProp<VDKBarChart,int> BarWidth;
  /*
    Sets/gets label flag
   */
  VDKReadWriteValueProp<VDKBarChart,bool> Labels;

  VDKBarChart(VDKForm* owner, int w = 100, int h = 100):
    VDKChart(owner,w,h),
    BarWidth("BarWidth",this,20),
    Labels("Labels",this,true)
    {}
  virtual ~VDKBarChart() {}
  /*!
    Plots data
   */
  virtual void Plot(VDKPoint& p, int t, Series*);
  /*!
    Returns barchart_class
   */
  virtual int isA() { return barchart_class; }
};

#endif


