// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | contact@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
#include "bytrancore.h"
#include <QLocale>
#include <QMessageBox>
#include <QStringList>
#include <QStandardPaths>
#include <QDir>
#include <QFileInfo>
#include <QQmlProperty>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QApplication>
#include <QTimer>
#include <QTime>
#include <QDateTime>
#include <QThread>
#include <QScreen>
#include <QtGlobal>
#include <QGuiApplication>
#include "custommessagebox.h"

BytranCore::BytranCore(QObject *parent) : QObject(parent)
{   
    QString cumulativeHitranFolder;  // Folder to contain the cumulative HITRAN file
    QString segmentedHitranFolder;   // Folder to contain the downloaded segmented HITRAN files
    QString dataSaveFolder;          // Folder to save the data to
    QString shareFolder;  // Folder for the image and data file to be shared
    QStringList files;    // List of files to be found in a directory
    QFileInfo info;       // Object to get information about a file
    QDir dir;  // diractory variable
    int i;     // Loop variable


    // For Documents and Downloads folder access the approach described in the below link should be used
    // http://stackoverflow.com/questions/23340398/how-to-access-downloads-folder-in-windows-phone-8-1
    // https://msdn.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations
    // https://www.microsoft.com/en-us/store/p/files/9wzdncrfj3pl
    // http://doc.qt.io/qt-5/qstandardpaths.html

    // Variable indicating that the calculation is not running
    calculationRunning = true;

    // Setting the default text size (in the settings for the iOS)
    this->m_iPhone = false;
    #if defined(Q_OS_IOS)

        // Initializing and setting the default text size (for iOS only)
        iosTextSize = new iosDefaultTextSize();
        this->m_iPhone = iosTextSize->isIPhone();

    #endif

    // Setting a variable indicating that TIPS initialization is complete
    this->tipsInitComplete = false;

    // Object to request permissions from the Android system
    permissions = new Permissions();
    // Requesting permissions
    permissions->requestPermissions();

    // Test variable to change the interface depending on whether access to external storage has been allowed
    // At the start assuming that no permissions have been granted
    this->m_externalStorageAccessGranted = false;
    emit externalStorageAccessGrantedChanged();

    // Setting up the application directory
    QString applicationPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    dir.setPath(applicationPath);
    if (!dir.exists())
        dir.mkpath(applicationPath);  // This does not require a permission

    // Initializing the horizontal path layer parameters to the default values
    par = new Params();

    // Initializing the HITRAN downloader (setting the default internal variables)
    hitranDownloader = new HitranOnlineDownloader(this);
    hitranDownloader->setHitranHostName("http://hitran.org");
    hitranDownloader->setHitranEmail("userName");
    hitranDownloader->setHitranPassword("password");
    hitranDownloader->setHitranLoginHost("http://hitran.org/login/");
    hitranDownloader->setUserAuthen(false);
    hitranDownloader->setMolparamDownloadPath("http://hitran.org/media/molparam.txt");
    hitranDownloader->setMolparamFolder(applicationPath);
    hitranDownloader->getTipsDownloader()->setTipsDownloadPath("http://hitran.org/data/Q/");
    hitranDownloader->getTipsDownloader()->setTipsFolder(hitranDownloader->getMolparamFolder() + "/TIPS");
    hitranDownloader->getTipsDownloader()->setTipsMaxIndex(121);

    // Creating connections
    createActionsEarly();

    // Checking the presence of the molparam.txt file and loading data if it is present, otherwise downloading
    info.setFile(hitranDownloader->getMolparamFolder() + "/molparam.txt");
    if (!info.exists())
    {
         // Sending a command to download the molparam.txt file
         hitranDownloader->downloadMolparamTxt();
    }
    else
    {
         // Need to modify this later to load data from the molparam.txt file
         loadMolParam();
    }

    // Creating TIPS sub-directory if it does not exist
    dir.setPath(hitranDownloader->getTipsDownloader()->getTipsFolder());
    if (!dir.exists())
        dir.mkpath(hitranDownloader->getTipsDownloader()->getTipsFolder());  // This does not require a permission

    hitranDownloader->setDownloadHistoryFile("hitranDownloadHistory.txt");  // Not used anymore but is present from the past
    hitranDownloader->setHitranFileUsage(0);  // Default is download HITRAN and save locally
    hitranDownloader->setSubrangeRecordsStep(20000);

    // Initializing the object and reading in the default atmospheric models
    atmos = new Atmosphere();
    atmos->setMaxNumMols(par->getMol()->count());  // Read in from the parameters variable (corresponding to the number of molecules available in the HITRAN database)
    atmos->initInternalAfglModels();
    atmos->setActiveAtmModelNum(5);  // Setting the default to US Standard 1976 atmosphere

    // Initializing the parameters for the horizontal path
    par->initHorizPathParamsFromStandardAtmModel(atmos->getActiveAtmModel());
    par->setHitranUnits(true);

    // Initializing the sensors object
    sensors = new Sensors(this, this->getParams()->getHorizParams());
    sensors->setSampligPeriod(200);
    sensors->setNumSamplesToAverage(5);

    // Initializing the object to contain the calculated horizontal path spectra
    horizSpectra = new OneLayerSpectra();

    // Objcet with the parameters related to the vertical axis units
    yaxis = new YAxis();

    // Objects used to convert data between different units
    concPressConverter = new ConcPressUnitsConvert();
    concPressConverter->setPressUnits(0);
    concPressConverter->setConcUnits(0);
    temperatureConverter = new TemperatureUnitsConvert();
    temperatureConverter->setUnits(0);
    pathlengthConverter = new PathlengthUnitsConvert();
    pathlengthConverter->setUnits(1);

    // Setting the default wavelengths and the spectral resolutions
    wavelength = new Wavelength();
    wavelength->setUnits(1);
    wavelength->setStartWn(2000);
    wavelength->setEndWn(2300);
    wavelength->setNumPoints(10000);

    // Initializing an object with the instrument functions
    instrFunct = new InstrumentalFunction();

    // Initializing the line-by-line object (to carry out the line-by-line calculations)
    lbl = new Lbl(this, this->hitranDownloader);
    lbl->setParams(this->par);
    lbl->setWavelength(wavelength);
    lbl->setHorizSpec(this->horizSpectra);

    // Object used for saving the results of the calculations
    resultsSaver = new ResultsSaver();

    // Creating connections
    createActionsLate();

    #if defined(Q_OS_ANDROID)
        // Saving the state of the variable indicating if access to the external storage is possible
        if (!(permissions->getIsMarshmallowOrAbove())) {
            this->m_externalStorageAccessGranted = true;  // If the Android operating system is below Marshmallow, then the system will automatically grant permissions
        }
        else {
            if (permissions->getPermissionGranted() == 1)
                { this->m_externalStorageAccessGranted = true; }
            if ((permissions->getPermissionGranted() == 0) || (permissions->getPermissionGranted() == 2))
                { this->m_externalStorageAccessGranted = false; }
        }
        emit externalStorageAccessGrantedChanged();
    #elif defined(Q_OS_LINUX)
        this->m_externalStorageAccessGranted = true;
    #elif defined(Q_OS_WIN32)
        this->m_externalStorageAccessGranted = true;
    #elif defined(Q_OS_WIN64)
        this->m_externalStorageAccessGranted = true;
    #elif defined(Q_OS_WINRT)
        this->m_externalStorageAccessGranted = false;
    #elif defined(Q_OS_MAC)
        this->m_externalStorageAccessGranted = true;
    #else
        this->m_externalStorageAccessGranted = false;  // If not under Android, then the external storage granted state is set to false
    #endif

    // Object to save and load the configuration to / from the configuration file
    configIo = new ConfigInputOutput();
    // Setting the objects to save and load the configuration data to / from
    configIo->setObjects(this->wavelength,
                         this->par,
                         this->atmos,
                         this->instrFunct,
                         this->hitranDownloader,
                         this->temperatureConverter,
                         this->pathlengthConverter,
                         this->concPressConverter,
                         this->yaxis,
                         this->sensors);

    // By default the HITRAN downloads will be stored in the internal application folder (only under Android saving under other location is possible)
    QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    // By default the data folder is within the internal application folder path
    QString documentsFolder = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/results";
    dataSaveFolder = documentsFolder;   // Preparing the folder to save the data to

    // Using the Downloads folder if possible, or otherwise using the internal storage (not visible) to store the configuation file
    if (this->m_externalStorageAccessGranted == true)  // Permission to access the Documents and Downloads folder has been granted, this is only applicable to Android and the desktop systems
    {
        // Under android it is possible to save to the Downloads folder if proper permissions are granted (as an alternative to the application folder)
        downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/bytran";

        // Getting the documents folder path, preparing the folder to save the data to
        documentsFolder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);  // Probably need to move this closer to where the bytran subfolder is created
        dataSaveFolder = documentsFolder + "/bytran";  // This might require a permission for this operation to be performed
    }

    // Creating the HITRAN cumulative file directory
    cumulativeHitranFolder = downloadsFolder;
    dir.setPath(cumulativeHitranFolder);
    if (!dir.exists())
        dir.mkpath(cumulativeHitranFolder);  // This may require a permission
    hitranDownloader->setCumulativeHitranPath(cumulativeHitranFolder);

    // Creating a HITRAN segmented files sub-directory
    segmentedHitranFolder = downloadsFolder + "/HITRAN-downloads";
    dir.setPath(segmentedHitranFolder);
    if (!dir.exists())
        dir.mkpath(segmentedHitranFolder);  // This may require a permission
    hitranDownloader->setSegmentedHitranPath(segmentedHitranFolder);

    // Setting variables related to the download and usage of the HITRAN database ()
    // Getting the list of files already in the folder
    dir.setPath(cumulativeHitranFolder);
    files = dir.entryList(QDir::NoDotAndDotDot | QDir::Files);
    if (files.count() == 0) { hitranDownloader->setCumulativeHitranFile("HITRAN2012.par"); }
    for (i = 0; i < files.count(); i++)
    {
        info.setFile(files[i]);
        if (info.completeSuffix() == "par") {
            hitranDownloader->setCumulativeHitranFile(info.completeBaseName() + "." + info.completeSuffix()); }
        else {
            hitranDownloader->setCumulativeHitranFile("HITRAN2012.par"); }
    }

    // Creating the data save folder
    dir.setPath(dataSaveFolder);
    if (!dir.exists())
        dir.mkpath(dataSaveFolder);

    // Setting the results saver path
    resultsSaver->setSavePath(dataSaveFolder);

    // Need to clean up of all these PNG and data files saved in the internal storage (on program startup is easier as opposed to right away)
    // This could be done immediately after the file is emailed, but this approach is easier to implement (taking into
    // account that this is more of an exception case when the permission is not granted, this could be improved later)

    // Need to have this cleaned after an email is sent (for those cases when the access to data is impossible)
