// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | bytran@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// The MIT License (MIT)
// Copyright (c) 2016 Dzianis Pliutau
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



// Plot to display graphs and transmission spectra
#ifndef PLOT_H
#define PLOT_H

#include <QtQuick/QQuickPaintedItem>
#include <QGestureEvent>
#include <filedownloader.h>
#include <QVector>
#include <QRectF>
#include <QImage>
#include <QPixmap>
#include "spectrum.h"

class Plot : public QQuickPaintedItem
{    
    Q_OBJECT

    Q_PROPERTY(QString saveImage READ saveImage WRITE setSaveImage NOTIFY saveImageChanged)
    Q_PROPERTY(QString topString READ topString WRITE setTopString NOTIFY topStringChanged)
    Q_PROPERTY(Spectrum spectrum READ spectrum WRITE setSpectrum NOTIFY spectrumChanged)
    Q_PROPERTY(QVector<double> wnGrid READ wnGrid WRITE setWnGrid NOTIFY wnGridChanged)
    Q_PROPERTY(double minX READ minX WRITE setMinX NOTIFY minXChanged)
    Q_PROPERTY(double maxX READ maxX WRITE setMaxX NOTIFY maxXChanged)
    Q_PROPERTY(double minY READ minY WRITE setMinY NOTIFY minYChanged)
    Q_PROPERTY(double maxY READ maxY WRITE setMaxY NOTIFY maxYChanged)
    Q_PROPERTY(double xMinPadding READ xMinPadding WRITE setXMinPadding NOTIFY xMinPaddingChanged)
    Q_PROPERTY(double xMaxPadding READ xMaxPadding WRITE setXMaxPadding NOTIFY xMaxPaddingChanged)
    Q_PROPERTY(double yMinPadding READ yMinPadding WRITE setYMinPadding NOTIFY yMinPaddingChanged)
    Q_PROPERTY(double yMaxPadding READ yMaxPadding WRITE setYMaxPadding NOTIFY yMaxPaddingChanged)
    Q_PROPERTY(QString xAxisTitle READ xAxisTitle WRITE setXAxisTitle NOTIFY xAxisTitleChanged)
    Q_PROPERTY(QString yAxisTitle READ yAxisTitle WRITE setYAxisTitle NOTIFY yAxisTitleChanged)
    Q_PROPERTY(QString plotTitle READ plotTitle WRITE setPlotTitle NOTIFY plotTitleChanged)
    Q_PROPERTY(QString lineColor READ lineColor WRITE setLineColor NOTIFY lineColorChanged)
    Q_PROPERTY(int lineThickness READ lineThickness WRITE setLineThickness NOTIFY lineThicknessChanged)
    Q_PROPERTY(int numMinorXTicks READ numMinorXTicks WRITE setNumMinorXTicks NOTIFY numMinorXTicksChanged)
    Q_PROPERTY(int numMajorXTicks READ numMajorXTicks WRITE setNumMajorXTicks NOTIFY numMajorXTicksChanged)
    Q_PROPERTY(int numMinorYTicks READ numMinorYTicks WRITE setNumMinorYTicks NOTIFY numMinorYTicksChanged)
    Q_PROPERTY(int numMajorYTicks READ numMajorYTicks WRITE setNumMajorYTicks NOTIFY numMajorYTicksChanged)
    Q_PROPERTY(bool plotInverted READ plotInverted WRITE setPlotInverted NOTIFY plotInvertedChanged)
    Q_PROPERTY(int currSpecIndex READ currSpecIndex WRITE setCurrSpecIndex NOTIFY currSpecIndexChanged)
    Q_PROPERTY(bool fileWritingComplete READ fileWritingComplete WRITE setFileWritingComplete NOTIFY fileWritingCompleteChanged)
    Q_PROPERTY(qreal touchCenterX READ touchCenterX WRITE setTouchCenterX NOTIFY touchCenterXChanged)
    Q_PROPERTY(qreal touchCenterY READ touchCenterY WRITE setTouchCenterY NOTIFY touchCenterYChanged)
    Q_PROPERTY(qreal touchStartX READ touchStartX WRITE setTouchStartX NOTIFY touchStartXChanged)
    Q_PROPERTY(qreal touchStartY READ touchStartY WRITE setTouchStartY NOTIFY touchStartYChanged)
    Q_PROPERTY(qreal touchEndX READ touchEndX WRITE setTouchEndX NOTIFY touchEndXChanged)
    Q_PROPERTY(qreal touchEndY READ touchEndY WRITE setTouchEndY NOTIFY touchEndYChanged)
    Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
    Q_PROPERTY(bool isHorizontalPinch READ isHorizontalPinch WRITE setIsHorizontalPinch NOTIFY isHorizontalPinchChanged)
    Q_PROPERTY(qreal fontPointSize READ fontPointSize WRITE setFontPointSize NOTIFY fontPointSizeChanged)
    Q_PROPERTY(int xHeight READ xHeight)
    Q_PROPERTY(bool enableRulers READ enableRulers WRITE setEnableRulers NOTIFY enableRulersChanged)
    Q_PROPERTY(bool plotInProgress READ plotInProgress NOTIFY plotInProgressChanged)

