// 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
//
// Parts of the line-by-line calculation algorithm are based on the Python code from the HITRAN Application
// Programming Interface (HAPI), http://hitran.org/hapi/
// R.V. Kochanov, I.E. Gordon, L.S. Rothman, P. Wcisło, C. Hill, J.S. Wilzewski, "HITRAN Application Programming Interface (HAPI):
// A comprehensive approach to working with spectroscopic data", JQSRT, Volume 177, July 2016, Pages 15–30; (hitran.org/hapi/)
//
// Appendix 1.1 of the theoretical section from the HITRAN-PC 4.0 manual was also consulted, www.cas.usf.edu/lidarlab/hitranpc/Hitran-PC_4.0_Manual.pdf
// Killinger D.K., Wilcox W.E., Pliutau D., "HITRAN=PC: 25 years of academic development and commercialization of laser
// atmospheric transmission software for environmental remote sensing", Technology & Innovation, Vol. 14, No. 3-4, pp. 303-327
//
// The Voigt calculation routine uses the algorithm described in: Abrarov, S., and Quine, B. (2015).
// "A rational approximation for efficient computation of the Voigt function in quantitative spectroscopy".
// Journal of Mathematics Research, 7(2), p 163. doi:http://dx.doi.org/10.5539/jmr.v7n2.
//
// 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.



// Object with all line-by-line calculation elements
#ifndef LBL_H
#define LBL_H

#include <QObject>
#include "hitranonerec.h"
#include "onelayerspectra.h"
#include "hitranonlinedownloader.h"
#include "params.h"
#include "spectrum.h"
#include "wavelength.h"
#include "const.h"
#include "auxisotopesarray.h"
#include <complex>   // Complex numbers need to be used in the Hartmann-Tran profile
#include <cmath>
#include <QList>
#include <QVector>


class Lbl: public QObject
{
    Q_OBJECT
public:

    explicit Lbl(QObject *parent = 0, HitranOnlineDownloader *newHitran = 0);

    // Method to calculate spectra for a horizontal path
    void calculateHorizPath();

    // Method to calculate spectra for a slant path
    void calculateSlantPath();

    // Methods to get and set the HITRAN records to run calculations for
    QVector<HitranOneRec> *getHitranRecs();
    void setHitranRecs(QVector<HitranOneRec> *newHitranRecs);

    // Methods to get and set a pointer to the spectra array (this object is used to save the calculated spectra to)
    OneLayerSpectra *getHorizSpec();
    void setHorizSpec(OneLayerSpectra *newHorizSpec);

    // Method to get and set a pointer to the object with the calculation parameters
    Params *getParams();
    void setParams(Params *newParams);

    // Method to get and set an object with wavelengths
    Wavelength *getWavelength();
    void setWavelength(Wavelength *newWavelength);

    // Method to initialize the spectra (resize them according to the molparam.txt file information)
    void initHorizSpectra();

    // Method to find maximum values in the spectra
    void findMinMaxValuesInSpectra();

    // Method to pass the hitran downloader class reference to the object (used for segment reading of the data)
    void setHitranDownloader(HitranOnlineDownloader *newHitran);

    // Method is used to set a variable used to cancel the calculation
    void setCancelCalculation(bool newCancelCalculation);

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 to update the spectra
    void updateSpectra(bool updateScale, bool updateTotal);

    // Signal is emited to notify the core object that the calculation has been completed
    void calculationComplete();

private slots:

    // Slot to calculate a segment (for different lineshape profiles)
    void calcWnSegment();

    // Slot is executed when the calcultion is over
    void postCalculation();

private:

    // Method to create connections
    void createActions();

    // Method to calculate one Lorentz wavenumber segment
    void calcDopplerWnSegment();
    void calcLorentzWnSegment();
    void calcVoigtWnSegment();
    void calcVoigtWnSegmentHighRes();

    // Method is used to precalculate frequently used variables
    void precalculateFrequentlyUsed();

    // Method to perform the line-by-line calculation
    void performLblCalculation();

    // Array with the HITRAN data records to run calculations for
    QVector<HitranOneRec> *hitranRecs;

    // Pointer to the object with the spectra
    OneLayerSpectra *horizSpectra;

    // Pointer to the object containing the calculation parameters
    Params *par;

    // Pointer to an array with wavelengths / wavenumbers
    Wavelength *wavelength;

    // Pointer to the HITRAN downlaoder class to segment-read the HITRAN data
    HitranOnlineDownloader *hitran;

    // Current record number
    int currRecNum;

    // Variable set to cancel the calculation
    bool cancelCalculation;

    // The following coefficents used in the the Voigt profile implementation are taken from the publication reported in:
    // Abrarov, S., & Quine, B. (2015). A Rational Approximation for Efficient Computation of the Voigt Function
    // in Quantitative Spectroscopy. Journal Of Mathematics Research, 7(2), p163. doi:http://dx.doi.org/10.5539/jmr.v7n2
    // Coefficients to be used for the calculation of the Voigt profile
    QVector<double> coeff1_12;  // Alpha
    QVector<double> coeff2_12;  // Beta
    QVector<double> coeff3_12;  // Gamma
    QVector<double> coeff1_16;  // Alpha
    QVector<double> coeff2_16;  // Beta
    QVector<double> coeff3_16;  // Gamma

    // Frequently used variables to be precalculated before the line-by-line routine
    double m0;          // First multiplication constant for the Doppler and Voigt calculations
    double m1;          // First multiplication constant, 100 is to convert to centimeters and 0.000001 is to convert from parts per million (ppmv)
    QVector<double> m3; // Multiplication constant used to convert the cross-section into the optical depth (this is precalculated to speed up the calculations)
    double expTerm1;    // Term under the exponent to recalculate the line intensity
    double expTerm2;    // Term under the exponent to recalculate the line intensity
    double pressRatio;  // Current to standard pressure ratio
    double tempRatio;   // Current to standard temperature ratio

};

#endif // LBL_H
