// 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 determine the spectral regions to be requested from the remote server
// The difference between this object and the standard download regions finder is that here equidistant sub-regions are used and files are not merged
#include "normalizeddownloadregionsfinder.h"
#include <math.h>
#include <QDir>
#include <QLocale>
#include <QMessageBox>


NormalizedDownloadRegionsFinder::NormalizedDownloadRegionsFinder(QObject *parent) :
  QObject(parent)
{
    // Initializing the download step array with the spectral span information for the HITRAN online download
    downloadtSteps.resize(133);
    downloadtSteps[0] = 0;
    downloadtSteps[1] = 3;
    downloadtSteps[2] = 5;
    downloadtSteps[3] = 7;
    downloadtSteps[4] = 9;
    downloadtSteps[5] = 11;
    downloadtSteps[6] = 13;
    downloadtSteps[7] = 15;
    downloadtSteps[8] = 17;
    downloadtSteps[9] = 19;
    downloadtSteps[10] = 21;
    downloadtSteps[11] = 23;
    downloadtSteps[12] = 26;
    downloadtSteps[13] = 29;
    downloadtSteps[14] = 32;
    downloadtSteps[15] = 35;
    downloadtSteps[16] = 38;
    downloadtSteps[17] = 41;
    downloadtSteps[18] = 46;
    downloadtSteps[19] = 52;
    downloadtSteps[20] = 60;
    downloadtSteps[21] = 72;
    downloadtSteps[22] = 90;
    downloadtSteps[23] = 110;
    downloadtSteps[24] = 137;
    downloadtSteps[25] = 175;
    downloadtSteps[26] = 217;
    downloadtSteps[27] = 260;
    downloadtSteps[28] = 330;
    downloadtSteps[29] = 400;
    downloadtSteps[30] = 440;
    downloadtSteps[31] = 482;
    downloadtSteps[32] = 500;
    downloadtSteps[33] = 521;
    downloadtSteps[34] = 570;
    downloadtSteps[35] = 607;
    downloadtSteps[36] = 622;
    downloadtSteps[37] = 629;
    downloadtSteps[38] = 637;
    downloadtSteps[39] = 647;
    downloadtSteps[40] = 655;
    downloadtSteps[41] = 664;
    downloadtSteps[42] = 671;
    downloadtSteps[43] = 683;
    downloadtSteps[44] = 701;
    downloadtSteps[45] = 715;
    downloadtSteps[46] = 726;
    downloadtSteps[47] = 738;
    downloadtSteps[48] = 751;
    downloadtSteps[49] = 772;
    downloadtSteps[50] = 780;
    downloadtSteps[51] = 804;
    downloadtSteps[52] = 822;
    downloadtSteps[53] = 836;
    downloadtSteps[54] = 847;
    downloadtSteps[55] = 857;
    downloadtSteps[56] = 867;
    downloadtSteps[57] = 877;
    downloadtSteps[58] = 887;
    downloadtSteps[59] = 896;
    downloadtSteps[60] = 906;
    downloadtSteps[61] = 919;
    downloadtSteps[62] = 937;
    downloadtSteps[63] = 973;
    downloadtSteps[64] = 1005;
    downloadtSteps[65] = 1031;
    downloadtSteps[66] = 1056;
    downloadtSteps[67] = 1085;
    downloadtSteps[68] = 1121;
    downloadtSteps[69] = 1160;
    downloadtSteps[70] = 1194;
    downloadtSteps[71] = 1221;
    downloadtSteps[72] = 1247;
    downloadtSteps[73] = 1278;
    downloadtSteps[74] = 1304;
    downloadtSteps[75] = 1329;
    downloadtSteps[76] = 1354;
    downloadtSteps[77] = 1383;
    downloadtSteps[78] = 1419;
    downloadtSteps[79] = 1460;
    downloadtSteps[80] = 1510;
    downloadtSteps[81] = 1570;
    downloadtSteps[82] = 1650;
    downloadtSteps[83] = 1705;
    downloadtSteps[84] = 1760;
    downloadtSteps[85] = 1860;
    downloadtSteps[86] = 1930;
    downloadtSteps[87] = 2000;
    downloadtSteps[88] = 2050;
    downloadtSteps[89] = 2090;
    downloadtSteps[90] = 2150;
    downloadtSteps[91] = 2220;
    downloadtSteps[92] = 2275;
    downloadtSteps[93] = 2335;
    downloadtSteps[94] = 2440;
    downloadtSteps[95] = 2530;
    downloadtSteps[96] = 2660;
    downloadtSteps[97] = 2745;
    downloadtSteps[98] = 2825;
    downloadtSteps[99] = 2915;
    downloadtSteps[100] = 2980;
    downloadtSteps[101] = 3045;
    downloadtSteps[102] = 3130;
    downloadtSteps[103] = 3280;
    downloadtSteps[104] = 3420;
    downloadtSteps[105] = 3505;
    downloadtSteps[106] = 3595;
    downloadtSteps[107] = 3680;
    downloadtSteps[108] = 3800;
    downloadtSteps[109] = 3960;
    downloadtSteps[110] = 4090;
    downloadtSteps[111] = 4270;
    downloadtSteps[112] = 4470;
    downloadtSteps[113] = 4650;
    downloadtSteps[114] = 4825;
    downloadtSteps[115] = 4980;
    downloadtSteps[116] = 5175;
    downloadtSteps[117] = 5530;
    downloadtSteps[118] = 5970;
    downloadtSteps[119] = 6225;
    downloadtSteps[120] = 6435;
    downloadtSteps[121] = 6710;
    downloadtSteps[122] = 7025;
    downloadtSteps[123] = 7400;
    downloadtSteps[124] = 7900;
    downloadtSteps[125] = 8550;
    downloadtSteps[126] = 9300;
    downloadtSteps[127] = 10600;
    downloadtSteps[128] = 11600;
    downloadtSteps[129] = 13600;
    downloadtSteps[130] = 16000;
    downloadtSteps[131] = 20000;
    downloadtSteps[132] = 50000;
}

