/*
 * 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.
 */

#ifndef otbS1ThermalNoiseLookupData_h
#define otbS1ThermalNoiseLookupData_h

#include "otbSentinel1ImageMetadataInterface.h"

#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "ossim/ossimTimeUtilities.h"
#pragma GCC diagnostic pop
#else
#include "ossim/ossimTimeUtilities.h"
#endif

namespace otb
{

/**
 * \class S1ThermalNoiseLookupData
 * \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 OTBSARCalibration
 */
template <class T = double>
class S1ThermalNoiseLookupData : public itk::LightObject
{

public:
  /** Standard typedefs */
  using Self = S1ThermalNoiseLookupData;
  using Superclass = itk::LightObject;
  using Pointer = itk::SmartPointer<Self>;
  using ConstPointer = itk::SmartPointer<const Self>;

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

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

  /** Set input metadata containing denoising LUTs */
  void SetImageKeywordlist(const ImageKeywordlist & kwl);

  using IndexValueType = itk::IndexValueType ;

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

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

private:

  /** Structure containing the azimuth noise LUT */
  struct Sentinel1AzimuthNoiseStruct
  {
    int firstAzimuthLine = 0;
    int lastAzimuthLine = 0;
    int firstRangeSample = 0;
    int lastRangeSample = 0;

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

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

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

  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;
};

}

#ifndef OTB_MANUAL_INSTANTIATION
#include "otbS1ThermalNoiseLookupData.hxx"
#endif

#endif