{-# LANGUAGE BangPatterns, RecordWildCards, TypeFamilies, TypeOperators #-}

module Vision.Image.RGB.Type (
      RGB, RGBPixel (..), RGBDelayed
    ) where

import Control.Applicative ((<$>), (<*>))
import Data.Word
import Foreign.Storable (Storable (..))
import Foreign.Ptr (castPtr, plusPtr)

import Vision.Image.Interpolate (Interpolable (..))
import Vision.Image.Transform (
      InterpolMethod, crop, resize, horizontalFlip, verticalFlip
    )
import Vision.Image.Type (Pixel (..), Manifest, Delayed)
import Vision.Primitive (Rect, Size)

data RGBPixel = RGBPixel {
      rgbRed   :: {-# UNPACK #-} !Word8, rgbGreen :: {-# UNPACK #-} !Word8
    , rgbBlue  :: {-# UNPACK #-} !Word8
    } deriving (Eq, Show)

type RGB = Manifest RGBPixel

type RGBDelayed = Delayed RGBPixel

instance Storable RGBPixel where
    sizeOf _ = 3 * sizeOf (undefined :: Word8)
    {-# INLINE sizeOf #-}

    alignment _ = alignment (undefined :: Word8)
    {-# INLINE alignment #-}

    peek !ptr =
        let !ptr' = castPtr ptr
        in RGBPixel <$> peek ptr'               <*> peek (ptr' `plusPtr` 1)
                    <*> peek (ptr' `plusPtr` 2)
    {-# INLINE peek #-}

    poke !ptr RGBPixel { .. } =
        let !ptr' = castPtr ptr
        in poke ptr'               rgbRed   >>
           poke (ptr' `plusPtr` 1) rgbGreen >>
           poke (ptr' `plusPtr` 2) rgbBlue
    {-# INLINE poke #-}

instance Pixel RGBPixel where
    type PixelChannel RGBPixel = Word8

    pixNChannels _ = 3
    {-# INLINE pixNChannels #-}

    pixIndex !(RGBPixel r _ _) 0 = r
    pixIndex !(RGBPixel _ g _) 1 = g
    pixIndex !(RGBPixel _ _ b) _ = b
    {-# INLINE pixIndex #-}

instance Interpolable RGBPixel where
    interpol f a b =
        let RGBPixel aRed aGreen aBlue = a
            RGBPixel bRed bGreen bBlue = b
        in RGBPixel {
              rgbRed  = f aRed  bRed, rgbGreen = f aGreen bGreen
            , rgbBlue = f aBlue bBlue
            }
    {-# INLINE interpol #-}

{-# SPECIALIZE crop           :: Rect -> RGB -> RGB #-}
{-# SPECIALIZE resize         :: InterpolMethod -> Size -> RGB -> RGB #-}
{-# SPECIALIZE horizontalFlip :: RGB -> RGB #-}
{-# SPECIALIZE verticalFlip   :: RGB -> RGB #-}