-- | Basic definitions for stencil handling.
module Data.Array.Repa.Stencil.Base
        ( Boundary      (..)
        , Stencil       (..)
        , makeStencil, makeStencil2)
where
import Data.Array.Repa.Index

-- | How to handle the case when the stencil lies partly outside the array.
data Boundary a
        -- | Use a fixed value for border regions.
        = BoundFixed !a

        -- | Treat points outside the array as having a constant value.
        | BoundConst !a

        -- | Clamp points outside to the same value as the edge pixel.
        | BoundClamp
        deriving (Show)


-- | Represents a convolution stencil that we can apply to array.
--   Only statically known stencils are supported right now.
data Stencil sh a

        -- | Static stencils are used when the coefficients are fixed,
        --   and known at compile time.
        = StencilStatic
        { stencilExtent :: !sh
        , stencilZero   :: !a
        , stencilAcc    :: !(sh -> a -> a -> a) }


-- | Make a stencil from a function yielding coefficients at each index.
makeStencil
        :: Num a
        => sh                   -- ^ Extent of stencil.
        -> (sh -> Maybe a)      -- ^ Get the coefficient at this index.
        -> Stencil sh a

{-# INLINE makeStencil #-}
makeStencil ex getCoeff
 = StencilStatic ex 0
 $ \ix val acc
        -> case getCoeff ix of
                Nothing         -> acc
                Just coeff      -> acc + val * coeff


-- | Wrapper for `makeStencil` that requires a DIM2 stencil.
makeStencil2
        :: Num a
        => Int -> Int           -- ^ extent of stencil
        -> (DIM2 -> Maybe a)    -- ^ Get the coefficient at this index.
        -> Stencil DIM2 a

{-# INLINE makeStencil2 #-}
makeStencil2 height width getCoeff
        = makeStencil (Z :. height :. width) getCoeff