{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{- |
Transformations of single datasets.
-}
module Data.Array.Accelerate.CUFFT.Single (
   Priv.Transform,
   Priv.transform,

   Handle,
   plan1D,
   plan2D,
   plan3D,

   RC.Real,
   Mode,
   Priv.forwardComplex, Priv.inverseComplex,
   Priv.forwardReal, Priv.inverseReal,

   Priv.getBestTarget,
   ) where

import qualified Data.Array.Accelerate.CUFFT.RealClass as RC
import qualified Data.Array.Accelerate.CUFFT.Private as Priv
import Data.Array.Accelerate.CUFFT.Private
          (Mode, wrapFallback, Handle, makeHandle, atTarget)

import qualified Data.Array.Accelerate.Fourier.Planned as Fourier

import Data.Array.Accelerate.LLVM.PTX (PTX)
import Data.Array.Accelerate (Elt, DIM1, DIM2, DIM3, Z(Z), (:.)((:.)), )

import qualified Foreign.CUDA.FFT as CUFFT


{- |
The plan must be created for the target where the transform is executed.
See 'Data.Array.Accelerate.CUFFT.Batched.plan1D' for details.
-}
plan1D ::
   (Elt e, RC.Real e) =>
   PTX -> Mode DIM1 e a b -> DIM1 -> IO (Handle DIM1 e a b)
plan1D target mode (Z:.width) =
   atTarget target $
   makeHandle mode width
      (\sign -> wrapFallback mode $ Fourier.transform sign width)
      (\typ -> CUFFT.plan1D width typ 1)

plan2D ::
   (Elt e, RC.Real e) =>
   PTX -> Mode DIM2 e a b -> DIM2 -> IO (Handle DIM2 e a b)
plan2D target mode sh@(Z:.height:.width) =
   atTarget target $
   makeHandle mode width
      (wrapFallback mode . Priv.transform2D sh)
      (CUFFT.plan2D height width)

plan3D ::
   (Elt e, RC.Real e) =>
   PTX -> Mode DIM3 e a b -> DIM3 -> IO (Handle DIM3 e a b)
plan3D target mode sh@(Z:.depth:.height:.width) =
   atTarget target $
   makeHandle mode width
      (wrapFallback mode . Priv.transform3D sh)
      (CUFFT.plan3D depth height width)