    public:

        // Invokable method used to update plot
        Q_INVOKABLE void updatePlot();
        Q_INVOKABLE void addTopString();

        Plot(QQuickItem *parent = nullptr);
        void paint(QPainter *painter);

        Spectrum spectrum() const;
        void setSpectrum(const Spectrum &spectrum);

        QVector<double> wnGrid() const;
        void setWnGrid(const QVector<double> &wnGrid);

        // Physical plot boundaries
        double minX() const;
        void setMinX(const double &minX);
        double maxX() const;
        void setMaxX(const double &maxX);
        double minY() const;
        void setMinY(const double &minY);
        double maxY() const;
        void setMaxY(const double &maxY);

        // Pinch gesture variables
        qreal touchCenterX() const;
        void setTouchCenterX(const qreal &touchCenterX);
        qreal touchCenterY() const;
        void setTouchCenterY(const qreal &touchCenterY);
        qreal touchStartX() const;
        void setTouchStartX(const qreal &touchStartX);
        qreal touchStartY() const;
        void setTouchStartY(const qreal &touchStartY);
        qreal touchEndX() const;
        void setTouchEndX(const qreal &touchEndX);
        qreal touchEndY() const;
        void setTouchEndY(const qreal &touchEndY);
        qreal scale() const;
        void setScale(const qreal &scale);
        bool isHorizontalPinch() const;
        void setIsHorizontalPinch(const bool &isHorizontalPinch);

        // Plot padding (distance between the edges and the axes area)
        double xMinPadding() const;
        void setXMinPadding(const double &xMinPadding);
        double xMaxPadding() const;
        void setXMaxPadding(const double &xMaxPadding);
        double yMinPadding() const;
        void setYMinPadding(const double &yMinPadding);
        double yMaxPadding() const;
        void setYMaxPadding(const double &yMaxPadding);

        // Titles for the vertical and horizontal axes as well as the plot Title
        QString xAxisTitle() const;
        void setXAxisTitle(const QString &xAxisTitle);
        QString yAxisTitle() const;
        void setYAxisTitle(const QString &yAxisTitle);
        QString plotTitle() const;
        void setPlotTitle(const QString &plotTitle);

        // Color to use for plotting the spectrum
        QString lineColor() const;
        void setLineColor(const QString &lineColor);

        // Plot line thickness to use
        int lineThickness() const;
        void setLineThickness(const int &lineThickness);

        // Variables to set the number of minor and major ticks along the horizontal and vertical axes
        int numMinorXTicks() const;
        void setNumMinorXTicks(const int &numMinorXTicks);
        int numMajorXTicks() const;
        void setNumMajorXTicks(const int &numMajorXTicks);
        int numMinorYTicks() const;
        void setNumMinorYTicks(const int &numMinorYTicks);
        int numMajorYTicks() const;
        void setNumMajorYTicks(const int &numMajorYTicks);

        // Variable indicating if the plot is to be dipslayed inverted or direct
        int plotInverted() const;
        void setPlotInverted(const bool &plotInverted);

        // Methods to get and set the current spectrum index
        int currSpecIndex() const;
        void setCurrSpecIndex(const int &currSpecIndex);

        // Methods to get and set the plot image
        QString saveImage() const;
        void setSaveImage(const QString &saveImage);

        // Methods to get and set the top string with the information about the total pressure, pathlegth and temperature
        QString topString() const;
        void setTopString(const QString &topString);

        // Methods to get and set the state when file writing is complete (this could be implemented in a different was as aprameter passing is not needed)
        bool fileWritingComplete() const;
        void setFileWritingComplete(const bool &fileWritingComplete);

        // Methods to read the height of the plot
        int xHeight() const;

        // Method to get a variable indicating if the spectrum has finished plotting
        bool plotInProgress() const;

        // Methods to set the font point size to use in the plot
        qreal fontPointSize() const;
        void setFontPointSize(const qreal &fontPointSize);

        // Methods to enable or disable the tracking rullers
        bool enableRulers() const;
        void setEnableRulers(const bool &enableRulers);

    signals:

        // Signal emitted when the spectrum plot is changed
        void spectrumChanged();

        // Signal indicating that the wavenumber grid has changed
        void wnGridChanged();

        // Signals emitted when the physical boundaries of the plot have been changed
        void minXChanged();
        void maxXChanged();
        void minYChanged();
        void maxYChanged();

        // Pinch gesture coordinates and the magnification level
        void touchCenterXChanged();
        void touchCenterYChanged();
        void touchStartXChanged();
        void touchStartYChanged();
        void touchEndXChanged();
        void touchEndYChanged();
        void scaleChanged();
        void isHorizontalPinchChanged();

        // Signals emitted when the plto padding has been changed
        void xMinPaddingChanged();
        void xMaxPaddingChanged();
        void yMinPaddingChanged();
        void yMaxPaddingChanged();

