// 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 is used to relay the atmospheric model information betweeen the C++ data objects and the QML interface
#include "atmospherelistviewmodel.h"
#include <QLocale>
#include <QMessageBox>

AtmosphereListViewModel::AtmosphereListViewModel(QObject *parent, BytranCore *inCore) :  QAbstractListModel(parent)
{
    int i;  // Loop variable
    QString text;
    QString itemName;


    // Auxiliary object
    aux = new Auxiliary();

    // Passing in the core module
    core = inCore;
    m_modelNum = core->getAtm()->getAtiveAtmModelNum(); // Pass the object instead
    m_selectedItem = 0;

    // Adding the standard Total pressure, ,temperature and air density components
    this->addElement(AtmosphereListView(0, "  Press."));
    this->addElement(AtmosphereListView(1, "  Temp."));
    this->addElement(AtmosphereListView(2, "  Dens."));

    // Populating the data list with the molecule elements initialized form the internally saved values or from an external file
    for (i = 0; i < core->getParams()->getMol()->count(); i++)
    {
        // Displaying the molecular infromation for each molecular record (not all parameters are displayed) as saved into the internal data structure
        text = QString::number(i + 1);
        if (text.count() < 2) { text = "  " + text; }
        itemName = "  " + core->getParams()->getMolAt(i)->getChemForm();
        this->addElement(AtmosphereListView(i + 3, itemName));
    }

    // Connections
    connect(this->core, SIGNAL(applyCurrentAtmModel()), this, SLOT(setUpdatedValues()));

    // Updating the spectrum
    updateSpectrum();
}

// Slot is used to update all values in the corresponding QML dialog
void AtmosphereListViewModel::setUpdatedValues()
{
    // Assigning a new atmospheric model value
    assignNewValues();
}

Spectrum AtmosphereListViewModel::spectrum() const
{
    return m_spectrum;
}

double AtmosphereListViewModel::minX() const { return m_minX; }
void AtmosphereListViewModel::setMinX(const double &minX)
{
    if (minX != m_minX)
    {
        m_minX = minX;
        emit minXChanged();
    }
}
double AtmosphereListViewModel::maxX() const { return m_maxX; }
void AtmosphereListViewModel::setMaxX(const double &maxX)
{
    if (maxX != m_maxX)
    {
        m_maxX = maxX;
        emit maxXChanged();
    }
}
double AtmosphereListViewModel::minY() const { return m_minY; }
void AtmosphereListViewModel::setMinY(const double &minY)
{
    if (minY != m_minY)
    {
        m_minY = minY;
        emit minYChanged();
    }
}
double AtmosphereListViewModel::maxY() const { return m_maxY; }
void AtmosphereListViewModel::setMaxY(const double &maxY)
{
    if (maxY != m_maxY)
    {
        m_maxY = maxY;
        emit maxYChanged();
    }
}

// Methods related to the assignment of new values to the values of pressure, temperature and partial pressures (molecules)
void AtmosphereListViewModel::assignNewValues()
{
    // Assigning new values to the total pressure, temperature and partial pressure
    // Initializing the parameters for the horizontal path
    core->getParams()->initHorizPathParamsFromStandardAtmModel(core->getAtm()->getActiveAtmModel());
}

// Title for the horizontal axis
QString AtmosphereListViewModel::xAxisTitle() { return this->m_xAxisTitle; }
void AtmosphereListViewModel::setXAxisTitle(const QString &xAxisTitle)
{
    if (xAxisTitle != m_xAxisTitle)
    {
        this->m_xAxisTitle = xAxisTitle;
        emit xAxisTitleChanged();
    }
}

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

quint8 AtmosphereListViewModel::modelNum() const
{
    return m_modelNum;
}
void AtmosphereListViewModel::setModelNum(const quint8 &modelNum)
{
    QLocale c;  // Object to convert strings into numerical variables


    if (modelNum != m_modelNum)
    {
        m_modelNum = modelNum;        
        // Only the horizontal path mode is available at this point
        // Need to convert the value to meters (default units)
        core->getAtm()->setActiveAtmModelNum(m_modelNum);

        // Updating the spectrum displayed
        updateSpectrum();
    }
}

int AtmosphereListViewModel::selectedItem() const
{
    return m_selectedItem;
}
void AtmosphereListViewModel::setSelectedItem(const int &selectedItem)
{
    if (selectedItem != m_selectedItem)
    {
        m_selectedItem = selectedItem;

        // Updating the spectrum
        updateSpectrum();
    }
}

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

// Method to update the plot according to the currently selected plot index
void AtmosphereListViewModel::plotSpectrum()
{
    // Plotting the currently selected spectrum
    updateSpectrum();
}

