/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  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
 *
 *         https://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  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 itkForwardInverseFFTTest_h
#define itkForwardInverseFFTTest_h

#include "itkAbsoluteValueDifferenceImageFilter.h"
#include "itkImageFileReader.h"

template <typename TForwardFFT, typename TInverseFFT>
bool
ForwardInverseFullFFTTest(const char * inputFileName)
{
  constexpr double tolerance{ 1.e-3 };
  using ImageType = typename TForwardFFT::InputImageType;
  using ReaderType = itk::ImageFileReader<ImageType>;
  auto reader = ReaderType::New();
  reader->SetFileName(inputFileName);

  auto fft = TForwardFFT::New();
  fft->SetInput(reader->GetOutput());

  auto ifft = TInverseFFT::New();
  ifft->SetInput(fft->GetOutput());

  using AbsDiffFilterType = itk::AbsoluteValueDifferenceImageFilter<ImageType, ImageType, ImageType>;
  auto diffFilter = AbsDiffFilterType::New();
  diffFilter->SetInput1(reader->GetOutput());
  diffFilter->SetInput2(ifft->GetOutput());
  diffFilter->UpdateLargestPossibleRegion();

  bool success = true;
  using IteratorType = itk::ImageRegionConstIteratorWithIndex<ImageType>;
  IteratorType it(diffFilter->GetOutput(), diffFilter->GetOutput()->GetLargestPossibleRegion());
  while (!it.IsAtEnd())
  {
    if (it.Get() > tolerance)
    {
      std::cerr << "Error found at pixel " << it.GetIndex() << '.' << std::endl;
      std::cerr << "Absolute difference is " << it.Get() << ", which is greater than the acceptable tolerance of"
                << tolerance << '.' << std::endl;
      success = false;
      break;
    }
    ++it;
  }

  return success;
}

template <typename TForwardFFT, typename TInverseFFT>
bool
ForwardInverseHalfFFTTest(const char * inputFileName)
{
  constexpr double tolerance{ 1.e-3 };
  using ImageType = typename TForwardFFT::InputImageType;
  using ReaderType = itk::ImageFileReader<ImageType>;
  auto reader = ReaderType::New();
  reader->SetFileName(inputFileName);
  reader->UpdateLargestPossibleRegion();

  auto fft = TForwardFFT::New();
  fft->SetInput(reader->GetOutput());

  auto       ifft = TInverseFFT::New();
  const bool xIsOdd = reader->GetOutput()->GetLargestPossibleRegion().GetSize()[0] % 2 == 1;
  ifft->SetActualXDimensionIsOdd(xIsOdd);
  ifft->SetInput(fft->GetOutput());

  using AbsDiffFilterType = itk::AbsoluteValueDifferenceImageFilter<ImageType, ImageType, ImageType>;
  auto diffFilter = AbsDiffFilterType::New();
  diffFilter->SetInput1(reader->GetOutput());
  diffFilter->SetInput2(ifft->GetOutput());
  diffFilter->UpdateLargestPossibleRegion();

  bool success = true;
  using IteratorType = itk::ImageRegionConstIteratorWithIndex<ImageType>;
  IteratorType it(diffFilter->GetOutput(), diffFilter->GetOutput()->GetLargestPossibleRegion());
  while (!it.IsAtEnd())
  {
    if (it.Get() > tolerance)
    {
      std::cerr << "ForwardInverseHalfFFTTest: Error found at pixel " << it.GetIndex() << '.' << std::endl;
      std::cerr << "Absolute difference is " << it.Get() << ", which is greater than the acceptable tolerance of"
                << tolerance << '.' << std::endl;
      success = false;
      break;
    }
    ++it;
  }

  return success;
}

#endif
