/*
 * 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 "otbFormosatImageMetadataInterface.h"

#include "otbMacro.h"
#include "otbMath.h"
#include "itkMetaDataObject.h"
#include "otbImageKeywordlist.h"
#include "otbStringUtils.h"

namespace otb
{

FormosatImageMetadataInterface::FormosatImageMetadataInterface()
{
}

bool FormosatImageMetadataInterface::CanRead() const
{
  std::string sensorID = GetSensorID();
  if (sensorID.find("Formosat") != std::string::npos)
    return true;
  else
    return false;
}

std::string FormosatImageMetadataInterface::GetInstrument() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (imageKeywordlist.HasKey("support_data.instrument"))
  {
    std::string valueString = imageKeywordlist.GetMetadataByKey("support_data.instrument");
    return valueString;
  }

  return "";
}

unsigned int FormosatImageMetadataInterface::GetInstrumentIndex() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (imageKeywordlist.HasKey("support_data.instrument_index"))
  {
    std::string  valueString = imageKeywordlist.GetMetadataByKey("support_data.instrument_index");
    unsigned int value       = atoi(valueString.c_str());
    return value;
  }

  return -1; // Invalid value
}

FormosatImageMetadataInterface::VariableLengthVectorType FormosatImageMetadataInterface::GetSolarIrradiance() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  std::vector<double> outputValues;
  if (imageKeywordlist.HasKey("support_data.solar_irradiance"))
  {
    std::vector<std::string> outputValuesString;
    std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.solar_irradiance");
    boost::trim(valueString);
    boost::split(outputValuesString, valueString, boost::is_any_of(" "));
    for (unsigned int i = 0; i < outputValuesString.size(); ++i)
    {
      outputValues.push_back(atof(outputValuesString[i].c_str()));
    }
  }

  VariableLengthVectorType outputValuesVariableLengthVector;
  outputValuesVariableLengthVector.SetSize(outputValues.size());
  outputValuesVariableLengthVector.Fill(0);
  // In the case of SPOT, the bands are in a different order:
  // XS3, XS2. XS1, SWIR in the tif file.
  if (outputValues.size() == 1)
  {
    // this is a PAN image
    outputValuesVariableLengthVector[0] = outputValues[0];
  }
  else if (outputValues.size() == 4)
  {
    outputValuesVariableLengthVector[0] = outputValues[2];
    outputValuesVariableLengthVector[1] = outputValues[1];
    outputValuesVariableLengthVector[2] = outputValues[0];
    outputValuesVariableLengthVector[3] = outputValues[3];
  }
  else
  {
    itkExceptionMacro("Invalid Solar Irradiance");
  }

  return outputValuesVariableLengthVector;
}

int FormosatImageMetadataInterface::GetDay() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.image_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.image_date");
  std::vector<std::string> outputValues;

  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Day");

  int value = atoi(outputValues[2].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetMonth() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.image_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.image_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Month");

  int value = atoi(outputValues[1].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetYear() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.image_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.image_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Year");

  int value = atoi(outputValues[0].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetHour() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.image_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.image_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() < 4)
    itkExceptionMacro(<< "Invalid Hour");

  int value = atoi(outputValues[3].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetMinute() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.image_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.image_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() < 5)
    itkExceptionMacro(<< "Invalid Minute");

  int value = atoi(outputValues[4].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetProductionDay() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.production_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.production_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Day");

  int value = atoi(outputValues[2].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetProductionMonth() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.production_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.production_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Month");

  int value = atoi(outputValues[1].c_str());
  return value;
}

int FormosatImageMetadataInterface::GetProductionYear() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.production_date"))
  {
    return -1;
  }

  std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.production_date");
  std::vector<std::string> outputValues;
  boost::split(outputValues, valueString, boost::is_any_of(" T:-"));

  if (outputValues.size() <= 2)
    itkExceptionMacro(<< "Invalid Year");

  int value = atoi(outputValues[0].c_str());
  return value;
}

FormosatImageMetadataInterface::VariableLengthVectorType FormosatImageMetadataInterface::GetPhysicalBias() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  std::vector<double> outputValues;
  if (imageKeywordlist.HasKey("support_data.physical_bias"))
  {
    std::vector<std::string> outputValuesString;
    std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.physical_bias");
    boost::trim(valueString);
    boost::split(outputValuesString, valueString, boost::is_any_of(" "));
    for (unsigned int i = 0; i < outputValuesString.size(); ++i)
    {
      outputValues.push_back(atof(outputValuesString[i].c_str()));
    }
  }

  VariableLengthVectorType outputValuesVariableLengthVector;
  outputValuesVariableLengthVector.SetSize(outputValues.size());
  outputValuesVariableLengthVector.Fill(0);
  // In the case of FORMOSAT-2, the bands are in a different order:
  // XS3, XS2. XS1, SWIR in the tif file.

  if (outputValues.size() == 1)
  {
    // this is a PAN image
    outputValuesVariableLengthVector[0] = outputValues[0];
  }
  else if (outputValues.size() == 4)
  {
    outputValuesVariableLengthVector[0] = outputValues[2];
    outputValuesVariableLengthVector[1] = outputValues[1];
    outputValuesVariableLengthVector[2] = outputValues[0];
    outputValuesVariableLengthVector[3] = outputValues[3];
  }
  else
  {
    itkExceptionMacro("Invalid Physical Bias");
  }

  return outputValuesVariableLengthVector;
}

FormosatImageMetadataInterface::VariableLengthVectorType FormosatImageMetadataInterface::GetPhysicalGain() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  std::vector<double> outputValues;
  if (imageKeywordlist.HasKey("support_data.physical_gain"))
  {
    std::vector<std::string> outputValuesString;
    std::string              valueString = imageKeywordlist.GetMetadataByKey("support_data.physical_gain");
    boost::trim(valueString);
    boost::split(outputValuesString, valueString, boost::is_any_of(" "));
    for (unsigned int i = 0; i < outputValuesString.size(); ++i)
    {
      outputValues.push_back(atof(outputValuesString[i].c_str()));
    }
  }

  VariableLengthVectorType outputValuesVariableLengthVector;
  outputValuesVariableLengthVector.SetSize(outputValues.size());
  outputValuesVariableLengthVector.Fill(0);
  // In the case of SPOT, the bands are in a different order:
  // XS3, XS2. XS1, SWIR in the tif file.

  if (outputValues.size() == 1)
  {
    // this is a PAN image
    outputValuesVariableLengthVector[0] = outputValues[0];
  }
  else if (outputValues.size() == 4)
  {
    outputValuesVariableLengthVector[0] = outputValues[2];
    outputValuesVariableLengthVector[1] = outputValues[1];
    outputValuesVariableLengthVector[2] = outputValues[0];
    outputValuesVariableLengthVector[3] = outputValues[3];
  }
  else
  {
    itkExceptionMacro("Invalid Physical Gain");
  }

  return outputValuesVariableLengthVector;
}

double FormosatImageMetadataInterface::GetSatElevation() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.incident_angle"))
  {
    return 0;
  }

  std::string valueString = imageKeywordlist.GetMetadataByKey("support_data.incident_angle");
  double      value       = 90 - atof(valueString.c_str());
  return value;
}

double FormosatImageMetadataInterface::GetSatAzimuth() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  if (!imageKeywordlist.HasKey("support_data.incident_angle"))
  {
    return 0;
  }

  std::string valueString = imageKeywordlist.GetMetadataByKey("support_data.sat_azimuth_angle");
  double      satAz       = atof(valueString.c_str());

  // In some software version, a bug exists.
  // We have to check the version t correct the satellite azimuth angle contained in the metadata
  std::string softVersion = imageKeywordlist.GetMetadataByKey("support_data.software_version");

  if ((softVersion == "R2P_02.03.P1") || (softVersion == "R2P_02.02") || (softVersion == "R2P_02.03"))
  {
    if (!imageKeywordlist.HasKey("support_data.viewing_angle_across_track"))
    {
      return 0;
    }
    if (!imageKeywordlist.HasKey("support_data.viewing_angle_along_track"))
    {
      return 0;
    }
    if (!imageKeywordlist.HasKey("support_data.scene_orientation"))
    {
      return 0;
    }

    valueString = imageKeywordlist.GetMetadataByKey("support_data.viewing_angle_across_track");
    double viewingAngleAcrossTrack(atof(valueString.c_str()));
    valueString = imageKeywordlist.GetMetadataByKey("support_data.viewing_angle_along_track");
    double viewingAngleAlongTrack(atof(valueString.c_str()));
    valueString = imageKeywordlist.GetMetadataByKey("support_data.scene_orientation");
    double sceneOrientation(atof(valueString.c_str()));

    double alpha = std::atan(std::tan(viewingAngleAcrossTrack * CONST_PI_180) / std::tan(viewingAngleAlongTrack * CONST_PI_180)) * CONST_180_PI;

    if (viewingAngleAlongTrack < 0)
    {
      if (alpha > 0)
      {
        alpha = alpha - 180;
      }
      else
      {
        alpha = alpha + 180;
      }
    }

    alpha -= sceneOrientation;
    if (alpha > 0)
    {
      satAz += 180;
    }
    else
    {
      satAz = 180 - satAz;
    }
  }

  return satAz;
}

FormosatImageMetadataInterface::VariableLengthVectorType FormosatImageMetadataInterface::GetFirstWavelengths() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid metadata, no Formosat2 Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  VariableLengthVectorType wavel(1);
  wavel.Fill(0.);

  int         nbBands  = this->GetNumberOfBands();
  std::string sensorId = this->GetSensorID();

  // Panchromatic case
  if (nbBands == 1)
  {
    wavel.SetSize(1);
    // FIXME that's definitely NOT correct in a formosat file!!!
    if (sensorId == "SPOT4")
      wavel.Fill(0.610);
    else if (sensorId == "SPOT5")
      wavel.Fill(0.480);
    else
      itkExceptionMacro(<< "Invalid Formosat2 Sensor ID");
  }
  else if (nbBands > 1 && nbBands < 5)
  {
    wavel.SetSize(4);
    // FIXME is that supposed to correspond to the bands in the files?
    wavel[0] = 0.500;
    wavel[1] = 0.610;
    wavel[2] = 0.780;
    wavel[3] = 1.580;
  }
  else
    itkExceptionMacro(<< "Invalid number of bands...");

  return wavel;
}

FormosatImageMetadataInterface::VariableLengthVectorType FormosatImageMetadataInterface::GetLastWavelengths() const
{
  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid metadata, no Formosat2 Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  VariableLengthVectorType wavel(1);
  wavel.Fill(0.);

  int         nbBands  = this->GetNumberOfBands();
  std::string sensorId = this->GetSensorID();

  // Panchromatic case
  if (nbBands == 1)
  {
    wavel.SetSize(1);
    if (sensorId == "SPOT4")
      wavel.Fill(0.680);
    else if (sensorId == "SPOT5")
      wavel.Fill(0.710);
    else
      itkExceptionMacro(<< "Invalid Formosat2 Sensor ID");
  }
  else if (nbBands > 1 && nbBands < 5)
  {
    // FIXME is that supposed to correspond to the bands in the files?
    wavel.SetSize(4);
    wavel[0] = 0.590;
    wavel[1] = 0.680;
    wavel[2] = 0.890;
    wavel[3] = 1.750;
  }
  else
    itkExceptionMacro(<< "Invalid number of bands...");

  return wavel;
}

unsigned int FormosatImageMetadataInterface::BandIndexToWavelengthPosition(unsigned int i) const
{
  otbMsgDevMacro(<< "Formosat2 detected: band 0 and 2 inverted");
  if (i == 0)
    return 2;
  if (i == 2)
    return 0;
  return i;
}

std::vector<unsigned int> FormosatImageMetadataInterface::GetDefaultDisplay() const
{
  std::vector<unsigned int> rgb(3);
  rgb[0] = 0;
  rgb[1] = 1;
  rgb[2] = 2;
  return rgb;
}

FormosatImageMetadataInterface::WavelengthSpectralBandVectorType FormosatImageMetadataInterface::GetSpectralSensitivity() const
{
  WavelengthSpectralBandVectorType wavelengthSpectralBand = InternalWavelengthSpectralBandVectorType::New();
  std::list<std::vector<float>>    tmpSpectralBandList;

  const MetaDataDictionaryType& dict = this->GetMetaDataDictionary();
  if (!this->CanRead())
  {
    itkExceptionMacro(<< "Invalid Metadata, no Formosat Image");
  }

  ImageKeywordlistType imageKeywordlist;

  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
  {
    itk::ExposeMetaData<ImageKeywordlistType>(dict, MetaDataKey::OSSIMKeywordlistKey, imageKeywordlist);
  }

  int         nbBands  = this->GetNumberOfBands();
  std::string sensorId = this->GetSensorID();

  // Panchromatic case
  if (nbBands == 1)
  {
    const float b0[281] = {
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.000219376f, 0.000219425f, 0.000231534f, 0.000284519f, 0.000550079f,
        0.001f,       0.003f,       0.006f,       0.012f,      0.0235f,      0.035f,       0.043f,       0.0503893f,   0.0525f,      0.055f,       0.0565f,
        0.058f,       0.059f,       0.059f,       0.0608594f,  0.061f,       0.0615f,      0.062f,       0.063f,       0.063f,       0.064f,       0.063f,
        0.064f,       0.065f,       0.066f,       0.066f,      0.066f,       0.066f,       0.0675f,      0.069f,       0.0708104f,   0.0709615f,   0.0709001f,
        0.071f,       0.0715f,      0.073f,       0.074f,      0.074f,       0.073f,       0.073f,       0.0735f,      0.075f,       0.0765f,      0.078f,
        0.078f,       0.078f,       0.0785f,      0.0800145f,  0.0815f,      0.083f,       0.083f,       0.083f,       0.083f,       0.083f,       0.0835f,
        0.085f,       0.0865f,      0.087f,       0.088f,      0.087f,       0.087f,       0.088f,       0.0885f,      0.0907023f,   0.0915f,      0.092f,
        0.092f,       0.092f,       0.092f,       0.093f,      0.094f,       0.095f,       0.096f,       0.096f,       0.096f,       0.095f,       0.095f,
        0.095f,       0.095f,       0.096f,       0.0975f,     0.098f,       0.099f,       0.099f,       0.098f,       0.098f,       0.0965f,      0.096f,
        0.0965f,      0.098f,       0.0985f,      0.099f,      0.0995f,      0.099f,       0.0975f,      0.097f,       0.0955f,      0.095f,       0.095f,
        0.095f,       0.0965f,      0.097f,       0.098f,      0.098f,       0.0975f,      0.097f,       0.096f,       0.095f,       0.095f,       0.094f,
        0.094f,       0.095f,       0.0955f,      0.096f,      0.097f,       0.097f,       0.097f,       0.097f,       0.097f,       0.097f,       0.096f,
        0.097f,       0.097f,       0.097f,       0.098f,      0.098f,       0.096f,       0.095f,       0.094f,       0.093f,       0.092f,       0.091f,
        0.0905658f,   0.089f,       0.089f,       0.089f,      0.088f,       0.088f,       0.0875f,      0.087f,       0.086f,       0.085f,       0.084f,
        0.083f,       0.0825f,      0.082f,       0.081f,      0.081f,       0.0804051f,   0.079f,       0.078f,       0.077f,       0.077f,       0.076f,
        0.075f,       0.074f,       0.0735f,      0.073f,      0.0725f,      0.072f,       0.071f,       0.071f,       0.0704136f,   0.069f,       0.0685f,
        0.068f,       0.067f,       0.066f,       0.0645f,     0.063f,       0.062f,       0.0607892f,   0.059f,       0.058f,       0.057f,       0.056f,
        0.0545f,      0.052f,       0.0455f,      0.038f,      0.0286994f,   0.0202138f,   0.0125f,      0.007f,       0.004f,       0.002f,       0.001f,
        0.000909856f, 0.000512159f, 0.000357051f, 0.00029112f, 0.000215752f, 0.000187213f, 0.000171918f, 0.000169724f, 0.000166392f, 0.000163058f, 0.000159726f,
        0.000156393f, 0.000153061f, 0.000149728f, 0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,         0.0f,         0.0f,        0.0f,         0.0f};

    // add panchromatic band to the temporary list
    const std::vector<float> vb0(b0, b0 + sizeof(b0) / sizeof(float));
    tmpSpectralBandList.push_back(vb0);
  }
  else if (nbBands > 1 && nbBands < 5)
  {
    const float b1[281] = {
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.000354959f, 0.000354603f, 0.000376745f, 0.000478212f, 0.0009718f,  0.002f,
        0.005f, 0.0124297f, 0.024f, 0.0415f, 0.057f, 0.0685f, 0.074f, 0.074f,  0.076f,       0.0795695f,   0.082f,       0.084f,       0.083f,      0.0825f,
        0.086f, 0.0910953f, 0.094f, 0.096f,  0.096f, 0.094f,  0.094f, 0.096f,  0.099f,       0.0995f,      0.099f,       0.098f,       0.095f,      0.092f,
        0.095f, 0.0985f,    0.092f, 0.0695f, 0.037f, 0.025f,  0.009f, 0.0025f, 0.001f,       0.000847053f, 0.000588401f, 0.00051966f,  0.00050602f, 0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,        0.0f,
        0};

    const float b2[281] = {
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.000324677f, 0.000326475f, 0.000331943f, 0.000386303f,
        0.000447683f, 0.001f,  0.003f, 0.0045f,    0.012f, 0.0205f, 0.036f,       0.0615f,      0.075f,       0.081f,       0.082f,       0.0845f,
        0.087f,       0.0885f, 0.088f, 0.087f,     0.086f, 0.0875f, 0.0908484f,   0.0925f,      0.094f,       0.094f,       0.093f,       0.0925f,
        0.093f,       0.0955f, 0.097f, 0.098f,     0.099f, 0.099f,  0.099f,       0.099f,       0.099f,       0.099f,       0.095f,       0.0815f,
        0.057f,       0.032f,  0.018f, 0.0112534f, 0.005f, 0.0015f, 0.000758484f, 0.000604297f, 0.000512471f, 0.000475316f, 0.000453283f, 0.00044559f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0.0f,   0.0f,    0.0f,         0.0f,         0.0f,         0.0f,         0.0f,         0.0f,
        0.0f,         0.0f,    0.0f,   0.0f,       0};

    const float b3[281] = {
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.000461752f,
        0.001f, 0.001f,  0.003f, 0.006f,     0.013f, 0.0335f,    0.063f, 0.089f,  0.098f, 0.099f,  0.099f, 0.099f,  0.099f,       0.0985f,
        0.097f, 0.0945f, 0.092f, 0.0906796f, 0.089f, 0.0907659f, 0.093f, 0.0965f, 0.1f,   0.097f,  0.091f, 0.0865f, 0.086f,       0.0910438f,
        0.094f, 0.092f,  0.093f, 0.088f,     0.064f, 0.034f,     0.015f, 0.0075f, 0.006f, 0.0045f, 0.003f, 0.001f,  0.000607601f, 0.000202927f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0.0f,   0.0f,    0.0f,   0.0f,       0.0f,   0.0f,       0.0f,   0.0f,    0.0f,   0.0f,    0.0f,   0.0f,    0.0f,         0.0f,
        0};

    const float b4[281] = {0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.000481456f,
                           0.00071923f,
                           0.00098303f,
                           0.001f,
                           0.000947915f,
                           0.00090899f,
                           0.000887367f,
                           0.000576847f,
                           0.000470858f,
                           0.00052246f,
                           0.000713811f,
                           0.001f,
                           0.0015f,
                           0.003f,
                           0.005f,
                           0.008f,
                           0.0145f,
                           0.022f,
                           0.035f,
                           0.049f,
                           0.0595f,
                           0.075f,
                           0.0905f,
                           0.098f,
                           0.0995f,
                           0.097f,
                           0.093f,
                           0.091f,
                           0.0925f,
                           0.094f,
                           0.096f,
                           0.096f,
                           0.0955f,
                           0.094f,
                           0.092f,
                           0.0907811f,
                           0.089f,
                           0.088f,
                           0.088f,
                           0.088f,
                           0.088f,
                           0.088f,
                           0.0875f,
                           0.087f,
                           0.086f,
                           0.085f,
                           0.084f,
                           0.083f,
                           0.083f,
                           0.082f,
                           0.081f,
                           0.0806396f,
                           0.079f,
                           0.078f,
                           0.077f,
                           0.076f,
                           0.075f,
                           0.074f,
                           0.073f,
                           0.072f,
                           0.071f,
                           0.0700369f,
                           0.0685f,
                           0.067f,
                           0.0655f,
                           0.064f,
                           0.063f,
                           0.063f,
                           0.062f,
                           0.059f,
                           0.054f,
                           0.043f,
                           0.034f,
                           0.025f,
                           0.016f,
                           0.009f,
                           0.0055f,
                           0.003f,
                           0.0015f,
                           0.001f,
                           0.000691333f,
                           0.000432126f,
                           0.000356974f,
                           0.000265441f,
                           0.000219773f,
                           0.000195346f,
                           0.000192716f,
                           0.000188932f,
                           0.000185148f,
                           0.000181364f,
                           0.00017758f,
                           0.000173796f,
                           0.000170011f,
                           0.000166227f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0.0f,
                           0};

    // Add multispectral bands to the temporary list
    const std::vector<float> vb1(b1, b1 + sizeof(b1) / sizeof(float));
    tmpSpectralBandList.push_back(vb1);
    const std::vector<float> vb2(b2, b2 + sizeof(b2) / sizeof(float));
    tmpSpectralBandList.push_back(vb2);
    const std::vector<float> vb3(b3, b3 + sizeof(b3) / sizeof(float));
    tmpSpectralBandList.push_back(vb3);
    const std::vector<float> vb4(b4, b4 + sizeof(b4) / sizeof(float));
    tmpSpectralBandList.push_back(vb4);

    unsigned int j = 0;
    for (std::list<std::vector<float>>::const_iterator it = tmpSpectralBandList.begin(); it != tmpSpectralBandList.end(); ++it)
    {
      wavelengthSpectralBand->PushBack(FilterFunctionValues::New());
      wavelengthSpectralBand->GetNthElement(j)->SetFilterFunctionValues(*it);
      wavelengthSpectralBand->GetNthElement(j)->SetMinSpectralValue(0.300);
      wavelengthSpectralBand->GetNthElement(j)->SetMaxSpectralValue(1.0);
      wavelengthSpectralBand->GetNthElement(j)->SetUserStep(0.0025);
      ++j;
    }
  }

  return wavelengthSpectralBand;
}

} // end namespace otb