        // Signals emitted when X or Y axis titles have been changed
        void xAxisTitleChanged();
        void yAxisTitleChanged();
        void plotTitleChanged();

        // Signal indicating that the color of the line to be used for plotting the spectrum has changed
        void lineColorChanged();

        // Signal informint that the line thickness to be used for the plot has changed
        void lineThicknessChanged();

        // Signals to notify about the change in the number of tick marks along the vertical or horizontal axis
        int numMinorXTicksChanged();
        int numMajorXTicksChanged();
        int numMinorYTicksChanged();
        int numMajorYTicksChanged();

        // Signal indicating that the plotInverted value has been changed
        bool plotInvertedChanged();

        // Signal is emitted when the current spectrum index is modified
        void currSpecIndexChanged();

        // Signal emited when the plot image is modigied
        void saveImageChanged();

        // Signal is emited when the top string is modified
        void topStringChanged();

        // Signal is emitted when saving of a file is complete
        void fileWritingCompleteChanged();

        // Signal is emitted when the x-axis height is changed
        void xHeightChanged();

        // Signal indicating the spectrum plotting state variable has been updated
        void plotInProgressChanged();

        // Signal is emited when the font point size is changed
        void fontPointSizeChanged();

        // Signals emitted when the ruler enabled state is changed
        void enableRulersChanged();

    private:

        // Method to draw axes and other components (Maybe import QWT), a curve plot maybe would do (need to check and see what it looks like)
        void drawAxes(QPainter *painter);

        // Method to find the new horizontal and vertical scales depending on the magnification level
        void findZoomPhysBoundaries();

        // Method to find the pan values along the X and Y axes (to pan spectrum)
        void findXAxisSetPanValues();
        void findYAxisSetPanValues();

        // Method to draw plots (Maybe import QWT), a curve plot maybe would do (need to check and see what it looks like)
        void drawPlot();
        void drawSpectrumInverted(QPainter *painter);
        void drawSpectrumDirect(QPainter *painter);

        // Methods to get the coordinates from the physical values
        int getXFromPhys(double xPhys);
        int getYFromPhys(double yPhys);

        // Methods to get the Physical values from the coordinates
        double getPhysX(int x);
        double getPhysY(int y);

        // Method to get X-axis resolution  equivalent to one pixel
        double getOnePixelXResolution();
        // Method to get the Y-axis resolution equivalent to one pixel
        double getOnePixelYResolution();

        // Nice numbers algorithm is converted from:
        //
        // Nice Numbers for Graph Labels
        // by Paul Heckbert
        // from "Graphics Gems", Academic Press, 1990
        //
        double nicenum(double x, bool round);

        Spectrum m_spectrum;
        QVector<Spectrum> spectra;  // Multiple spectra passed to the object for flotting
        QVector<double> m_wnGrid;

        double m_minX;
        double m_maxX;
        double m_minY;
        double m_maxY;
        // These are the default values assigned
        double minXdefault;
        double maxXdefault;
        double minYdefault;
        double maxYdefault;
        // These are the current scale values
        double minXcurrent;
        double maxXcurrent;
        double minYcurrent;
        double maxYcurrent;

        qreal m_touchCenterX;
        qreal m_touchCenterY;
        qreal m_touchStartX;
        qreal m_touchStartY;
        qreal m_touchEndX;
        qreal m_touchEndY;
        qreal m_scale;
        bool m_isHorizontalPinch;

        // Padding of the plot
        int m_xMinPadding;
        int m_yMinPadding;
        int m_xMaxPadding;
        int m_yMaxPadding;

        // Axies and plot titles
        QString m_xAxisTitle;
        QString m_yAxisTitle;
        QString m_plotTitle;

        // Color of the line to be used for plotting the spectrum
        QString m_lineColor;
        QVector<QString> colors;  // Array of colors for various passed in spectra

        // Thickness of the line to be used for plotting
        int m_lineThickness;

        // Number of tick marks along thevertical and horizontal axes
        int m_numMinorXTicks;
        int m_numMajorXTicks;
        int m_numMinorYTicks;
        int m_numMajorYTicks;

        // Variable indicating if the plot is to be displayed inverted or not
        bool m_plotInverted;

        // Plot bounding rectangle
        QRectF plotRect;

        // Boolean variable indicates that the top string is to be added to the plot
        bool appendTopString;

        // Variable indicating the current spectrum index
        int m_currSpecIndex;

        // Variable containing the path to save the plot image to
        QString m_saveImage;

        // Variable contains the top string with the additional information to be displayed in the saved plot
        QString m_topString;

        // Variable corresponding to the completion of file writing to disk
        bool m_fileWritingComplete;

        // Variable is used to return the height of the plot
        int m_xHeight;

        // Variable indicating the spectrum plotting state variable has been updated
        bool m_plotInProgress;

        // Variable to store the font point size
        qreal m_fontPointSize;

        // Enabled state of the tracking rulers
        bool m_enableRulers;
};

#endif // PLOT_H
