   , bandBlockLen
   , bandSize
   , bandNodataValue
+  , bandNodataPredicate
   , setBandNodataValue
   , getBand
+  , getMaskBand
   , readBand
   , unsafeLazyReadBand
   , readBandBlock

import Control.Monad.IO.Class (MonadIO(..))

import Data.Int (Int16, Int32)
import Data.Complex (Complex(..))
import Data.Maybe (isJust)
import Data.Proxy (Proxy(..))
import Data.Typeable (Typeable)

foreign import ccall safe "gdal.h GDALWriteBlock" writeBlock_
   :: (RWBand s a) -> CInt -> CInt -> Ptr () -> IO CInt

foreign import ccall safe "gdal.h GDALGetMaskBand" c_getMaskBand
   :: (Band s t a) -> IO (Band s t Word8)

getMaskBand :: Band s t a -> GDAL s (Band s t Word8)
getMaskBand = liftIO . c_getMaskBand


class Storable a => GDALType a where
  datatype   :: Proxy a -> Datatype
  toNodata   :: a -> CDouble
  fromNodata :: CDouble -> a

instance GDALType Word8 where
  datatype _ = GDT_Byte
  toNodata = fromIntegral
  fromNodata = round
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Word16 where
  datatype _ = GDT_UInt16
  toNodata = fromIntegral
  fromNodata = round
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Word32 where
  datatype _ = GDT_UInt32
  toNodata = fromIntegral
  fromNodata = round
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Int16 where
  datatype _ = GDT_Int16
  toNodata = fromIntegral
  fromNodata = round
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Int32 where
  datatype _ = GDT_Int32
  toNodata = fromIntegral
  fromNodata = round
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Float where
  datatype _ = GDT_Float32
  toNodata = realToFrac
  fromNodata = realToFrac
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType Double where
  datatype _ = GDT_Float64
  toNodata = realToFrac
  fromNodata = realToFrac
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType (Complex Int16) where
  datatype _ = GDT_CInt16
  toNodata = fromIntegral . realPart
  fromNodata d = fromNodata d :+ fromNodata d
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType (Complex Int32) where
  datatype _ = GDT_CInt32
  toNodata = fromIntegral . realPart
  fromNodata d = fromNodata d :+ fromNodata d
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType (Complex Float) where
  datatype _ = GDT_CFloat32
  toNodata = realToFrac . realPart
  fromNodata d = fromNodata d :+ fromNodata d
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}

instance GDALType (Complex Double) where
  datatype _ = GDT_CFloat64
  toNodata = realToFrac . realPart
  fromNodata d = fromNodata d :+ fromNodata d
  {-# INLINE datatype #-}
  {-# INLINE toNodata #-}
  {-# INLINE fromNodata #-}
