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



// Object is used to handle the access and manipulation of the downlaod history file
// This approach is not currently in use and has known errors in the algorithm (does not work in all cases), not well structured
#include "downloadregionsfinder.h"
#include <QMessageBox>
#include <QTextStream>

DownloadRegionsFinder::DownloadRegionsFinder()
{
    ;
}

// Name of the file containing the history of downloads
QString DownloadRegionsFinder::getDownloadHistoryFilePath() { return this->downloadHistoryFilePath; }
void DownloadRegionsFinder::setDownloadHistoryFilePath(QString newDownloadHistoryFilePath) { this->downloadHistoryFilePath = newDownloadHistoryFilePath; }

// Methods to get and set the user specified and determined for the new download spectral region
double DownloadRegionsFinder::getStartWn() { return this->startWn; }
void DownloadRegionsFinder::setStartWn(double newStartWn) { this->startWn = newStartWn; }
double DownloadRegionsFinder::getEndWn() { return this->endWn; }
void DownloadRegionsFinder::setEndWn(double newEndWn) { this->endWn = newEndWn; }

QVector <double> *DownloadRegionsFinder::getDownloadStartWn() { return &(this->downloadStartWn); }
void DownloadRegionsFinder::setDownloadStartWn(QVector<double> *newDownloadStratWn) { this->downloadStartWn = *newDownloadStratWn; }
QVector <double> *DownloadRegionsFinder::getDownloadEndWn() { return &(this->downloadEndWn); }
void DownloadRegionsFinder::setDownloadEndWn(QVector<double> *newDownloadEndWn) { this->downloadEndWn = *newDownloadEndWn; }

// Methods to get and set the download regions at a specified index
double DownloadRegionsFinder::getDownloadStartWnValueAtIndex(int index) { return this->downloadStartWn[index]; }
void DownloadRegionsFinder::setDownloadStartWnValueAtIndex(int index, double value) { this->downloadStartWn[index] = value; }
double DownloadRegionsFinder::getDownloadEndWnValueAtIndex(int index) { return this->downloadEndWn[index]; }
void DownloadRegionsFinder::setDownloadEndWnValueAtIndex(int index, double value) { this->downloadEndWn[index] = value; }

// Array with the new wavenumbers for the new updated download history file
int DownloadRegionsFinder::getIndexStartWnInHistory() { return this->indexStartWnInHistory; }  // Starting index for the new download region determined from the history file data
void DownloadRegionsFinder::setIndexStartWnInHistory(int newIndexStartWnInHistory) { this->indexStartWnInHistory = newIndexStartWnInHistory; }
int DownloadRegionsFinder::getIndexEndWnInHistory() { return this->indexEndWnInHistory; }    // Ending index for the new download region determined from the history file data
void DownloadRegionsFinder::setIndexEndWnInHistory(int newIndexEndWnInHistory) { this->indexEndWnInHistory = newIndexEndWnInHistory; }

// Very beginning wavenumber for the spectral regions to download
double DownloadRegionsFinder::getDownloadVeryStartWn() { return this->downloadVeryStartWn; }
// Very end wavenumber for the spectral regions to download
double DownloadRegionsFinder::getDownloadVeryEndWn() { return this->downloadVeryEndWn; }

// Method to read the download history data from file
void DownloadRegionsFinder::readDownloadHistoryFile()
{
    QFile historyFile;  // Path to the file containing the history of HITRAN database downloads
    QString historyFileContents;  // String with the entire contents of the history file
    QStringList historyFileList;  // String list with the split line data of the downlaoded spectral regions
    QStringList startEndSplitList;   // List with the string representations of the start and end wavenumbers of a download region
    QLocale c;  // Variable used to convert from string representation to numerical representation
    int i;  // Loop variable


    // Check the download history file to determine the spectral regions currently available
    // Reading all data from the download history file and saving it to the start and end arrays
    historyFile.setFileName(this->downloadHistoryFilePath);
    this->historyStartWn.resize(0);
    this->historyEndWn.resize(0);
    if (historyFile.open(QIODevice::ReadOnly))
    {
        QTextStream in(&historyFile);
        historyFileContents = in.readAll();
        historyFileList = historyFileContents.split("\n", QString::SkipEmptyParts);
        this->historyStartWn.resize(historyFileList.count());
        this->historyEndWn.resize(historyFileList.count());

        for (i = 0; i < historyFileList.count(); i++)
        {
            startEndSplitList = historyFileList[i].split("-");
            this->historyStartWn[i] = c.toDouble(startEndSplitList[0]);
            this->historyEndWn[i] = c.toDouble(startEndSplitList[1]);
        }
        historyFile.close();
    }
}

