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



// Object used to pass spectral results calculations to the plot from the core module and its components
#include "spectraresultsqml.h"
#include "auxiliary.h"
#include <QMessageBox>
#include <QApplication>
#include <QScreen>
#include <cmath>

SpectraResultsQml::SpectraResultsQml(QObject *parent, BytranCore *inCore) : QObject(parent)
{
    // Passing in the core object into the internal variable
    this->core = inCore;
    m_showTotal = this->core->getYAxis()->getShowTotal();
    m_showPlainTotal = true;
    m_showInstrTotal = true;

    // Setting the total view to display both the total spectrum as well as the smoothed instrument function processed one
    totalView = 0;

    // Initializing the object to calculate the radiance
    radiance = new Radiance();

    // Creating connections
    createActions();
}

// Method to create connections
void SpectraResultsQml::createActions()
{
    connect(this->core, &BytranCore::updateSpectra, this, &SpectraResultsQml::setUpdateSpectra);
    connect(this->core->getRemoteControl(), SIGNAL(showTotalChanged(bool)), this, SLOT(updateShowTotal(bool)));
    connect(this->core->getRemoteControl(), SIGNAL(showPlainTotalChanged(bool)), this, SLOT(updateShowPlainTotal(bool)));
    connect(this->core->getRemoteControl(), SIGNAL(showInstrTotalChanged(bool)), this, SLOT(updateShowInstrTotal(bool)));
}
// Method returns the current spectrum
Spectrum SpectraResultsQml::spectrum() const
{
    return m_spectrum;
}

QVector<double> SpectraResultsQml::wnGrid() const { return this->m_wnGrid; }

// Color to use for plottin the spectrum
QString SpectraResultsQml::lineColor() const { return m_lineColor; }

// Methods to get and set the current spectrum index
int SpectraResultsQml::currSpecIndex() const { return this->m_currSpecIndex; }
void SpectraResultsQml::setCurrSpecIndex(const int currSpecIndex)
{
    if (currSpecIndex != m_currSpecIndex)
    {
        m_currSpecIndex = currSpecIndex;
        emit currSpecIndexChanged();
    }
}

// Methods to set the number of points along the vertical axis
int SpectraResultsQml::heightPoints() const { return this->m_heightPoints; }
void SpectraResultsQml::setHeightPoints(const int &heightPoints)
{
    if (heightPoints != m_heightPoints)
    {
        m_heightPoints = heightPoints;
        emit heightPointsChanged();
    }
}

// Updating the dispay variables (Total vs. separate molecules), total and instrument function processed total spectrum display
void SpectraResultsQml::updateShowTotal(bool newShowTotal) { m_showTotal = newShowTotal;
                                                             this->core->getYAxis()->setShowTotal(newShowTotal);
                                                             emit showTotalChanged(); }
void SpectraResultsQml::updateShowPlainTotal(bool newShowPlainTotal) { m_showPlainTotal = newShowPlainTotal; emit showPlainTotalChanged(); }
void SpectraResultsQml::updateShowInstrTotal(bool newShowInstrTotal) { m_showInstrTotal = newShowInstrTotal; emit showInstrTotalChanged(); }

// Methods to switch between the separate molecules spectra and the total spectrum
bool SpectraResultsQml::showTotal() const { return this->core->getYAxis()->getShowTotal(); }
void SpectraResultsQml::setShowTotal(const bool &showTotal)
{
    if (showTotal != m_showTotal)
    {
        m_showTotal = showTotal;
        this->core->getYAxis()->setShowTotal(m_showTotal);
        emit showTotalChanged();
        updatePlotAllPreserveScale();
    }
}

// Method to set a variable indicating if the plain total spectrum is to be displayed
bool SpectraResultsQml::showPlainTotal() const { return m_showPlainTotal; }
void SpectraResultsQml::setShowPlainTotal(const bool &showPlainTotal)
{
    if (showPlainTotal != m_showPlainTotal)
    {
        m_showPlainTotal = showPlainTotal;
        emit showPlainTotalChanged();
        setUpdateSpectra(false, true);
    }
}

// Method to set a variable indicating if the instrument function processed spectrum is to be displayed
bool SpectraResultsQml::showInstrTotal() const { return m_showInstrTotal; }
void SpectraResultsQml::setShowInstrTotal(const bool &showInstrTotal)
{
    if (showInstrTotal != m_showInstrTotal)
    {
        m_showInstrTotal = showInstrTotal;
        emit showInstrTotalChanged();
        setUpdateSpectra(false, true);
    }
}