//    QDir dir(resultsSaver->getSavePath());
//    dir.setNameFilters(QStringList() << "*.*");
//    dir.setFilter(QDir::Files);
//    foreach(QString dirFile, dir.entryList())
//    {
//        dir.remove(dirFile);
//    }

    // Setting the configuration file path
    configIo->setConfigFilePath(downloadsFolder + "/" + "config.txt");

    // Introducing a  delay nere for Marshmallow (to give extra time to process that permission request)
    // Without this delay here the configuration file would not read for some reason (permission is inactive or something)
    if(permissions->getIsMarshmallowOrAbove())
    {
        // Based on this suggestion: http://stackoverflow.com/questions/3752742/how-do-i-create-a-pause-wait-function-using-qt
        QTime waitTillTime = QTime::currentTime().addMSecs(500);
        while (QTime::currentTime() < waitTillTime)
        {
            QApplication::processEvents();
        }
    }

    // Checking if the configuration file exists and loading the file if it exists
    info.setFile(configIo->getConfigFilePath());
    if (info.exists()) { configIo->loadToConfig(); }

    // Setting the molecules array to the HITRAN downloader object
    hitranDownloader->setMolArray(par->getMol());

    // Variable indicating that the calculation is not running
    calculationRunning = false;
}

// Method is used to read in the molparam data and download the TIPS files
void BytranCore::loadMolParam()
{
    // Rading data from the downloaded molparam file, this was disabled as this would occur too late any way
    par->readMolparamFileContents(hitranDownloader->getMolparamFolder() + "/molparam.txt");

    // Once loading of the molecular parameters is complete, the rest of initialization
    // is carried out through a signal - slot by running downloadTips();
}

