#ifndef WIDGETS_GRAPHPLOTTER_DATASET_H
#define WIDGETS_GRAPHPLOTTER_DATASET_H

#include "Interpolator.h"


// -- TDE NAMESPACE ----------------------------------------------------

namespace TDE {

// -- Widgets NAMESPACE ------------------------------------------------

namespace Widgets {

namespace Plot {


class DataSet;

typedef SHARED_PTR<DataSet> DataSetPtr;

typedef std::vector<DataSetPtr> DataSetPtrVector;
typedef std::vector<DataSetPtr>::const_iterator DataSetPtrConstIterator;
typedef std::vector<DataSetPtr>::iterator DataSetPtrIterator;

class DataSet : public QObject
{
	Q_OBJECT
    Q_PROPERTY(Mode mode READ mode WRITE mode NOTIFY modeChanged)

public:
	enum Mode
	{
		PLOT,
		DESIGN
	};
	Q_ENUMS( Mode );

public:
	enum Kind
	{
		DATA,
		SPLINE,
		LINEAR,
		S_RAMP,
		CUBIC_BEZIER,
		BEZIER,
		STEP
	};

	DataSet(const std::string& name, const QColor& fg = Qt::lightGray, Kind kind = DATA, const InterpolatorParameters& params = InterpolatorParameters()) :
		m_name(name), m_kind(kind), m_fg_color(fg),	m_auto_scale_x(true), m_auto_scale_y(true), m_margin(0.0), m_mode(PLOT), m_params(params), m_axis_label(true),
		m_update_enable(true), m_update_cnt(0), m_update_id(0), m_pen_width(2) {}
	virtual ~DataSet() {}

	std::string name() const                       { return m_name; }
	std::string name(const std::string name_, bool do_emit = true);

	Kind kind() const { return m_kind; }

	QColor fgColor() const { return m_fg_color; }
	QColor fgColor(const QColor& value, bool do_emit = true);

	const std::vector<Point>& points() const        { return m_points; }
	std::vector<Point>& points() 			        { return m_points; }
	const Range2D extent() const                    { return (margin() != 0.0) ? m_range.Margin(m_margin / 100.0) : m_range; }
	virtual Range2D viewPort() const;
	virtual Range2D viewPort(const Range2D& viewport, bool do_emit = true);
	virtual Range   viewPortX() const 				{ return viewPort().x(); }
	virtual Range2D viewPortX(const Range& rangeX, bool do_emit = true);
	virtual Range   viewPortY() const 				{ return viewPort().y(); }
	virtual Range2D viewPortY(const Range& rangeY, bool do_emit = true);

	virtual QRectF  viewPortQt() const;
	virtual void    viewPortQt(const QRectF& r, bool do_emit = true);

	virtual bool axisLabel() const;
	virtual bool axisLabel(bool enable, bool do_emit = true);
	virtual bool autoScale() const;
	virtual bool autoScale(bool enable, bool do_emit = true);
	virtual bool autoScaleX() const;
	virtual bool autoScaleX(bool enable, bool do_emit = true);
	virtual bool autoScaleY() const;
	virtual bool autoScaleY(bool enable, bool do_emit = true);
	virtual double margin() const;
	virtual double margin(double value, bool do_emit = true);

	bool empty() const                             { return m_points.empty() || extent().empty(); }
	virtual std::string repr() const;

	virtual std::vector<Point>::const_iterator findNearest(double x) const;
	virtual std::vector<Point>::const_iterator findNearest(const Point& point) const;

	virtual InterpolatorPtr getInterpolator() const;

	virtual bool loadCSV(const std::string& pathname, bool headerLine = true, bool do_emit = true);
	virtual bool saveCSV(const std::string& pathname, bool headerLine = true, bool inViewport = false, bool interpolated = false, int nPoints = -1, double width = -1);

	friend std::ostream& operator<< (std::ostream& out, DataSet const &value);

	virtual int penWidth() const { return m_pen_width; }
	virtual int penWidth(int width, bool do_emit = true);	

public slots:
	virtual DataSet& addPoint(const Point& point, bool do_emit = true);
	virtual DataSet& addPoint(double x, double y, bool do_emit = true);

	virtual DataSet& clear(bool do_emit = true);
	virtual DataSet& setData(const std::vector<Point>& points, bool do_emit = true);
	virtual DataSet& setData(const std::vector<double>& x, std::vector<double>& y, bool do_emit = true);
	virtual DataSet& setData(const std::vector<double>& y, bool do_emit = true);

	virtual Mode mode() const										{ return m_mode; }
	virtual Mode mode(Mode value, bool do_emit = true);

	virtual bool updateEnable() const					{ return m_update_enable; }
	virtual bool updateEnable(bool value);
	virtual bool updateSuspend()						{ return updateEnable(false); }
	virtual bool updateResume()							{ return updateEnable(true); }
	virtual long updatedId() const						{ return m_update_id; }

	virtual void emit_updated();

signals:
	void updated(QString name, long update_id);
    void rangeChanged(QRectF);
    void axisLabelChanged(bool);                // axis label option changed
    void autoScaleChanged(bool);                // autoscale option changed
    void autoScaleXChanged(bool);               // autoscale X option changed
    void autoScaleYChanged(bool);               // autoscale X option changed
    void marginChanged(double);                 // margin option changed
    void modeChanged(Mode);

protected:
	void _emit_updated();

	std::string m_name;
	Kind m_kind;
	QColor m_fg_color;
	std::vector<Point> m_points;

	bool m_auto_scale_x;
	bool m_auto_scale_y;
	Range2D m_viewport;
	Range2D m_range;
	double m_margin;
	Mode m_mode;
	InterpolatorParameters m_params;

	bool m_update_enable;
	long m_update_cnt;
	long m_update_id;

	bool m_axis_label;
	int m_pen_width;

private:
};

std::ostream& operator<< (std::ostream& out, DataSet const &value);


} /* end of namespace Plot */

} /* end of namespace Widgets */

} /* end of namespace TDE */

#endif /* WIDGETS_GRAPHPLOTTER_DATASET_H */