double SpectraResultsQml::minX() const { return core->getWavelengths()->getStartWlCurrUnits(); }
double SpectraResultsQml::maxX() const { return core->getWavelengths()->getEndWlCurrUnits(); }
double SpectraResultsQml::minY() const { return core->getYAxis()->getMinYPlot(); }
double SpectraResultsQml::maxY() const { return core->getYAxis()->getMaxYPlot(); }

// Title for the horizontal axis
QString SpectraResultsQml::xAxisTitle()
{
    return core->getWavelengths()->getAxisTitle();
}

// Method to get the Y axis title
QString SpectraResultsQml::yAxisTitle()
{
    return this->m_yAxisTitle;
}

// Slot called to update spectra
void SpectraResultsQml::setUpdateSpectra(bool updateScale, bool updateTotal)
{
    int i;  // Loop variable
    int j;  // Loop variable
    double optDepth;   // Auxiliary optical depth variable
    double crossSect;  // Auxiliary value to calculate the cross-section total spectrum
    double maxCurUnits;   // Maximum in current units
    bool condition1;  // Condition 1
    bool condition2;  // Condition 2
    int power;        // Integer determining to what power another variable is to be raised
    double powValue;  // Maximum axis value obtained using the pow averaging


    // Updating the scale
    if (updateScale)
    {
        m_minY = core->getYAxis()->getMinYPlot();
        m_maxY = core->getYAxis()->getMaxYPlot();
        m_minX = core->getWavelengths()->getStartWlCurrUnits();
        m_maxX = core->getWavelengths()->getEndWlCurrUnits();
    }

    // Getting the axes titles based on the current settings
    m_yAxisTitle = core->getYAxis()->getYAxisTitle();
    m_xAxisTitle = core->getWavelengths()->getAxisTitle();

    // Setting the wavelnegth grid in current units
    m_wnGrid.resize(core->getWavelengths()->getWns()->count());
    for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
    {
        m_wnGrid[i] = core->getWavelengths()->fromDefaultToCurrent(core->getWavelengths()->getWnsAt(i));
    }

    emit wnGridChanged();
    emit yAxisTitleChanged();
    emit xAxisTitleChanged();

    // Updating the scale
    if (updateScale)
    {
        emit minXChanged();
        emit maxXChanged();
        emit minYChanged();
        emit maxYChanged();
    }

    // Choosing between the showing total spectra or the individual molecular components
    if (this->core->getYAxis()->getShowTotal() == true)
    {
        if (updateTotal)  // Sometimes there is no need to recalculate and resend the total spectrum to the plot because it does not depend on the vertical resolution of the screen
        {
            // Clearing the pushed data (for saving to a file)
            core->getResultsSaver()->clearPushedData();
            // Appending the wavenumbers array to the data to be saved
            core->getResultsSaver()->addPushedData(*(core->getWavelengths()->getWns()), "Wavenumber, cm-1");
            // Appending the wavelength array to the data to be saved
            core->getResultsSaver()->addPushedData(m_wnGrid, core->getWavelengths()->getAxisTitle());

            m_currSpecIndex = -1;  // Sending the command to accumulate the spectra to plot
            emit currSpecIndexChanged();
            emit lineColorChanged();
            emit spectrumChanged();

            if (core->getYAxis()->getDisplayedValue() == 0)  // Attenuation (Optical depth etc and cross-sections)
            {
                if (core->getYAxis()->getYPlotUnits() == 0)  // Cross-sections
                {
                    if (this->m_showPlainTotal || this->m_showInstrTotal)  // Cross-sections - Show high resolution total spectrum
                    {
                        // Filling the total for the cross-section spectra with 0
                        core->getHorizSpectra()->getCrossSect()->getY()->resize(core->getWavelengths()->getWns()->count());
                        core->getHorizSpectra()->getCrossSect()->getX()->resize(0);
                        for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                        {
                             core->getHorizSpectra()->getCrossSect()->setYAt(i, 0);
                        }

                        // Recalculating the total cross-sections by taking into account the selected spectra
                        // Forming the total cross-sectional spectrum
                        for (j = 0; j < core->getParams()->getMol()->count(); j++)
                        {
                            // Only adding the selected spectra to the plot
                            if (core->getParams()->getMolAt(j)->getSelected() == true)
                            {
                                // Summing spectra by wavelength
                                for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                                {
                                    crossSect = core->getHorizSpectra()->getCrossSect()->getYAt(i) + core->getHorizSpectra()->getMolAt(j)->getCrossSect()->getYAt(i);
                                    core->getHorizSpectra()->getCrossSect()->setYAt(i, crossSect);
                                }
                            }
                        }
                        // Finding the maximum cross-sectional value in the total cross-sectional spectrum
                        core->getHorizSpectra()->getCrossSect()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getCrossSect()->getY()));

                        // Automatic recalculation of the maximum cross-sectional scale (if applicable)
                        // Calculating the maximum value if needed
                        if (core->getYAxis()->getCrossSectionAutoRecalc())
                        {
                            power = (int) (log10(core->getHorizSpectra()->getCrossSect()->getMaxValue()));
                            powValue = pow(10, power);
                            if (core->getHorizSpectra()->getCrossSect()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxCrossSection(powValue * 0.5); }
                            else { core->getYAxis()->setMaxCrossSection(powValue); }
                            emit maxYChanged();
                        }
                    }

                    if (this->m_showInstrTotal)  // Cross-sections - Show instrument function total spectrum
                    {
                        // Calculating the instrument function processed cross-sectional spectrum
                        // Calculating the instrument function processed total spectrum
                        core->getInstrFunct()->setWavelength(core->getWavelengths());
                        core->getInstrFunct()->convolveSpectrum(core->getHorizSpectra()->getCrossSect(), core->getHorizSpectra()->getInstrFunctCrossSect());
                        core->getHorizSpectra()->getInstrFunctCrossSect()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getInstrFunctCrossSect()->getY()));

                        // Calculating the maximum scale in the automatic mode (only if it hasn't been calculated for the plain spectrum)
                        if (this->m_showPlainTotal == false)
                        {
                            // Calculating the maximum value if needed
                            if (core->getYAxis()->getCrossSectionAutoRecalc())
                            {
                                power = (int) (log10(core->getHorizSpectra()->getCrossSect()->getMaxValue()));
                                powValue = pow(10, power);
                                if (core->getHorizSpectra()->getCrossSect()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxCrossSection(powValue * 0.5); }
                                else { core->getYAxis()->setMaxCrossSection(powValue); }
                                emit maxYChanged();
                            }
                        }
                    }
                }
                else // Optical depth and other
                {
                    if (this->m_showPlainTotal || this->m_showInstrTotal)  // Optical depth etc - Show high resolution total spectrum
                    {
                        // Filling the arrays with 0 for the composite spectrum
                        core->getHorizSpectra()->getOptDepth()->getY()->resize(core->getWavelengths()->getWns()->count());
                        core->getHorizSpectra()->getOptDepth()->getX()->resize(0);
                        for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                        {
                             core->getHorizSpectra()->getOptDepth()->setYAt(i, 0);
                        }

                        // Recalculating the total composite by taking into account the selected spectra
                        // Forming the composite spectrum
                        for (j = 0; j < core->getParams()->getMol()->count(); j++)
                        {
                            // Only adding the selected spectra to the plot
                            if (core->getParams()->getMolAt(j)->getSelected() == true)
                            {
                                // Summing spectra by wavelength
                                for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                                {
                                    optDepth = core->getHorizSpectra()->getOptDepth()->getYAt(i) + core->getHorizSpectra()->getMolAt(j)->getOptDepth()->getYAt(i);
                                    core->getHorizSpectra()->getOptDepth()->setYAt(i, optDepth);
                                }
                            }
                        }

                        // Finding the maximum value in the total Optical Depth spectrum
                        core->getHorizSpectra()->getOptDepth()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getOptDepth()->getY()));
                    }

                    if (this->m_showInstrTotal)  // Optical depth etc - Show instrument function total spectrum
                    {
                        // Calculating the instrument function processed total spectrum
                        core->getInstrFunct()->setWavelength(core->getWavelengths());
                        core->getInstrFunct()->convolveSpectrum(core->getHorizSpectra()->getOptDepth(), core->getHorizSpectra()->getInstrFunctOptDepth());
                        core->getHorizSpectra()->getInstrFunctOptDepth()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getInstrFunctOptDepth()->getY()));
                    }
                }
            }
            else // Radiance
            {
                // Filling the arrays with 0 for the composite spectrum
                core->getHorizSpectra()->getOptDepth()->getY()->resize(core->getWavelengths()->getWns()->count());
                core->getHorizSpectra()->getOptDepth()->getX()->resize(0);
                for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                {
                     core->getHorizSpectra()->getOptDepth()->setYAt(i, 0);
                }

                // Recalculating the total composite by taking into account the selected spectra
                // Forming the composite spectrum
                for (j = 0; j < core->getParams()->getMol()->count(); j++)
                {
                    // Only adding the selected spectra to the plot
                    if (core->getParams()->getMolAt(j)->getSelected() == true)
                    {
                        // Summing spectra by wavelength
                        for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                        {
                            optDepth = core->getHorizSpectra()->getOptDepth()->getYAt(i) + core->getHorizSpectra()->getMolAt(j)->getOptDepth()->getYAt(i);
                            core->getHorizSpectra()->getOptDepth()->setYAt(i, optDepth);
                        }
                    }
                }

                // Finding the maximum value in the total Optical Depth spectrum
                core->getHorizSpectra()->getOptDepth()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getOptDepth()->getY()));

                if (this->m_showPlainTotal)  // Radiance - Show high resolution total spectrum
                {
                    // Calculating the radiance
                    radiance->calculateRadiance(core->getHorizSpectra()->getOptDepth(), core->getHorizSpectra()->getPlainRadiance(), core->getWavelengths()->getWns(), core->getParams()->getHorizParams()->getTemp());
                    core->getHorizSpectra()->getPlainRadiance()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getPlainRadiance()->getY()));

                    // Calculating the maximum scale value if needed
                    if (core->getYAxis()->getRadianceAutoRecalc())
                    {
                        power = (int) (log10(core->getHorizSpectra()->getPlainRadiance()->getMaxValue()));
                        powValue = pow(10, power);
                        if (core->getHorizSpectra()->getPlainRadiance()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxRadiance(powValue * 0.5); }
                        else { core->getYAxis()->setMaxRadiance(powValue); }
                        emit maxYChanged();
                    }
                }

                if (this->m_showInstrTotal)  // Radiance - Show instrument function total spectrum
                {
                    // Calculating the instrument function processed total spectrum
                    core->getInstrFunct()->setWavelength(core->getWavelengths());
                    core->getInstrFunct()->convolveSpectrum(core->getHorizSpectra()->getOptDepth(), core->getHorizSpectra()->getInstrFunctOptDepth());
                    core->getHorizSpectra()->getInstrFunctOptDepth()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getInstrFunctOptDepth()->getY()));

                    // Calculating the radiance
                    radiance->calculateRadiance(core->getHorizSpectra()->getInstrFunctOptDepth(), core->getHorizSpectra()->getInstrFunctRadiance(), core->getWavelengths()->getWns(), core->getParams()->getHorizParams()->getTemp());
                    core->getHorizSpectra()->getInstrFunctRadiance()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getInstrFunctRadiance()->getY()));

                    // Calculating the maximum scale in the automatic mode (only if it hasn't been calculated for the plain spectrum)
                    if (this->m_showPlainTotal == false)
                    {
                        // Calculating the maximum value if needed
                        if (core->getYAxis()->getRadianceAutoRecalc())
                        {
                            power = (int) (log10(core->getHorizSpectra()->getInstrFunctRadiance()->getMaxValue()));
                            powValue = pow(10, power);
                            if (core->getHorizSpectra()->getInstrFunctRadiance()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxRadiance(powValue * 0.5); }
                            else { core->getYAxis()->setMaxRadiance(powValue); }
                            emit maxYChanged();
                        }
                    }
                }
            }

            // PLOTTING - High resolution
            // Ploting unprocessed total or the corresponding radiance
            if (this->m_showPlainTotal == true)
            {
                if (core->getYAxis()->getDisplayedValue() == 1)  // Radiance
                {
                    // Transfering the total spectrum to the variable used to transfer data over to the plotting object
                    m_spectrum.getY()->resize(core->getHorizSpectra()->getPlainRadiance()->getY()->count());
                    for (j = 0; j < core->getHorizSpectra()->getPlainRadiance()->getY()->count(); j++)
                    {
                        m_spectrum.setYAt(j,  core->getHorizSpectra()->getPlainRadiance()->getYAt(j));
                    }
                    m_spectrum.setMaxValue(core->getHorizSpectra()->getPlainRadiance()->getMaxValue());

                    m_lineColor = "black";
                    m_currSpecIndex = 0;
                    emit currSpecIndexChanged();
                    emit lineColorChanged();
                    emit spectrumChanged();

                    // Appending the radiance spectrum to the sectra to be saved
                    core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "Radiance");
                }
                else  // Total spectrum
                {
                    if (core->getYAxis()->getYPlotUnits() == 0)  // Cross-sections plot
                    {
                        // Transfering the total spectrum to the variable used to transfer data over to the ploting object
                        m_spectrum.getY()->resize(core->getHorizSpectra()->getCrossSect()->getY()->count());
                        for (j = 0; j < core->getHorizSpectra()->getCrossSect()->getY()->count(); j++)
                        {
                            m_spectrum.setYAt(j,  core->getHorizSpectra()->getCrossSect()->getYAt(j));
                        }
                        m_spectrum.setMaxValue(core->getHorizSpectra()->getCrossSect()->getMaxValue());

                        m_lineColor = "black";
                        m_currSpecIndex = 0;
                        emit currSpecIndexChanged();
                        emit lineColorChanged();
                        emit spectrumChanged();

                        // Appending the total spectum to the spectra to be saved
                        core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "XSect_Total");
                    }
                    else // Optical depth, Absorption, Transmission plot
                    {
                        // Transfering the total spectrum to the variable used to transfer data over to the ploting object
                        m_spectrum.getY()->resize(core->getHorizSpectra()->getOptDepth()->getY()->count());
                        for (j = 0; j < core->getHorizSpectra()->getOptDepth()->getY()->count(); j++)
                        {
                            m_spectrum.setYAt(j,  core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getOptDepth()->getYAt(j)));
                        }
                        m_spectrum.setMaxValue(core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getOptDepth()->getMaxValue()));

                        m_lineColor = "black";
                        m_currSpecIndex = 0;
                        emit currSpecIndexChanged();
                        emit lineColorChanged();
                        emit spectrumChanged();

                        // Appending the total spectum to the spectra to be saved
                        core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "Total");
                    }
                }
            }

            // PLOTTING - Instrument function processed
            // Transfering the instrument function adjusted spectrum over to the plot (if the instrument function is selected)
            if ((core->getInstrFunct()->getInstrFunctIndex() != 0) && (this->m_showInstrTotal == true))
            {
                if (core->getYAxis()->getDisplayedValue() == 1)  //  Instrument function processed Radiance
                {
                    // Transfering the total instrument function adjusted spectrum to the variable used to transfer data over to the plotting object
                    m_spectrum.getY()->resize(core->getHorizSpectra()->getInstrFunctRadiance()->getY()->count());
                    for (j = 0; j < core->getHorizSpectra()->getInstrFunctRadiance()->getY()->count(); j++)
                    {
                        m_spectrum.setYAt(j,  core->getHorizSpectra()->getInstrFunctRadiance()->getYAt(j));
                    }
                    m_spectrum.setMaxValue(core->getHorizSpectra()->getInstrFunctRadiance()->getMaxValue());

                    if (this->m_showPlainTotal == false) { m_lineColor = "black"; }
                    else { m_lineColor = "red"; }

                    m_currSpecIndex = 1;
                    emit currSpecIndexChanged();
                    emit lineColorChanged();
                    emit spectrumChanged();

                    // Appending the instrument funciton processed radiance spectrum to be saved
                    core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "Instr. funct. Radiance");
                }
                else  // Instrument function processed total spectrum
                {
                    if (core->getYAxis()->getYPlotUnits() == 0)  // Cross-section instrument function processed spectrum
                    {
                        // Transfering the total instrument function adjusted spectrum to the variable used to transfer data over to the plotting object
                        m_spectrum.getY()->resize(core->getHorizSpectra()->getInstrFunctCrossSect()->getY()->count());
                        for (j = 0; j < core->getHorizSpectra()->getInstrFunctCrossSect()->getY()->count(); j++)
                        {
                            m_spectrum.setYAt(j,  core->getHorizSpectra()->getInstrFunctCrossSect()->getYAt(j));
                        }
                        m_spectrum.setMaxValue(core->getHorizSpectra()->getInstrFunctCrossSect()->getMaxValue());

                        if (this->m_showPlainTotal == false) { m_lineColor = "black"; }
                        else { m_lineColor = "red"; }

                        m_currSpecIndex = 1;
                        emit currSpecIndexChanged();
                        emit lineColorChanged();
                        emit spectrumChanged();

                        // Appending the insrument function spectrum to the spectra to be saved
                        core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "Instr. funct. XSect_Total");
                    }
                    else  // Instrument function processed Optical Depth, Absorption or Transmission
                    {
                        // Transfering the total instrument function adjusted spectrum to the variable used to transfer data over to the plotting object
                        m_spectrum.getY()->resize(core->getHorizSpectra()->getInstrFunctOptDepth()->getY()->count());
                        for (j = 0; j < core->getHorizSpectra()->getInstrFunctOptDepth()->getY()->count(); j++)
                        {
                            m_spectrum.setYAt(j,  core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getInstrFunctOptDepth()->getYAt(j)));
                        }
                        m_spectrum.setMaxValue(core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getInstrFunctOptDepth()->getMaxValue()));

                        if (this->m_showPlainTotal == false) { m_lineColor = "black"; }
                        else { m_lineColor = "red"; }

                        m_currSpecIndex = 1;
                        emit currSpecIndexChanged();
                        emit lineColorChanged();
                        emit spectrumChanged();

                        // Appending the insrument function spectrum to the spectra to be saved
                        core->getResultsSaver()->addPushedData(*(m_spectrum.getY()), "Instr. funct. Total");
                    }
                }
            }
        }
    }
    else // Separate molecules plot
    {
        // Clearing the pushed data (for saving to a file)
        core->getResultsSaver()->clearPushedData();
        // Appending the wavenumbers array to the data to be saved
        core->getResultsSaver()->addPushedData(*(core->getWavelengths()->getWns()), "Wavenumber, cm-1");
        // Appending the wavelength array to the data to be saved
        core->getResultsSaver()->addPushedData(m_wnGrid, core->getWavelengths()->getAxisTitle());

        m_currSpecIndex = -1;  // Sending the command to accumulate spectra to plot
        emit currSpecIndexChanged();
        emit lineColorChanged();
        emit spectrumChanged();

        if (core->getYAxis()->getDisplayedValue() == 0) // Individual molecular spectra
        {
            if (core->getYAxis()->getYPlotUnits() == 0)  // Absorption cross-section
            {
                // Filling the the total for the cross-section spectra with 0
                core->getHorizSpectra()->getCrossSect()->getY()->resize(core->getWavelengths()->getWns()->count());
                core->getHorizSpectra()->getCrossSect()->getX()->resize(0);
                for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                {
                     core->getHorizSpectra()->getCrossSect()->setYAt(i, 0);
                }

                // Recalculating the total cross-sections by taking into account the selected spectra
                // Forming the composite spectrum
                for (j = 0; j < core->getParams()->getMol()->count(); j++)
                {
                    // Only adding the selected spectra to the plot
                    if (core->getParams()->getMolAt(j)->getSelected() == true)
                    {
                        // Summing spectra by wavelength
                        for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                        {
                            crossSect = core->getHorizSpectra()->getCrossSect()->getYAt(i) + core->getHorizSpectra()->getMolAt(j)->getCrossSect()->getYAt(i);
                            core->getHorizSpectra()->getCrossSect()->setYAt(i, crossSect);
                        }
                    }
                }
                // Finding the maximum value in the total cross-sectional spectrum
                core->getHorizSpectra()->getCrossSect()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getCrossSect()->getY()));

                // Automatic recalculation of the maximum cross-sectional scale (if applicable)
                // Calculating the maximum value if needed
                if (core->getYAxis()->getCrossSectionAutoRecalc())
                {
                    power = (int) (log10(core->getHorizSpectra()->getCrossSect()->getMaxValue()));
                    powValue = pow(10, power);
                    if (core->getHorizSpectra()->getCrossSect()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxCrossSection(powValue * 0.5); }
                    else { core->getYAxis()->setMaxCrossSection(powValue); }
                    emit maxYChanged();
                }

                for (m_currSpecIndex = 0; m_currSpecIndex < core->getHorizSpectra()->getMol()->count(); m_currSpecIndex++)
                {
                    if (core->getParams()->getMolAt(m_currSpecIndex)->getSelected() == true)
                    {
                        // Finding the maximum of the spectrum
                        maxCurUnits = core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getCrossSect()->getMaxValue();
                        // If Transmission units are used the values are inverted with Optical depth resulting in incorrect handling of the threshold condition
                        condition1 = (maxCurUnits > (core->getYAxis()->getMinYPlot() + (core->getYAxis()->getMaxYPlot() - core->getYAxis()->getMinYPlot()) / (m_heightPoints * 0.5)));

                        if (condition1)
                        {
                            m_spectrum.getY()->resize(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getCrossSect()->getY()->count());
                            for (j = 0; j < core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getCrossSect()->getY()->count(); j++)
                            {
                                m_spectrum.setYAt(j, core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getCrossSect()->getYAt(j));
                            }
                            m_spectrum.setMaxValue(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getCrossSect()->getMaxValue());
                            m_lineColor = core->getParams()->getMolAt(m_currSpecIndex)->getColor();
                            emit currSpecIndexChanged();
                            emit lineColorChanged();
                            emit spectrumChanged();

                            // Transfering the molecule component to the spectra to be saved
                            core->getResultsSaver()->addPushedData((*m_spectrum.getY()), core->getParams()->getMolAt(m_currSpecIndex)->getChemForm());
                        }
                    }
                }               
            }
            else  // Optical depth
            {
                for (m_currSpecIndex = 0; m_currSpecIndex < core->getHorizSpectra()->getMol()->count(); m_currSpecIndex++)
                {
                    if (core->getParams()->getMolAt(m_currSpecIndex)->getSelected() == true)
                    {
                        // Finding the maximum of the spectrum
                        maxCurUnits = core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth()->getMaxValue());
                        // If Transmission units are used the values are inverted with Optical depth resulting in incorrect handling of the threshold condition
                        condition1 = (maxCurUnits > (core->getYAxis()->getMinYPlot() + (core->getYAxis()->getMaxYPlot() - core->getYAxis()->getMinYPlot()) / (m_heightPoints * 0.5))) && ((core->getYAxis()->getYPlotUnits() == 2) || (core->getYAxis()->getYPlotUnits() == 1));
                        // Reconsider this condition it is too slow need to have a threshold case to replot fewer spectra
                        condition2 = (maxCurUnits < (core->getYAxis()->getMaxYPlot() - (core->getYAxis()->getMaxYPlot() - core->getYAxis()->getMinYPlot()) / (m_heightPoints * 0.5))) && (core->getYAxis()->getYPlotUnits() == 3);

                        if (condition1 || condition2)
                        {
                            m_spectrum.getY()->resize(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth()->getY()->count());
                            for (j = 0; j < core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth()->getY()->count(); j++)
                            {
                                m_spectrum.setYAt(j, core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth()->getYAt(j)));
                            }
                            m_spectrum.setMaxValue(core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth()->getMaxValue()));
                            m_lineColor = core->getParams()->getMolAt(m_currSpecIndex)->getColor();
                            emit currSpecIndexChanged();
                            emit lineColorChanged();
                            emit spectrumChanged();

                            // Transfering the molecule component to the spectra to be saved
                            core->getResultsSaver()->addPushedData((*m_spectrum.getY()), core->getParams()->getMolAt(m_currSpecIndex)->getChemForm());
                        }
                    }
                }
            }
        }
        else // Individual molecules radiance
        {
            for (m_currSpecIndex = 0; m_currSpecIndex < core->getHorizSpectra()->getMol()->count(); m_currSpecIndex++)
            {
                if (core->getParams()->getMolAt(m_currSpecIndex)->getSelected() == true)
                {
                    // Calculating radiance
                    radiance->calculateRadiance(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getOptDepth(), core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance(), core->getWavelengths()->getWns(), core->getParams()->getHorizParams()->getTemp());
                    // Finding the maximum value for the radiance in each spectrum
                    maxCurUnits = Auxiliary::maximum(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getY());
                    core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->setMaxValue(maxCurUnits);

                    // Finding the maximum of the spectrum
                    maxCurUnits = core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getMaxValue());
                    condition1 = (maxCurUnits > (core->getYAxis()->getMinYPlot() + (core->getYAxis()->getMaxYPlot() - core->getYAxis()->getMinYPlot()) / (m_heightPoints * 0.5)));

                    if (condition1)
                    {
                        m_spectrum.getY()->resize(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getY()->count());
                        for (j = 0; j < core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getY()->count(); j++)
                        {
                            m_spectrum.setYAt(j, core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getYAt(j)));
                        }
                        m_spectrum.setMaxValue(core->getYAxis()->toCurrentFromDefault(core->getHorizSpectra()->getMolAt(m_currSpecIndex)->getRadiance()->getMaxValue()));
                        m_lineColor = core->getParams()->getMolAt(m_currSpecIndex)->getColor();
                        emit currSpecIndexChanged();
                        emit lineColorChanged();
                        emit spectrumChanged();

                        // Transfering the molecule component to the spectra to be saved
                        core->getResultsSaver()->addPushedData((*m_spectrum.getY()), core->getParams()->getMolAt(m_currSpecIndex)->getChemForm() + "_R");
                    }
                }
            }

            // Filling the arrays with 0 for the composite spectrum
            core->getHorizSpectra()->getOptDepth()->getY()->resize(core->getWavelengths()->getWns()->count());
            core->getHorizSpectra()->getOptDepth()->getX()->resize(0);
            for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
            {
                 core->getHorizSpectra()->getOptDepth()->setYAt(i, 0);
            }

            // Recalculating the total composite by taking into account the selected spectra
            // Adding optical depth for the total optical depth spectrum
            for (j = 0; j < core->getParams()->getMol()->count(); j++)
            {
                // Only adding the selected spectra to the plot
                if (core->getParams()->getMolAt(j)->getSelected() == true)
                {
                    // Summing spectra by wavelength
                    for (i = 0; i < core->getWavelengths()->getWns()->count(); i++)
                    {
                        optDepth = core->getHorizSpectra()->getOptDepth()->getYAt(i) + core->getHorizSpectra()->getMolAt(j)->getOptDepth()->getYAt(i);
                        core->getHorizSpectra()->getOptDepth()->setYAt(i, optDepth);
                    }
                }
            }

            // Calculating the total radiance
            radiance->calculateRadiance(core->getHorizSpectra()->getOptDepth(), core->getHorizSpectra()->getPlainRadiance(), core->getWavelengths()->getWns(), core->getParams()->getHorizParams()->getTemp());
            core->getHorizSpectra()->getPlainRadiance()->setMaxValue(Auxiliary::maximum(core->getHorizSpectra()->getPlainRadiance()->getY()));

            // Automatic recalculation of the maximum radiance scale (if applicable)
            // Calculating the maximum value if needed
            if (core->getYAxis()->getRadianceAutoRecalc())
            {
                power = (int) (log10(core->getHorizSpectra()->getPlainRadiance()->getMaxValue()));
                powValue = pow(10, power);
                if (core->getHorizSpectra()->getPlainRadiance()->getMaxValue() < (powValue * 0.5) ) { core->getYAxis()->setMaxRadiance(powValue * 0.5); }
                else { core->getYAxis()->setMaxRadiance(powValue); }
                emit maxYChanged();
            }            
        }
    }

    // This condition was introduced to prevent an error when the spectrum is blank
    // When a blank spectum is passed to the plotting routine, then program crashes
    if (m_spectrum.getY()->count() > 3)
    {
        // Sending the command to plot the accumulated spectra
        m_currSpecIndex = -2;
        emit currSpecIndexChanged();
        emit lineColorChanged();
        emit spectrumChanged();
    }
}