// Method to download files with the Total Internal Partition Sums
void BytranCore::downloadTips()
{
    QDir dir;  // Directory variable

    // Requesting TIPS file download or else reading in TIPS data
    dir.setPath(hitranDownloader->getTipsDownloader()->getTipsFolder());
    if (dir.entryList(QDir::Files | QDir::NoDotAndDotDot).count() >= 116)  // Should come up with a better way in the future
    {
        // Loading the TIPS files
        loadTips();
    }
    else
    {
        // Hiding the notification window
        emit notify("", 0, false, false);

        // Sending a command to download TIPS files (if the files are already present on the local device, they will not be downloaded again)
        hitranDownloader->downloadTipsFiles();

        // Loading TIPS files is carried out through a signal - slot connection by calling loadTips
    }
}

// Method is used to read in Total Internal Partition Sums (TIPS) and all the remaining program data and initialize it
void BytranCore::loadTips()
{
    
    // Informing the user that the TIPS data is being loaded
    emit notify("Loading downloaded TIPS data.", 0, true, false);

    // Setting the TIPS folder and reading the TIPS data from the corresponding files
    par->setTipsFolder( hitranDownloader->getTipsDownloader()->getTipsFolder());
    par->read2016HitranOnlineTipsFilesContents();

    // Hiding the notification window
    emit notify("", 0, false, false);

    // Setting a variable indicating that TIPS initialization is complete
    this->tipsInitComplete = true;
}

