/*
 * Copyright (c) 2020 Mark Liversedge (liversedge@gmail.com)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _GC_UserChart_h
#define _GC_UserChart_h 1

#include "GoldenCheetah.h"
#include "Settings.h"
#include "Context.h"
#include "Athlete.h"
#include "Colors.h"
#include "RCanvas.h"

#include "GenericSelectTool.h"
#include "GenericLegend.h"
#include "GenericChart.h"
#include "GenericPlot.h"
#include "ColorButton.h"
#include "DataFilter.h"

// the chart
class ChartSpace;
class UserChartSettings;
class UserChartOverviewItem;
class UserChartWindow;
class DataFilterEdit;
class UserChart : public QWidget {

    Q_OBJECT

    Q_PROPERTY (Perspective* perspective READ getPerspective WRITE setPerspective USER false)

    friend class ::Leaf; // data filter eval accessing our curve data
    friend class ::UserChartOverviewItem; // get chartinfo.bgcolor
    friend class ::UserChartWindow; // get chartinfo.bgcolor

    public:

        UserChart(QWidget *parent, Context *context, bool rangemode, QString bg="");

        // config widget, for user to configure the chart
        UserChartSettings *settingsTool() { return settingsTool_; }

        // for read and write of settings via chart properties
        QString settings() const;
        void applySettings(QString);

        Perspective *getPerspective() const { return perspective_; }
        void setPerspective(Perspective *x) { perspective_ = x; }

        // set background for all charts, legends etc
        void setBackgroundColor(QColor bgcolor);
        void setGraphicsItem(QGraphicsItem *);

        // groupBy day, week, month etc where x is dates and y is values
        void groupBy(int groupby, int aggregateby, QVector<double> &xseries, QVector<double> &yseries, bool fillzero);
        long groupForDate(int groupby, QDate date);
        QDate dateForGroup(int groupby, long);

    signals:
        void userChartConfigChanged();

    public slots:

        // runtime - ride item changed
        void setRide(const RideItem*);

        // runtime - date range was selected
        void setDateRange(DateRange);

        // intervals changed, maybe we refresh
        void intervalRefresh();

        // redraw
        void refresh();

        // global config changed?
        void configChanged(qint32);

        // chart config changed?
        void chartConfigChanged();

        // catch annotations from program
        void annotate(GenericAnnotationInfo&);

    protected:

        // the actual config
        GenericChartInfo chartinfo;
        QList<GenericSeriesInfo> seriesinfo; // also contain annotations.
        QList<GenericAxisInfo> axisinfo;

        // annotations generated by the program (not the user)
        QList<QStringList> annotations;

    private:

        Perspective *perspective_;
        Context *context;
        bool rangemode;
        bool stale;

        const RideItem *last; // the last ride we plotted
        const RideItem *ride;
        DateRange dr;
        int intervals; // remember how many intervals were selected when we last refreshed

        GenericChart *chart;
        QGraphicsItem *item;
        UserChartSettings *settingsTool_;
};

class UserChartSettings : public QWidget {

    Q_OBJECT

    public:
        UserChartSettings(Context *, bool rangemode, GenericChartInfo &, QList<GenericSeriesInfo> &, QList<GenericAxisInfo> &);

        // we want some additional config?
        void insertLayout(QLayout *);

    private:
        Context *context;
        bool rangemode;

        // settings maintained here
        GenericChartInfo &chartinfo;
        QList<GenericSeriesInfo> &seriesinfo;
        QList<GenericAxisInfo> &axisinfo;

        // layout widget, can have other stuff inserted...
        QVBoxLayout *layout;

        // tabs
        QTabWidget *tabs;
        QWidget *chartpage;

        // series tab
        QTableWidget *seriesTable;

        // axes tab
        QTableWidget *axisTable;

    public slots:

        // configuration - chart
        void refreshChartInfo(); // update gui with loaded config
        void updateChartInfo();

        // configuration - data series
        void refreshSeriesTab(); // update gui with current config
        void editSeries();
        void seriesClicked(int,int);
        void addSeries();
        void deleteSeries();
        void moveSeriesUp();
        void moveSeriesDown();

        // configuration - axes
        void refreshAxesTab(); // update gui with current config
        void editAxis();
        void axisClicked(int,int);
        void addAxis();
        void deleteAxis();

    signals:

        void chartConfigChanged();

    private:

        bool updating;

        // chart page
        QLineEdit *title;
        QTextEdit *description;
        QCheckBox *animate;
        QComboBox *type;
        QComboBox *legpos;
        QCheckBox *stack;
        QComboBox *orientation;
        QSlider *scale;
        ColorButton *bgcolor;
        QCheckBox *intervalrefresh;

        bool blocked;
};

class EditUserSeriesDialog : public QDialog
{
    Q_OBJECT

    public:
        EditUserSeriesDialog(Context *, bool rangemode, GenericSeriesInfo &);

    public slots:
        void okClicked();
        void cancelClicked();

        void setErrors(QStringList &errors);

    private:
        Context *context;
        GenericSeriesInfo &original;

        // series page
        QLineEdit *name, *xname, *yname, *groupname;
        DataFilterEdit *program;
        QLabel *errors;

        QComboBox *aggregate;
        QComboBox *line, *symbol;
        QDoubleSpinBox *size;
        ColorButton *color;
        QSpinBox *opacity;
        QCheckBox *fill, *opengl, *legend, *datalabels;
        QLineEdit *labels, *colors;

        QPushButton *okButton, *cancelButton;

};

class EditUserAxisDialog : public QDialog
{
    Q_OBJECT

    public:
        EditUserAxisDialog(Context *,GenericAxisInfo &);

    public slots:

        void setWidgets();

        void okClicked();
        void cancelClicked();

    private:
        Context *context;
        GenericAxisInfo &original;

        // axes page
        QLineEdit *axisname;
        QComboBox *axistype;
        QCheckBox *log;
        QCheckBox *fixed;
        QDoubleSpinBox *min, *max;
        ColorButton *axiscolor;
        QLineEdit *categories;
        QComboBox *groupby;
        QSlider *smooth;
        QLabel *smoothlabel, *groupbylabel;

        QPushButton *okButton, *cancelButton;
};
#endif