// Methods to update plot with the axes preserved
void SpectraResultsQml::updatePlotAllPreserveScale()
{
    setUpdateSpectra(false, true);
}
// Methods to get and set the update plot variable
void SpectraResultsQml::updatePlot()
{
    setUpdateSpectra(true, true);
}
// Method is used to upate the plot and keep the vertical and horizontal axis scale (this will also prevent the update of the total spectrum)
void SpectraResultsQml::updatePlotMolsOnlyPreserveScale()
{
    setUpdateSpectra(false, false);
}

// Updating the X and Y axis scale
void SpectraResultsQml::updateXAxis()
{
    m_minX = core->getWavelengths()->getStartWlCurrUnits();
    m_maxX = core->getWavelengths()->getEndWlCurrUnits();
    m_xAxisTitle = core->getWavelengths()->getAxisTitle();
    emit minXChanged();
    emit maxXChanged();
    emit xAxisTitleChanged();

    m_currSpecIndex = -2;  // Sending the command to plot the accumulated spectra
    emit currSpecIndexChanged();
    emit lineColorChanged();
    emit spectrumChanged();
}
void SpectraResultsQml::updateYAxis()
{
    m_minY = core->getYAxis()->getMinYPlot();
    m_maxY = core->getYAxis()->getMaxYPlot();
    m_yAxisTitle = core->getYAxis()->getYAxisTitle();
    emit minYChanged();
    emit maxYChanged();
    emit yAxisTitleChanged();

    m_currSpecIndex = -2;  // Sending the command to plot the accumulated spectra
    emit currSpecIndexChanged();
    emit lineColorChanged();
    emit spectrumChanged();
}