// Method to determine the new download region based on the requested region and the data about the spectral ranges already downloaded
void DownloadRegionsFinder::findDownloadRegions()
{
    int iStart;  // The very beginning index
    int iEnd;    // The very end index
    int i;  // Loop variable

    // Condition variable to be used in comparative statements
    bool condition1;
    bool condition2;
    bool condition3;
    bool condition4;


    // This is too much of a convoluted algorithm, need to come up with something better than this
    // Replace later with something more efficient and less bulky with fewer if statements
    // Need to simply scan though the values similar to the algorithm used to write out values into the updated download history file

    // Nullifying the arrays with the download regions
    downloadStartWn.resize(0);
    downloadEndWn.resize(0);

    // Determining the boundary for the very lowest user specified wavenumer (edge boundary)
    downloadVeryStartWn = -1;
    iStart = 0;
    i = 0;
    while ((downloadVeryStartWn < 0) && (i < historyStartWn.count()))
    {
        if (startWn < historyStartWn[i]) { downloadVeryStartWn = startWn;  iStart = i; }
        if ((startWn >= historyStartWn[i]) && (startWn <= historyEndWn[i])) { downloadVeryStartWn = historyEndWn[i];  iStart = i + 1; }

        // Incrementing the index to switch to the next spectral region
        i++;
    }
    if (downloadVeryStartWn < 0) { downloadVeryStartWn = startWn; }

    // Determining the boundary for the very highest user specified wavenumer (edge boundary)
    downloadVeryEndWn = -1;
    iEnd = 0;
    i = historyEndWn.count() - 1;
    // Descending motion
    while ((downloadVeryEndWn < 0) && (i >= iStart))
    {
        if ((endWn >= historyStartWn[i]) && (endWn <= historyEndWn[i])) { downloadVeryEndWn = historyStartWn[i];  iEnd = i - 1; }
        if (endWn > historyEndWn[i]) { downloadVeryEndWn = endWn;  iEnd = i;  }

        // Incrementing to switch to the next spectral region
        i--;
    }
    if (downloadVeryEndWn < 0) { downloadVeryEndWn = endWn; }

    // Going from the beginning to the end indexes and adding in the intermediate region download wavenumbers into the array of beginning and ending wavenumbers
    // Handle the cases when the staring or ending region is not overlaping the old one but rather
    // If both the starting and the ending regions of the calculation range are smaller than the minimum wavenumber of the history downloads
    condition1 = (startWn < historyStartWn[0]);
    condition2 = (endWn < historyStartWn[0]);
    condition3 = (startWn > historyStartWn[historyStartWn.count() - 1]);
    condition4 = (endWn > historyStartWn[historyEndWn.count() - 1]);
    if (condition1 && condition2)
    {
        downloadStartWn.append(startWn);
        downloadEndWn.append(endWn);
    }
    else if (condition3 && condition4)  // If both the start and the end wavenumbers for the newly specified region are higher than the history download maximum wavenumber
    {
        downloadStartWn.append(startWn);
        downloadEndWn.append(endWn);
    }
    else if (downloadVeryStartWn != downloadVeryEndWn)
    {
        // If at least one of the newly specified wavenumbers (start or end) lies withing the old spectral region (history download region)
        downloadStartWn.append(downloadVeryStartWn);
        if (historyStartWn.length() > 0)
        {
            for (i = iStart; i <= iEnd; i++) {
                downloadEndWn.append(historyStartWn[i]);
                downloadStartWn.append(historyEndWn[i]);
            }
        }
        downloadEndWn.append(downloadVeryEndWn);
    }
}

// Method to update the download history file
void DownloadRegionsFinder::updateDownloadHistoryFile()
{
    // Saving the data to the download history file    
    QFile historyFile;    // Path to the file containing the history of HITRAN database downloads
    double currWn;   // Current wavenumber value
    int i;   // Loop variable


    // Check the download history file to determine the spectral regions currently available
    // Reading all data from the download history file and saving it to the start and end arrays
    historyFile.setFileName(this->downloadHistoryFilePath);
    if (historyFile.open(QIODevice::WriteOnly))
    {
        QTextStream out(&historyFile);


        // Updating the history file
        // Processing the segment before the very start wavenumber
        // Only going though this algorithm if the length of the file is larger than zero, otherwise
        // writing a fresh file with only one region present (better algorithm could probably be written)
        currWn = historyStartWn[0];
        i = 0;
        while ((currWn < startWn) && (i < (historyStartWn.count())))
        {
            out << currWn;  out << " - ";
            if (historyEndWn[i] < startWn) { out << historyEndWn[i]; out << "\n"; }
            i++;
            currWn = historyStartWn[i];
        }
        // Writing out the starting wavenumber if the end wavenumber is smaller than the start wavenumber
        i--;
        if (historyEndWn[i] <= startWn) { out << startWn; out << " - "; }

        // Scanning forward until after we reach the end wavenumber value and writing out the end wavenumber value specified by the user or the end wavenumber value for the current spectral sub-region
        while ((endWn >= historyEndWn[i]) && (endWn > historyStartWn[i]) && (i < (historyStartWn.count()))) { i++; }
        i--;  // Decrementing so that the comparison is with the correct spectral sub-region
        if ( historyEndWn[i] <= endWn ) { out << endWn;  out << "\n"; }
        else { out << historyEndWn[i];  out << "\n"; }

        // Scanning through values until after we reach the end of the dataset (start to end spectral sub-regions)
        i++;
        while (i < historyStartWn.count())
        {
            out << historyStartWn[i];  out << " - ";
            out << historyEndWn[i];  out << "\n";
            i++;
        }

        // Closing the file
        historyFile.close();
    }
}
