#ifndef CDO_FFTW3_H
#define CDO_FFTW3_H

#include "varray.h"

void fourier2grid(int gridID1, Varray<double> const &array1, Varray<double> &array2);
void grid2fourier(int gridID1, Varray<double> const &array1, int gridID2, Varray<double> &array2);

#if __has_include(<fftw3.h>)
#include <fftw3.h>

#include <mutex>
extern std::mutex fftw3Mutex;

struct FFTW3RCMemory
{
  double *real{};
  fftw_complex *complex{};
  fftw_plan plan{};

  bool
  empty() const
  {
    return (real == nullptr);
  }

  void
  init(int sign, int numGP)
  {
    real = fftw_alloc_real(numGP);
    complex = fftw_alloc_complex(numGP / 2 + 1);
    std::scoped_lock lock(fftw3Mutex);
    if (sign == FFTW_FORWARD) { plan = fftw_plan_dft_r2c_1d(numGP, real, complex, FFTW_ESTIMATE); }
    if (sign == FFTW_BACKWARD) { plan = fftw_plan_dft_c2r_1d(numGP, complex, real, FFTW_ESTIMATE); }
  }

  FFTW3RCMemory() {}
  ~FFTW3RCMemory()
  {
    if (plan)
    {
      std::scoped_lock lock(fftw3Mutex);
      fftw_destroy_plan(plan);
    }
    if (complex) fftw_free(complex);
    if (real) fftw_free(real);
  }
};
#endif

#endif