// Name of the file containing the history of downloads
QString NormalizedDownloadRegionsFinder::getSegmentedHitranPath() { return this->segmentedHitranPath; }
void NormalizedDownloadRegionsFinder::setSegmentedHitranPath(QString newSegmentedHitranPath) { this->segmentedHitranPath = newSegmentedHitranPath; }

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

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

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

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

// Method to get the start and end wavelengths from the region number
void NormalizedDownloadRegionsFinder::getWnFromRegionNum(int regionNum, double *startWn, double *endWn)
{
    *startWn = this->downloadtSteps[regionNum];
    *endWn = this->downloadtSteps[regionNum + 1];
}

// Method to determine the new download region based on the requested region and the data about the spectral ranges already downloaded
void NormalizedDownloadRegionsFinder::findDownloadRegions()
{
    QLocale loc;  // Object to convert to numbers from strings
    QDir dir(this->segmentedHitranPath);  // Directory object with the HITRAN segmented files
    QStringList files;  // List of files contained in the directory
    QStringList fileNameSplitList;  // Slpit list with the file name split into 3 parts (1 - segment number, 2 - start wavenumber, 3 - end wavenumber)
    int i;  // Loop variable
    int j;  // Loop variable
    QVector<int> downloadedSegmentNum;  // Segment numbers of the downloaded regions
    int segmentStartIndex = 0;  // Start index for the start wavenumber segment
    int segmentEndIndex;    // End index for the end wavenumber segment
    bool segmentFound;   // Variable indicates that the segment has already been downloaded
    double segmentStartWn;  // Rounded to integer start wavenumber
    double segmentEndWn;    // Rounded to integer end wavenumber


    // Initializing the arrays
    segmentsToDownload.resize(0);
    downloadFileNames.resize(0);
    downloadStartWn.resize(0);
    downloadEndWn.resize(0);

    // Getting the list of files already in the folder
    files = dir.entryList(QDir::NoDotAndDotDot | QDir::Files);

    // Determining the starting and ending segments covering the spectral range specified by the user
    i = 0;
    segmentStartWn = this->downloadtSteps[0];
    while (segmentStartWn <= this->startWn)
    {
        i++;
        segmentStartWn = this->downloadtSteps[i];

    }
    if (i > 0)
    {
        segmentStartIndex = i - 1;
        i--;
    }

    segmentStartWn = this->downloadtSteps[segmentStartIndex];
    segmentEndWn = segmentStartWn;
    while (segmentEndWn < this->endWn)
    {
        i++;
        segmentEndWn = this->downloadtSteps[i];
    }
    segmentEndIndex = i;
    segmentEndWn = this->downloadtSteps[segmentEndIndex];

    // Getting the indexes of the files already in place (to determine what needs to be downloaded)
    for (i = 0; i < files.count(); i++)
    {
        fileNameSplitList = files[i].split("-", QString::SkipEmptyParts);
        downloadedSegmentNum.append(loc.toInt(fileNameSplitList[0]));
    }

    // Determining which segments are to be downloaded (checking which segments are already present)
    for (i = segmentStartIndex; i < segmentEndIndex; i++)
    {
        segmentFound = false;
        for (j = 0; j < downloadedSegmentNum.count(); j++)
        {
            if (i == downloadedSegmentNum[j]) { segmentFound = true; }
        }
        if (segmentFound == false) { segmentsToDownload.append(i); }
    }

    // Forming the file names for the files to still be downloaded
    for (i = 0; i < segmentsToDownload.count(); i++)
    {
        getWnFromRegionNum(segmentsToDownload[i], &segmentStartWn, &segmentEndWn);
        this->downloadFileNames.append(QString::number(segmentsToDownload[i]) + " - " + QString::number(round(segmentStartWn)) + " - " + QString::number(round(segmentEndWn)) + ".par");

        // Appending to the download starting wavenumber array
        downloadStartWn.append(segmentStartWn);
        downloadEndWn.append(segmentEndWn);
    }

    // Emitting a signal indicating that the list of download regions has been formed
    emit downloadRegionsFormed();
}
// This method is to find the download grid for the download every time case
void NormalizedDownloadRegionsFinder::findDownloadEveryTmeRegions()
{
    int i;  // Loop variable
    int segmentStartIndex = 0;  // Start index for the start wavenumber segment
    int segmentEndIndex;    // End index for the end wavenumber segment
    double segmentStartWn;  // Rounded to integer start wavenumber
    double segmentEndWn;    // Rounded to integer end wavenumber


    // Resizing the start and end wavenumber grid arrays
    segmentsToDownload.resize(0);
    downloadStartWn.resize(0);
    downloadEndWn.resize(0);

    // Determining the starting and ending segments covering the spectral range specified by the user
    i = 0;
    segmentStartWn = this->downloadtSteps[0];
    while (segmentStartWn <= this->startWn)
    {
        i++;
        segmentStartWn = this->downloadtSteps[i];
    }
    if (i > 0)
    {
        segmentStartIndex = i - 1;
        i--;
    }
    segmentStartWn = this->downloadtSteps[segmentStartIndex];
    segmentEndWn = segmentStartWn;
    while (segmentEndWn < this->endWn)
    {
        i++;
        segmentEndWn = this->downloadtSteps[i];

    }
    segmentEndIndex = i;
    segmentEndWn = this->downloadtSteps[segmentEndIndex];

    // Determining which segments are to be downloaded (checking which segments are already present)
    for (i = segmentStartIndex; i < segmentEndIndex; i++)
    {
        segmentsToDownload.append(i);
    }

    // Forming the download region arrays
    for (i = 0; i < segmentsToDownload.count(); i++)
    {
        getWnFromRegionNum(segmentsToDownload[i], &segmentStartWn, &segmentEndWn);

        // Appending to the download starting wavenumber array
        downloadStartWn.append(segmentStartWn);
        downloadEndWn.append(segmentEndWn);
    }

    // Reassigning the start and end wavenumbers with the actual start and end wavenumbers (there could be cases when the values are too close to the start region)
    downloadStartWn[0] = this->startWn;
    downloadEndWn[downloadEndWn.count() - 1] = this->endWn;

    // Need to handle the case when the start Wn is too close to the end Wn for the initial and ending regions
}

// Method to get the file name for a given spectral region
QString NormalizedDownloadRegionsFinder::getFileNameAtIndex(int index)
{
    return this->downloadFileNames[index];
}
