/***************************** LICENSE START ***********************************

 Copyright 2013 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

/******************************************************************************

    The MvRttov class loads and parses an output file from the RTTOV model.
    A skeleton of such a file looks like:


 # RTTOV OUTPUT
  -----------------
  Instrument iasi
  -----------------
  ... <parameter lines>
  ... <parameter lines>
2m air parameters
  param_name (units)   value
  param_name (units)   value
  ...
  <blank line>
  <other lines>

 OUTPUT: CHANNEL BRIGHTNESS TEMPERATURE       EMISSIVITY:

            1    218.8644864351669        0.9531080000000000
            2    218.8867066300515        0.9531470000000000
            .... <more lines of output>
 <blank lines>
 JACOBIANS:
  0.0000E+00           1           2           3  ...
  0.1000E-01 -0.2195E-14 -0.5583E-14 -0.2388E-12  ...


******************************************************************************/


#include <algorithm>
#include <fstream>
#include <sstream>
#include "fstream_mars_fix.h"

#include "MvRttov.h"
#include "TableReader.h"

using namespace metview;

MvRttov::MvRttov()
{
    fileName_ = "NO FILE SPECIFIED";
    currentLine_ = 0;
}


MvRttov::~MvRttov() = default;


// ----------------------------------------------------------------------
// MvRttov::searchForLineContainingString
// Reads line after line of text from the given input stream and stops
// when it finds the given string (and returns true) or when it reaches
// the end of the file (and returns false).
// ----------------------------------------------------------------------

bool MvRttov::searchForLineContainingString(std::ifstream& ifs, std::string& str)
{
    std::string line;
    bool found = false;
    while (!found && !ifs.eof()) {
        getline(ifs, line);
        currentLine_++;
        if (line.find(str) != std::string::npos)  // does this line match the given string?
        {
            found = true;
        }
    }
    return true;
}


// ----------------------------------------------------------------------
// MvRttov::parseFile
// Reads the given file into memory and stores structured information
// and data from it. If it returns false, then errorMessage() should be
// called in order to obtain the reason for the failure.
// ----------------------------------------------------------------------

bool MvRttov::parseFile(std::string& fileName)
{
    fileName_ = fileName;

    // open the file
    std::ifstream in(fileName.c_str());

    if (!in) {
        errorMsg_ = "Unable to read file " + fileName;
        return false;
    }


    // look for the start of the tb data

    std::string headerString = "OUTPUT:";
    bool found = searchForLineContainingString(in, headerString);

    if (!found)  // could not find the start of the data?
    {
        errorMsg_ = "Could not find label '" + headerString + "' in file";
        return false;
    }


    // now we're at the start of the data, keep reading each line until we
    // get to a blank line (or eof)

    std::string line;
    getline(in, line);  // first, skip the blank line between the header and the data
    currentLine_++;

    int channel = 0;
    double tb, emis;
    bool endOfData = false;
    while (!endOfData && !in.eof()) {
        getline(in, line);  // first, skip the blank line between the header and the data
        currentLine_++;
        std::istringstream iss(line);
        if (iss >> channel)  // any valid data on this line?
        {
            iss >> tb;
            iss >> emis;
            channels_.push_back(channel);
            tbs_.push_back(tb);
        }
        else {
            endOfData = true;
        }
    }


    // ----- look for the start of the Jacobian data -----

    headerString = "JACOBIANS:";
    found = searchForLineContainingString(in, headerString);

    if (!found)  // could not find the start of the data?
    {
        errorMsg_ = "Could not find label '" + headerString + "' in file";
        return false;
    }


    // use the Table Reader to parse the table of Jacobians

    TableReader tableReader(fileName);
    tableReader.setDelimiter(' ');
    tableReader.setHeaderRow(currentLine_ + 1);
    tableReader.setConsecutiveDelimitersAsOne(true);

    std::string errorMsg;
    bool ret = 0;

    ret = tableReader.getMetaData(errorMsg);

    if (!ret) {
        errorMsg_ = errorMsg;
        return false;
    }

    std::vector<std::string>& colNames = tableReader.fieldNames();


    // for each column, create a vector to hold its values and tell the Table Reader
    // that this vector should store the values for that column

    std::string emptyString;
    jacobians_.reserve(colNames.size());
    for (size_t i = 0; i < colNames.size(); i++) {
        std::vector<double> vd;
        jacobians_.push_back(vd);
        tableReader.setFieldContainer(i, emptyString, jacobians_[jacobians_.size() - 1], -99999);
    }


    // read the data from the file

    ret = tableReader.read(errorMsg);

    if (!ret) {
        errorMsg_ = errorMsg;
        return false;
    }


    // reverse the arrays of data so that the bottom pressure level is first
    // (so that the default visualisation has the vertical axis the 'right way up'

    for (size_t i = 0; i < colNames.size(); i++) {
        std::vector<double>& vd = jacobians_[i];
        reverse(vd.begin(), vd.end());
    }


    return true;
}