// Creating connections earlier for things to be implemented first
void BytranCore::createActionsEarly()
{
    connect(this->hitranDownloader, SIGNAL(molparamTxtDownloadComplete()), this, SLOT(loadMolParam()));
    connect(this->hitranDownloader, SIGNAL(tipsDownloadComplete()), this, SLOT(loadTips()));
    connect(this->par, SIGNAL(readingMolParamsComplete()), this, SLOT(downloadTips()));
}

// Method to create actions to be accessed later than the inital TIPS and molparam initializiations
void BytranCore::createActionsLate()
{
    connect(this->hitranDownloader, SIGNAL(hitranDownloadComplete()), this, SLOT(calculateLineByLine()));
    connect(this->lbl, SIGNAL(notify(QString, double, bool, bool)), this, SIGNAL(notify(QString, double, bool, bool)));
    connect(this->lbl, SIGNAL(updateSpectra(bool, bool)), this, SIGNAL(updateSpectra(bool, bool)));
    connect(this->lbl, SIGNAL(calculationComplete()), this, SLOT(postCalculation()));
    connect(this->hitranDownloader, SIGNAL(notify(QString, double, bool, bool)), this, SIGNAL(notify(QString, double, bool, bool)));
    connect(this->hitranDownloader, SIGNAL(hitranDownloadUnsuccessful()), this, SLOT(postCalculation()));
    connect(this->hitranDownloader, SIGNAL(openOkDialog(QString)), this, SLOT(displayOkDialog(QString)));
    connect(this->par, SIGNAL(notify(QString, double, bool, bool)), this, SIGNAL(notify(QString, double, bool, bool)));
    connect(this->instrFunct, SIGNAL(openOkDialog(QString)), this, SLOT(displayOkDialog(QString)));
}

// Method to send a notification to the user
void BytranCore::displayNotification(QString message, double value, bool visible, bool cancelButtonVisible)
{
    // Letting the user know that the HITRAN database download is about to be carried out
    emit notify(message, value, visible, cancelButtonVisible);
    QApplication::processEvents();
}
void BytranCore::hideNotification()
{
    // Letting the user know that the HITRAN database download is about to be carried out
    emit notify("", 0, false, true);
    QApplication::processEvents();
}

