text: /*
   * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
   *
   * This file is part of Orfeo Toolbox
   *
   *     https://www.orfeo-toolbox.org/
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  #include "otbSpectralSensitivityReader.h"
  
  #include <fstream>
  #include <algorithm>
  #include <cctype>
  #include "otb_boost_string_header.h"
  #include "itksys/SystemTools.hxx"
  
  #include "itkMacro.h"
  
  namespace otb
  {
  SpectralSensitivityReader::SpectralSensitivityReader() : m_FileName(""), m_DataPath("")
  {
    this->Superclass::SetNumberOfRequiredOutputs(1);
    this->Superclass::SetNthOutput(0, WavelengthSpectralBandVectorType::New().GetPointer());
  }
  
  SpectralSensitivityReader::~SpectralSensitivityReader()
  {
  }
  
  SpectralSensitivityReader::WavelengthSpectralBandVectorType* SpectralSensitivityReader::GetOutput()
  {
    if (this->GetNumberOfOutputs() < 1)
    {
      return nullptr;
    }
    return static_cast<WavelengthSpectralBandVectorType*>(this->ProcessObject::GetOutput(0));
  }
  
  const SpectralSensitivityReader::WavelengthSpectralBandVectorType* SpectralSensitivityReader::GetOutput() const
  {
    if (this->GetNumberOfOutputs() < 1)
    {
      return nullptr;
    }
    return static_cast<const WavelengthSpectralBandVectorType*>(this->ProcessObject::GetOutput(0));
  }
  
  void SpectralSensitivityReader::FindFileName()
  {
    std::string        sensor("");
    std::ostringstream oss;
  
    if (!m_ImageMetadata->Has(MDStr::SensorID)
        || !m_ImageMetadata->Has(MDStr::Instrument)
        || !m_ImageMetadata->Has(MDStr::InstrumentIndex))
    {
      itkExceptionMacro(<< "Cannot decode the filename from the input metadata: " 
                        << *m_ImageMetadata);
    }
  
    sensor = (*m_ImageMetadata)[MDStr::SensorID];
  
    sensor = itksys::SystemTools::UpperCase(sensor);
    // Suppress spaces
    sensor.erase(std::remove_if(sensor.begin(), sensor.end(), isspace), sensor.end());
  
    oss.str("");
    oss << (*m_ImageMetadata)[MDStr::Instrument];
    oss << (*m_ImageMetadata)[MDStr::InstrumentIndex];
  
    std::string instrument = oss.str();
  
    oss.str("");
    oss << m_DataPath;
    oss << "/";
    oss << sensor;
    oss << "/";
    oss << instrument;
    oss << "/rep6S.dat";
  
    m_FileName = oss.str();
  }
  
  void SpectralSensitivityReader::GenerateData()
  {
    if (m_FileName == "")
      this->FindFileName();
  
    WavelengthSpectralBandVectorType* wavelengthSpectralBand = this->GetOutput();
  
    if (!itksys::SystemTools::FileExists(m_FileName))
    {
      itkExceptionMacro(<< m_FileName << " does not exist.");
    }
  
    std::ifstream file(m_FileName);
    if (!file)
      itkExceptionMacro(<< "Enable to read " << m_FileName << " file.");
  
    std::string line;
    double      mini      = 0;
    double      maxi      = 0.;
    bool        firstLine = true;
  
    unsigned int nbBands = 0;
    // used to store the coef
    std::vector<ValuesVectorType> valuesVector;
  
    while (std::getline(file, line))
    {
      // Replace any tabulation by a space
      std::string::size_type tabpos = line.find('\t');
      while (tabpos != std::string::npos)
      {
        line.at(tabpos) = ' ';
        tabpos          = line.find('\t');
      }
  
      // Replace multiple spaces by a unique space
      std::unique(line.begin(), line.end(), SpectralSensitivityReader::BothAre(' '));
  
      // if the first character is a space, erase it
      boost::trim(line);
      std::vector<std::string> keywordStrings;
      boost::split(keywordStrings, line, boost::is_any_of(" "));
  
      if (keywordStrings.size() < 3)
        itkExceptionMacro(<< "Invalid file format");
  
      // Store min wavelength
      if (firstLine)
      {
        mini    = atof(keywordStrings[0].c_str());
        nbBands = keywordStrings.size() - 2;
  
        for (unsigned int j = 0; j < nbBands; ++j)
        {
          wavelengthSpectralBand->PushBack(FilterFunctionValues::New());
          ValuesVectorType temp;
          valuesVector.push_back(temp);
        }
        firstLine = false;
      }
  
      if (nbBands != keywordStrings.size() - 2)
        itkExceptionMacro(<< "Invalid file format");
  
      for (unsigned int i = 0; i < nbBands; ++i)
      {
        valuesVector[i].push_back(atof(keywordStrings[i + 2].c_str()));
      }
  
      maxi = atof(keywordStrings[0].c_str());
    } // while ( std::getline( file, line ) )
  
    for (unsigned int j = 0; j < nbBands; ++j)
    {
      wavelengthSpectralBand->GetNthElement(j)->SetFilterFunctionValues(valuesVector[j]);
      wavelengthSpectralBand->GetNthElement(j)->SetMinSpectralValue(mini);
      wavelengthSpectralBand->GetNthElement(j)->SetMaxSpectralValue(maxi);
    }
  }
  
  /**PrintSelf method */
  void SpectralSensitivityReader::PrintSelf(std::ostream& os, itk::Indent indent) const
  {
    os << "DataPath: " << m_DataPath << std::endl;
    if (m_FileName != "")
      os << "FileName: " << m_FileName << std::endl;
  
    // Function values print :
    const WavelengthSpectralBandVectorType* wavelengthSpectralBand = this->GetOutput();
    os << "Filter function values: " << std::endl;
    for (unsigned int i = 0; i < wavelengthSpectralBand->Size(); ++i)
    {
      os << indent << "Channel " << i + 1 << " : " << std::endl;
      os << indent << wavelengthSpectralBand->GetNthElement(i) << std::endl;
    }
  }
  
  } // end namespace otb
  