#ifndef WIDGETS_GRAPHPLOTTER_H
#define WIDGETS_GRAPHPLOTTER_H

#include <QtCore/QtGlobal>
#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsTextItem>
#include <QColor>

#include <tr1/memory>
#include <vector>
#include <utility>

#include <stdint.h>
#include <sys/types.h>

#include <boost/optional.hpp>

#include "Common.h"
#include "Vector2D.h"

#include "Spline.h"
#include "Interpolator.h"
#include "SplineInterpolator.h"
#include "LinearInterpolator.h"
#include "StepInterpolator.h"

#include "DataSet.h"
#include "PlotterItemGroup.h"

#include "BackgroundLayer.h"
#include "AxisLayer.h"
#include "CursorLayer.h"
#include "PlotLayer.h"
#include "CtlPointsLayer.h"

#include "Legend.h"
#include "GraphPlotterBaloon.h"
#include "GraphPlotterScene.h"


#define COSMETIC_PEN_FLAG	true

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

namespace TDE {

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

namespace Widgets {

/*!
 * \namespace TDE::Widgets::Plot
 * \brief Namespace for GraphPlotter widget
 *
 * All GraphPlotter related symbols are contained inside this namespace.
 */

namespace Plot {


class WIDGETS_EXPORT GraphPlotter : public QGraphicsView
{
	Q_OBJECT
    Q_PROPERTY(double hTics READ hTics WRITE hTics NOTIFY hTicsChanged)
    Q_PROPERTY(double hMinorTics READ hMinorTics WRITE hMinorTics NOTIFY hMinorTicsChanged)
    Q_PROPERTY(double vTics READ vTics WRITE vTics NOTIFY vTicsChanged)
    Q_PROPERTY(double vMinorTics READ vMinorTics WRITE vMinorTics NOTIFY vMinorTicsChanged)
    Q_PROPERTY(QColor bgColor READ bgColor WRITE bgColor NOTIFY bgColorChanged)
    Q_PROPERTY(bool   axisEnable READ axisEnable WRITE axisEnable NOTIFY axisEnableChanged)
    Q_PROPERTY(QColor axisColor READ axisColor WRITE axisColor NOTIFY axisColorChanged)
    Q_PROPERTY(QColor minorAxisColor READ minorAxisColor WRITE minorAxisColor NOTIFY minorAxisColorChanged)
    Q_PROPERTY(QColor marginColor READ marginColor WRITE marginColor NOTIFY marginColorChanged)
    Q_PROPERTY(QColor cursorColor READ cursorColor WRITE cursorColor NOTIFY cursorColorChanged)
    Q_PROPERTY(bool   cursorTracking READ cursorTracking WRITE cursorTracking NOTIFY cursorTrackingChanged)

public:
    GraphPlotter(QWidget* parent = 0);
    virtual ~GraphPlotter();

    virtual GraphPlotterScenePtr scene()					{ return m_scene; }

public slots:
	virtual void redraw();
	virtual void redraw_dataset(QString name, long updated_id);

	virtual void suspend_redraws()                    { m_suspend_redraws++; }
	virtual void resume_redraws(bool refresh = true);
	virtual bool redraws_suspended() const { return (m_suspend_redraws > 0); }
	virtual bool redraws_enabled() const   { return (m_suspend_redraws <= 0); }
	virtual void refresh();

	virtual DataSetPtr addDataSet(const std::string& name, const QColor& fg = QColor(), DataSet::Kind kind = DataSet::DATA, const InterpolatorParameters& params = InterpolatorParameters());
	virtual DataSetPtr addDataSet(const std::string& name, DataSet::Kind kind);
	virtual GraphPlotter& addDataSet(DataSetPtr dataSetPtr);
	virtual std::vector<DataSetPtr>& datasets() { return m_dataSets; }
	virtual DataSetPtr findDataSet(const std::string& name);

	virtual void removeDataSet(DataSetPtr dataSetPtr);
	virtual void removeDataSet(const std::string& name);
	virtual void removeAllDataSets();

	virtual bool 	   hasReferenceDataSet() const 					{ return m_ref_dataset.get(); }
	virtual DataSetPtr referenceDataSet() const 					{ return m_ref_dataset; }
	virtual void       referenceDataSet(DataSetPtr dataSetPtr);
	virtual void       referenceDataSet(const std::string& name);

	virtual bool 	   hasCursorTrackingDataSet() const 			{ return m_cursor_tracking_dataset.get(); }
	virtual DataSetPtr cursorTrackingDataSet() const 				{ return m_cursor_tracking_dataset; }
	virtual void       cursorTrackingDataSet(DataSetPtr dataSetPtr);
	virtual void       cursorTrackingDataSet(const std::string& name);

	virtual const std::vector<PlotLayerPtr>& plotLayers() const { return m_plotLayers; }
	virtual std::vector<PlotLayerPtr> plotLayers()              { return m_plotLayers; }
	virtual PlotLayerPtr findPlotLayer(DataSetPtr datasetPtr);
	virtual PlotLayerPtr findPlotLayer(const std::string& dataSetName);

	virtual CtlPointsLayerPtr findCtlPointsLayer(DataSetPtr datasetPtr);
	virtual CtlPointsLayerPtr findCtlPointsLayer(const std::string& dataSetName);

	virtual QSize internalSize() const;
	virtual QSizeF internalSizeF() const;