// Methods to read the height of the plot
bool BytranCore::externalStorageAccessGranted() const { return this->m_externalStorageAccessGranted; }

// Method indicates if the application is executed on an iPhone
bool BytranCore::iPhone() const { return this->m_iPhone; }

// Method to access the total pressure units converter
ConcPressUnitsConvert *BytranCore::getConcPressUnitsConverter() { return this->concPressConverter; }
TemperatureUnitsConvert *BytranCore::getTemperatureUnitsConverter() { return this->temperatureConverter; }
PathlengthUnitsConvert *BytranCore::getPathlengthUnitsConverter() { return this->pathlengthConverter; }
Wavelength *BytranCore::getWavelengths() { return this->wavelength; }
ResultsSaver *BytranCore::getResultsSaver() { return this->resultsSaver; }
ConfigInputOutput *BytranCore::getConfigIO() { return this->configIo; }
Sensors *BytranCore::getSensors() { return this->sensors; }

// Method to get the horizontal path spectra
OneLayerSpectra *BytranCore::getHorizSpectra() { return this->horizSpectra; }

// Methods to retrieve and set the HITRAN downloader object
HitranOnlineDownloader *BytranCore::getHitranDownloader() { return this->hitranDownloader; }
void BytranCore::setHitranDownloader(HitranOnlineDownloader *newHitranDownloader) { this->hitranDownloader = newHitranDownloader; }

// Invokable method to save the configuration to a file
void BytranCore::saveConfiguration()
{
    // Saving configuration parameters to a configuration file
    configIo->saveToConfig();

    // Disabling the sensors so that manual parameter be restored in the configuration file
    sensors->setEnableTotalPressureSensor(false);
    sensors->setEnableTemperatureSensor(false);
    sensors->setEnableHumiditySensor(false);
}

// Invokable method to cancel the calculation
void BytranCore::cancelCalculation()
{
    lbl->setCancelCalculation(true);
    hitranDownloader->setCancelCalculation(true);
    QApplication::processEvents();
}

// Slot to run the calculation
void BytranCore::calculate()
{
    if (this->tipsInitComplete == false)  // This is triggered if no TIPS files are present in the system
    {
        this->displayOkDialog("TIPS files unavailable. Please restart\nbytran when connected to internet\nto download TIPS from HITRAN.org");
    }
    else
    {
        if (calculationRunning == false)
        {
            // Stopping the sensor updates
            sensors->stopTimer();

            // Setting the variable indicating that the calculation is not to be canceled initially
            lbl->setCancelCalculation(false);
            hitranDownloader->setCancelCalculation(false);

            // Variable indicating that the calculation is running
            calculationRunning = true;

            // Indicating that the download is initiated by the calculation button press (this is to avoid triggering the line-by-line calculation when the complete HITRAN download is carried out)
            calcButtonPressed = true;

            // Setting the line-by-line variable letting the unit know to run the calculation (no cancelation)
            lbl->setCancelCalculation(false);

            // Setting the molecules array to the downloader (done to initiate HITRAN database download quiery)
            hitranDownloader->setMolArray(this->getParams()->getMol());

            // Determining if HITRAN download is necessary and if so downloading the missing HITRAN database data
            hitranDownloader->setStartWn(wavelength->getStartWn());
            hitranDownloader->setEndWn(wavelength->getEndWn());
            hitranDownloader->getHitranData();  // The download is only done if there are missing spectral regions

            // The above will only download the missing data from HITRAN online, it will not segment read the data
            // Segment reading is used to take into accout the large amount of data contained in the HITRAN database
            // This way the number or records being processed for a large calculation spectral range does not
            // overload the memory

            // The remaining line-by-line calculations are carried out through a signal-slot connection
        }
    }
}

