// 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.



// Main calculation class for the line-by-line program
#ifndef BYTRANCORE_H
#define BYTRANCORE_H

#include <QObject>
#include <QVector>
#include "spectrum.h"
#include "hitranonerec.h"
#include "atmosphere.h"
#include "params.h"
#include "lbl.h"
#include "concpressunitsconvert.h"
#include "temperatureunitsconvert.h"
#include "pathlengthunitsconvert.h"
#include "wavelength.h"
#include "hitranonlinedownloader.h"
#include "onelayerspectra.h"
#include "instrumentfunction.h"
#include "configinputoutput.h"
#include "sensors.h"
#include "yaxis.h"
#include "resultssaver.h"
#include "permissions.h"
#include "remotecontrol.h"
#include "ios/iosdefaulttextsize.h"


class BytranCore : public QObject
{
    Q_OBJECT

    // Property indicating if the internal storage read / write permission has been granted
    Q_PROPERTY (bool externalStorageAccessGranted READ externalStorageAccessGranted NOTIFY externalStorageAccessGrantedChanged)

    // Property indicates if the application is executed on an iPhone vs iPad
    Q_PROPERTY (bool iPhone READ iPhone NOTIFY iPhoneChanged)

    // Property with the default font point size to use
    Q_PROPERTY (qreal defaultFontPointSize READ defaultFontPointSize WRITE setDefaultFontPointSize NOTIFY defaultFontPointSizeChanged)
    // Property with the label height containing the default font (in pixels) on current platform
    Q_PROPERTY (int defaultLabelHeight READ defaultLabelHeight WRITE setDefaultLabelHeight NOTIFY defaultLabelHeightChanged)
    // Property with the font scaling ratio
    Q_PROPERTY(qreal fontScalingRatio READ fontScalingRatio WRITE setFontScalingRatio NOTIFY fontScalingRatioChanged)

    // Message to be displayed in the Ok dialog
    Q_PROPERTY(QString okDialogText READ okDialogText WRITE setOkDialogText NOTIFY okDialogTextChanged)

public:

    // Invocable method to be called from the QML to start running the calculations
    Q_INVOKABLE void calculate();
    // Invocable method to determine if the calculation is currently running
    Q_INVOKABLE bool calculationIsRunning();

    // Invokable method to save the configuration to a file
    Q_INVOKABLE void saveConfiguration();

    // Invokable method to cancel the calculation
    Q_INVOKABLE void cancelCalculation();

    // Invokable to update the variable indicating if the spectrum redraw update is complete
    Q_INVOKABLE void updatePlotInProgress(bool newPlotInProgress);

    // Constructor
    explicit BytranCore(QObject *parent = nullptr);

    // Methods to retrieve and set the HITRAN downloader object
    HitranOnlineDownloader *getHitranDownloader();
    void setHitranDownloader(HitranOnlineDownloader *newHitranDownloader);

    // Method to get the paramters
    Params *getParams();

    // Method to get the currently active atmospheric model
    Atmosphere *getAtm();

    // Method to get the horizontal path spectra
    OneLayerSpectra *getHorizSpectra();

    // Method to access the units converters
    ConcPressUnitsConvert *getConcPressUnitsConverter();
    TemperatureUnitsConvert *getTemperatureUnitsConverter();
    PathlengthUnitsConvert *getPathlengthUnitsConverter();
    Wavelength *getWavelengths();

    // Method to get a reference to the object with the vertical axis units
    YAxis *getYAxis();

    // Method to get a reference to an instrument function object
    InstrumentFunction *getInstrFunct();

    // Method to get a reference to the results saver
    ResultsSaver *getResultsSaver();

    // Method to get the configuration file loader / saver
    ConfigInputOutput *getConfigIO();

    // Method to return the sensors information
    Sensors *getSensors();

    // Method returns a reference to an object responsible for the remote control of the calculations
    RemoteControl *getRemoteControl();

    // Method to send a notification to the user
    void displayNotification(QString message, double value, bool visible, bool cancelButtonVisible);
    void hideNotification();

    // Methods to read / write the configuration file data after the permissions requests and initialization have been carried out
    void initAndLoadConfig();

    // Methods to read the height of the plot
    bool externalStorageAccessGranted() const;