// Method to update the spectrum displayed
void AtmosphereListViewModel::updateSpectrum()
{
    // Setting the current spectrum index
    m_currSpecIndex = -1;
    emit currSpecIndexChanged();
    emit lineColorChanged();
    emit spectrumChanged();

    if (m_selectedItem == 0)
    {
        // Getting the spectrum for the atmospehric model
        m_lineColor = "#ff0000";
        m_spectrum = *(core->getAtm()->getActiveAtmModel()->getTotalPress());
        m_xAxisTitle = "Total pressure, mbar";
        m_minX = 0;
        m_maxX = core->getAtm()->getActiveAtmModel()->getTotalPress()->getX()->last();
        m_minY = 0; // aux->minimum(core->getAtm()->getActiveAtmModel()->getTotalPress()->getY());
        m_maxY = aux->maximum(core->getAtm()->getActiveAtmModel()->getTotalPress()->getY());        
    }
    else if (m_selectedItem == 1)
    {
        // Getting the spectrum for the atmospehric model
        m_lineColor = "#ff0000";
        m_xAxisTitle = "Temperature, Kelvin";
        m_spectrum = *(core->getAtm()->getActiveAtmModel()->getTemp());
        m_minX = 0;
        m_maxX = core->getAtm()->getActiveAtmModel()->getTemp()->getX()->last();
        m_minY = 0; // aux->minimum(core->getAtm()->getActiveAtmModel()->getTemp()->getY());
        m_maxY = aux->maximum(core->getAtm()->getActiveAtmModel()->getTemp()->getY());
    }
    else if (m_selectedItem == 2)
    {
        // Getting the spectrum for the atmospehric model
        m_lineColor = "#ff0000";
        m_xAxisTitle = "Air density, cm-3";
        m_spectrum = *(core->getAtm()->getActiveAtmModel()->getDensity());
        m_minX = 0;
        m_maxX = core->getAtm()->getActiveAtmModel()->getDensity()->getX()->last();
        m_minY = 0; // aux->minimum(core->getAtm()->getActiveAtmModel()->getDensity()->getY());
        m_maxY = aux->maximum(core->getAtm()->getActiveAtmModel()->getDensity()->getY());
    }
    else if ((m_selectedItem - 3) < core->getAtm()->getActiveAtmModel()->getPartPressArray()->count())
    {
        m_lineColor = "#ff0000";
        m_spectrum  = *(core->getAtm()->getActiveAtmModel()->getPartPressSpecByMolIndex(m_selectedItem - 3));
        m_xAxisTitle = "Concentration of " + core->getParams()->getMolAt(m_selectedItem - 3)->getChemForm() + ", cm-3";
        m_minX = 0;
        m_maxX = core->getAtm()->getActiveAtmModel()->getPartPressSpecByMolIndex(m_selectedItem - 3)->getX()->last();
        m_minY = 0; // aux->minimum(core->getAtm()->getActiveAtmModel()->getPartPressSpecByMolIndex(m_selectedItem - 3)->getY());
        m_maxY = aux->maximum(core->getAtm()->getActiveAtmModel()->getPartPressSpecByMolIndex(m_selectedItem - 3)->getY());
    }

    // Emitting signals indicating that the model and the spectrum have been changed
    emit modelNumChanged();
    emit xAxisTitleChanged();
    emit minXChanged();
    emit maxXChanged();
    emit minYChanged();
    emit maxYChanged();

    m_currSpecIndex = 0;
    emit currSpecIndexChanged();
    emit lineColorChanged();
    emit spectrumChanged();
    m_currSpecIndex = -2;
    emit currSpecIndexChanged();
    emit lineColorChanged();
    emit spectrumChanged();
}

AtmosphereListView::AtmosphereListView(const int &index, const QString &itemName)
     : m_index(index), m_itemName(itemName)
{
}

int AtmosphereListView::index() const
{ return m_index; }

QString AtmosphereListView::itemName() const
{ return m_itemName; }

void AtmosphereListViewModel::addElement(const AtmosphereListView &atmListView)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_atmListView << atmListView;
    endInsertRows();
}

int AtmosphereListViewModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_atmListView.count();
}

QVariant AtmosphereListViewModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() >= m_atmListView.count())
        return QVariant();

    const AtmosphereListView &atmListView = m_atmListView[index.row()];
    if (role == itemNameRole)
        return atmListView.itemName();
    return QVariant();
}

// Method to set the data when the values in the model are modified
bool AtmosphereListViewModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    emit dataChanged(index, index);
    return true;
}

//![0]
QHash<int, QByteArray> AtmosphereListViewModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[itemNameRole] = "itemName";
    return roles;
}
//![0]

// Need to update the model and synch data etc.
