/*
 * Copyright (C) 2005-2022 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.
 */

#ifndef otbSentinel1ThermalNoiseLookupData_h
#define otbSentinel1ThermalNoiseLookupData_h

#include "otbSentinel1CalibrationLookupData.h"

namespace otb
{

/** 
 * \struct 
 * \brief Structure containing the Sentinel 1 azimuth noise LUT 
 * \ingroup OTBMetadata
*/
struct Sentinel1AzimuthNoiseStruct
{
  int firstAzimuthLine = 0;
  int lastAzimuthLine = 0;
  int firstRangeSample = 0;
  int lastRangeSample = 0;

  std::vector<int> lines;
  std::vector<float>  vect;
};

/**
 * \class Sentinel1ThermalNoiseLookupData
 * \brief Calculate the Sentinel 1 thermal noise contribution for the given pixel
 *
 * This class computes the thermal noise using the noise LUTs contained in the product
 * metadata. Range noise and azimuth noise are considered. The noise contribution is
 * the product of the interpolated LUTs at the pixel index. Only range noise is used
 * if the azimuth noise LUT is not available (it is the case for older products).
 *
 * Reference: MPC-0392 DI-MPC-TN Thermal Denoising of Products Generated by the S-1 IPF
 *
 * This class is templated over the input image type and the
 * coordinate representation type (e.g. float or double ).
 *
 * \ingroup OTBMetadata
 */
class Sentinel1ThermalNoiseLookupData : public SarCalibrationLookupData
{
public:
  /** Standard typedefs */
  using Self = Sentinel1ThermalNoiseLookupData;
  using Superclass = itk::LightObject;
  using Pointer = itk::SmartPointer<Self>;
  using ConstPointer = itk::SmartPointer<const Self>;

  using IndexValueType = itk::IndexValueType ;

  /** Creation through the object factory */
  itkNewMacro(Self);

  /** RTTI */
  itkTypeMacro(Sentinel1ThermalNoiseLookupData, itk::LightObject);

  /** Init the LUT using metadatas */
  void InitParameters(double firstLineTime,
                      double lastLineTime,
                      int numOfLines,
                      std::vector<Sentinel1CalibrationStruct> const& rangeNoiseVectorList,
                      std::vector<Sentinel1AzimuthNoiseStruct> const& azimuthNoiseVectorList);

  /** Compute noise contribution for a given pixel */
  double GetValue(const IndexValueType x, const IndexValueType y) const override;

protected:
  Sentinel1ThermalNoiseLookupData() : m_FirstLineTime(0.), m_LastLineTime(0.) {m_FirstLineTime = 1.;};
  ~Sentinel1ThermalNoiseLookupData() = default;

private:
  /** Compute range thermal noise contribution */
  double GetRangeNoise(const IndexValueType x, const IndexValueType y) const;

  /** Compute azimuth thermal noise contribution */
  double GetAzimuthNoise(const IndexValueType x, const IndexValueType y) const;

  int GetRangeVectorIndex(int y) const;

  int GetAzimuthVectorIndex(int x, int y) const;

  int GetPixelIndex(int x, const std::vector<int> & vec) const;

  /** First line of the S1 product */
  double m_FirstLineTime = 0.;

  /** Last line of the product */
  double m_LastLineTime = 0.;

  /** Duration between two lines */
  double m_LineTimeInterval = 0.;

  int m_NumOfLines = 0;
  int m_RangeCount = 0;
  int m_AzimuthCount = 0;

  /** Range noise LUT container */
  std::vector<Sentinel1CalibrationStruct> m_RangeNoiseVectorList;
  
  /** Azimuth noise LUT container*/
  std::vector<Sentinel1AzimuthNoiseStruct> m_AzimuthNoiseVectorList;
};

}

#endif