    // Method indicates if the application is executed on an iPhone
    bool iPhone() const;

    // Methods to get and set the default font related paramters (font point size and the height of the label)
    qreal defaultFontPointSize() const;
    void setDefaultFontPointSize(qreal const defaultFontPointSize);
    int defaultLabelHeight() const;
    void setDefaultLabelHeight(int const defaultLabelHeight);
    qreal fontScalingRatio() const;
    void setFontScalingRatio(qreal const defaultFontScalingRatio);

    // Methods to get and set the text to be displayed in the Ok dialog
    QString okDialogText() const;
    void setOkDialogText(QString const okDialogText);

private slots:

    // Slot to invoke a complete calculation (used to tringger the calculation using remote control)
    void invokeCalculate();

    // Slot executed to calculate the line-by-line after the download of the HITRAN database is over
    void calculateLineByLine();
    void postCalculation();

    // Slot to load auxiliary data
    void loadTips();

signals:

    // Signal used to send notifications to the user of what is going on in the program
    void notify(QString message, double value, bool visible, bool cancelButtonVisible);

    // Signal is emitted after the calculations or when the magnification of the spectrum is needed in order to plot spectra
    void updateSpectra(bool updateScale, bool updateTotal);

    // Signal is used to update the value in the dialogs if they have been changed through remote control commands
    void valuesUpdated();
    // Signal is called to assign values from the currently selected atmospheric model
    void applyCurrentAtmModel();

    // Signal is emitted when the state of the variable indicating if the external storage is readable / writeable is changed
    void externalStorageAccessGrantedChanged();

    // Signal is emitted when the variable indicating if we are on an iPhone is changed
    void iPhoneChanged();

    // Signals emitted when the default font point size or label height are modified
    void defaultFontPointSizeChanged();
    void defaultLabelHeightChanged();
    void fontScalingRatioChanged();

    // Signal is emited when the ok dialog text is modified
    void okDialogTextChanged();

public slots:

    // Slot to open an Ok dialog
    void displayOkDialog(QString okDialogText);

private:

    // Method to download the TIPS data
    void downloadTips();

    // Method to create actions
    void createActionsEarly();
    void createActionsLate();

    // Object with the calculation parameters
    Params *par;

    // Object to read in and manipulate the atmospheric models (built in a custom)
    Atmosphere *atmos;

    // Object to carry out the line-by-line calculations
    Lbl *lbl;

    // Path to the location of the HITRAN database file
    QString hitranFilePath;

    // Objects used to convert data between different units
    ConcPressUnitsConvert *concPressConverter;
    TemperatureUnitsConvert *temperatureConverter;
    PathlengthUnitsConvert *pathlengthConverter;
    Wavelength *wavelength;

    // Downloader used to download data from a remote database
    HitranOnlineDownloader *hitranDownloader;

    // Object to contain the horizontal path calculated spectra
    OneLayerSpectra *horizSpectra;

    // Object with the parameters related to the vertical axis units
    YAxis *yaxis;

    // Object with the instrument functions
    InstrumentFunction *instrFunct;

    // Object to save and load the configuration to / from the configuration file
    ConfigInputOutput *configIo;

    // Object to save the results of the calculations
    ResultsSaver *resultsSaver;

    // Object to request permissions from the Andoid system
    Permissions *permissions;

    // Object with the sonsors data
    Sensors *sensors;

    // Object responsible for the remote control of the program
    RemoteControl *remoteControl;

    // Object to set the default text size in the iOS
    iosDefaultTextSize *iosTextSize;

    // Variable indicates that the calculation was triggered by pressing the calculation button
    bool calcButtonPressed;
    bool calculationRunning;

    // Variable indicating that the TIPS initialization is complete
    bool tipsInitComplete;

    // Variable indicating if the external storage read / write permission has been granted
    bool m_externalStorageAccessGranted;

    // Variable indicates if we are on an iPhone vs iPad
    bool m_iPhone;

    // Default font and label parameters
    qreal m_defaultFontPointSize;
    int m_defaultLabelHeight;
    qreal m_fontScalingRatio;
    QString m_okDialogText = "undefined";

};

#endif // BYTRANCORE_H
