#pragma once
#include <map>
#include <vector>

struct PFFFT_Setup;

struct WavtoolFFT {
  enum class TransformType { REAL = 0, COMPLEX = 1 };

  enum class TransformDirection { FORWARD = 0, BACKWARD = 1 };

  std::map<int, std::pair<PFFFT_Setup *, PFFFT_Setup *>>
      pffft_setups; // size -> (real, complex)

  WavtoolFFT();
  ~WavtoolFFT();

  std::vector<int> get_supported_sizes();

  // input and output are interleaved complex numbers and may alias
  // for REAL transform:
  //   input is size floats representing a real sequence
  //   output is size floats representing an interleaved complex sequence
  //   (size/2 values)
  //   the first output value is special:
  //     output[0] is DC, output[1] is Nyquist, i.e.
  //     complex[0] = output[0] + i*output[1] = F(0) + i*F(size/2+1)
  // for COMPLEX transform:
  //   input and output are 2*size floats representing interleaved complex
  //   sequences
  // transform is not scaled: BACKWARD(FORWARD(x)) = size*x
  int fft_ordered(int size, TransformType type, TransformDirection direction,
                  const float *input, float *output);

  // like fft_ordered, but the order of elements in the output is not specified
  // this is faster than fft_ordered and should be used with
  // fft_convolve_accumulate
  int fft_unordered(int size, TransformType type, TransformDirection direction,
                    const float *input, float *output);

  // in1 and in2 are the output of fft_unordered(size, *, FORWARD, ...)
  // accumulate the convolution of in1 and in2 into output, scaled by scale
  // the order of elements in output is not specified; use fft_reorder to get
  // the canonical order
  int fft_convolve_accumulate(int size, TransformType type, float scale,
                              const float *in1, const float *in2,
                              float *output);

  // reorder the output of fft_unordered and fft_convolve_accumulate to the
  // canonical order input and output should not alias
  int fft_reorder(int size, TransformType type, const float *input,
                  float *output);

  // for power users
  PFFFT_Setup *get_pffft_setup(int size, TransformType type);
};

extern WavtoolFFT wavtool_fft;