// Slot executed to calculate the line-by-line after the download of the HITRAN database is over
void BytranCore::calculateLineByLine()
{
    if (calcButtonPressed)  // This is to block a signal trigering this slot when HITRAN data is downloaded (for selected usage options)
    {
        // Here an optimization may be done (not very important) to avoid double data read if the data has
        // already been accessed during hitran.org requests, this optimization will only be useful if the data
        // needs to be requested from HITRAN online.
        hitranDownloader->getHitranRecordBoundaries();
        lbl->setHitranDownloader(this->hitranDownloader);

        // Running line-by-line calculations
        lbl->calculateHorizPath();
    }
}

// Method is used to run post-calculation tasks
void BytranCore::postCalculation()
{
    // Saving the calculation parameter into the results saver class
    resultsSaver->setTemperature(par->getHorizParams()->getTemp());
    resultsSaver->setTotalPress(par->getHorizParams()->getTotalPress());
    resultsSaver->setPathlength(par->getHorizParams()->getPathLength());
    resultsSaver->setSelectedAndNames(par->getMol());
    resultsSaver->setPartPress(par->getHorizParams()->getPartPressArray());
    resultsSaver->setData(horizSpectra);
    resultsSaver->setWavelength(wavelength);

    // Removing all read in HITRAN records from memory
    hitranDownloader->getHitranRecs()->resize(0);

    // Clearing the notification area
    emit notify("", 0, false, true);
    QApplication::processEvents();

    // Appending spectra to the plot (one spectrum for the total and multiple spectra for the individal molecules)
    // Emitting a signal notifying that the spectrum needs to be updated
    emit updateSpectra(true, true);
    QApplication::processEvents();

    // Restarting the sensor updates
    sensors->startTimer();

    calculationRunning = false;
    calcButtonPressed = false;
}

// Method to get the paramters
Params *BytranCore::getParams() { return this->par; }

// Method to get the currently active atmospheric model
Atmosphere *BytranCore::getAtm() { return this->atmos; }

// Method to get a reference to the object with the vertical axis units
YAxis *BytranCore::getYAxis() { return this->yaxis; }

// Method to get a reference to an instrument function object
InstrumentalFunction *BytranCore::getInstrFunct() { return this->instrFunct; }

// Methods to get and set the default font related paramters (font point size and the height of the label)
qreal BytranCore::defaultFontPointSize() const { return this->m_defaultFontPointSize; }
void BytranCore::setDefaultFontPointSize(qreal const defaultFontPointSize)
{
    if (defaultFontPointSize != m_defaultFontPointSize)
    {
        m_defaultFontPointSize = defaultFontPointSize;
        emit defaultFontPointSizeChanged();
    }
}
int BytranCore::defaultLabelHeight() const { return this->m_defaultLabelHeight; }
void BytranCore::setDefaultLabelHeight(int const defaultLabelHeight)
{
    if (defaultLabelHeight != m_defaultLabelHeight)
    {
        m_defaultLabelHeight = defaultLabelHeight;
        emit defaultLabelHeightChanged();
    }
}
qreal BytranCore::fontScalingRatio() const { return this->m_fontScalingRatio; }
void BytranCore::setFontScalingRatio(qreal const fontScalingRatio)
{
    if (fontScalingRatio != m_fontScalingRatio)
    {
        m_fontScalingRatio = fontScalingRatio;
        emit fontScalingRatioChanged();
    }
}

// Methods to get and set the text to be displayed in the Ok dialog
QString BytranCore::okDialogText() const { return this->m_okDialogText; }
void BytranCore::setOkDialogText(QString const okDialogText)
{
    if (okDialogText != m_okDialogText)
    {
        m_okDialogText = okDialogText;
        emit okDialogTextChanged();
    }
}

// Slot to open an Ok dialog
void BytranCore::displayOkDialog(QString okDialogText) {

    setOkDialogText(okDialogText);

    // This is in case the iOS native dialog is desired (not sure maybe native dialogs will be pulled automatically now for iOS not sure)
    //    // Object to show a custom message box
    //    CustomMessageBox customMessageBox;

    //    customMessageBox.setTitleAndText("No data to save", "No calculation has been performed.\nThere are no data to save.");
    //    customMessageBox.show();
}