	virtual bool   plotSurfaceSet() const							{ return m_plot_surface_set; }
	virtual QRectF plotSurface() const;
	virtual QRectF plotSurface(const QRectF& value);
	virtual QSizeF plotSurfaceSize() const;
	virtual QSize  plotSurfaceSizeI() const;

	virtual Range2D window() const;

	virtual double hTics() const									{ return m_h_tics; }
	virtual double hTics(double value, bool redraw = true);
	virtual double hMinorTics() const								{ return m_h_minor_tics; }
	virtual double hMinorTics(double value, bool redraw = true);
	virtual double vTics() const									{ return m_v_tics; }
	virtual double vTics(double value, bool redraw = true);
	virtual double vMinorTics() const								{ return m_v_minor_tics; }
	virtual double vMinorTics(double value, bool redraw = true);

	virtual QColor	bgColor() const							{ return m_bg_color; }
	virtual QColor	bgColor(const QColor& value, bool redraw = true);
	virtual bool	axisEnable() const						{ return m_axis_enable; }
	virtual bool	axisEnable(bool value, bool redraw = true);
	virtual QColor	axisColor() const						{ return m_axis_color; }
	virtual QColor	axisColor(const QColor& value, bool redraw = true);
	virtual QColor	minorAxisColor() const					{ return m_minor_axis_color; }
	virtual QColor	minorAxisColor(const QColor& value, bool redraw = true);
	virtual QColor	marginColor() const						{ return m_margin_color; }
	virtual QColor	marginColor(const QColor& value, bool redraw = true);
	virtual QColor	cursorColor() const						{ return m_cursor_color; }
	virtual QColor	cursorColor(const QColor& value, bool redraw = true);
	virtual bool    cursorTracking() const                  { return m_cursor_tracking; }
	virtual bool    cursorTracking(bool value, bool redraw = true);

	virtual CursorLayerPtr cursorLayer() 					{ return m_cursorLayer; }

signals:

	void referenceDataSetChanged(QString);		// reference dataset changed
    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 hTicsChanged(double);
    void hMinorTicsChanged(double);
    void vTicsChanged(double);
    void vMinorTicsChanged(double);
    void bgColorChanged(QColor);
    void axisEnableChanged(bool);
    void axisColorChanged(QColor);
    void minorAxisColorChanged(QColor);
    void marginColorChanged(QColor);
    void cursorColorChanged(QColor);
    void cursorTrackingChanged(bool);

protected:
	virtual void buildScene(bool recreate = false);
	virtual void drawScene(bool invalidate = false);
	virtual void drawBg(bool invalidate = false);
	virtual void drawAxis(bool invalidate = false);
	virtual void drawCursor(bool invalidate = false);
	virtual void drawPlots(bool invalidate = false);
	virtual void resizeEvent(QResizeEvent* event);
	virtual void mousePressEvent(QMouseEvent* event);
	virtual void mouseReleaseEvent(QMouseEvent* event);
	virtual void mouseMoveEvent(QMouseEvent* event);
	virtual void trackCursor(const QPoint& mousePos);

public:
	static const QColor DEFAULT_BG_COLOR;
	static const QColor DEFAULT_AXIS_COLOR;
	static const QColor DEFAULT_MINOR_AXIS_COLOR;
	static const QColor DEFAULT_MARGIN_COLOR;
	static const QColor DEFAULT_CURSOR_COLOR;
	static const bool   DEFAULT_CURSOR_TRACKING;

	static const double DEFAULT_MAJOR_H_TICS;
	static const double DEFAULT_MINOR_H_TICS;
	static const double DEFAULT_MAJOR_V_TICS;
	static const double DEFAULT_MINOR_V_TICS;

private:
	struct DataSetInfo
	{
		QMetaObject::Connection connection;
	};

	GraphPlotterScenePtr m_scene;

	BackgroundLayerPtr m_bgLayer;
	AxisLayerPtr m_axisLayer;
	CursorLayerPtr m_cursorLayer;
	std::vector<PlotLayerPtr> m_plotLayers;
	std::vector<CtlPointsLayerPtr> m_ctlPointsLayers;
	int m_nextPlotLayerIdx;

	std::vector<DataSetPtr> m_dataSets;
	DataSetPtr m_ref_dataset;
	std::map<DataSetPtr, DataSetInfo> m_dataSetInfo;

	int m_suspend_redraws;

	bool m_auto_scale_x;
	bool m_auto_scale_y;
	Range2D m_viewport;
	Range2D m_range;

	double m_h_tics;
	double m_h_minor_tics;
	double m_v_tics;
	double m_v_minor_tics;

	QColor m_bg_color;
	bool   m_axis_enable;
	QColor m_axis_color;
	QColor m_minor_axis_color;
	QColor m_margin_color;
	QColor m_cursor_color;
	bool   m_cursor_tracking;
	DataSetPtr m_cursor_tracking_dataset;

	QGraphicsItem* m_dragging;
	DataSetPtr m_dragging_for_dataset;
	QPointF m_dragging_initial;
	QPointF m_dragging_current;
	bool m_zooming;
	QPointF m_zoom_start, m_zoom_end;
	bool m_mouse_move_cursor;

	bool   m_plot_surface_set;
	QRectF m_plot_surface;

	GraphPlotterBaloon* m_pos_baloon;
};


} /* end of namespace Plot */

} /* end of namespace Widgets */

} /* end of namespace TDE */

#endif /* WIDGETS_GRAPHPLOTTER_H */
