module Data.Grib (
GribIO
, runGribIO
, runGribIO_
, skipMessage
, skipMessageIf
, skipMessageIf_
, getDouble
, getLong
, getString
, getValues
, setDouble
, setLong
, setString
, setValues
, getFilename
, getIndex
, getHandle
, liftIO
, GribEnv
, SkipMessage
) where
import Control.Exception ( Exception, throwIO, try )
import Control.Monad ( void, when )
import Control.Monad.IO.Class ( liftIO )
import Control.Monad.Trans.Reader ( ReaderT, ask, runReaderT )
import Data.Typeable ( Typeable )
import Foreign ( allocaArray, allocaBytes )
import Control.Applicative
import Prelude
import Data.Grib.Raw
handles :: FilePath -> IO [GribHandle]
handles path = withBinaryCFile path ReadMode go
where go file = gribHandleNewFromFile defaultGribContext file >>=
maybe (return []) (\h' -> (h' :) <$> go file)
data GribEnv = GribEnv
{ filename :: FilePath
, index :: Int
, handle :: GribHandle
}
envs :: FilePath -> IO [GribEnv]
envs path = fmap (zipWith3 GribEnv (repeat path) [0..]) (handles path)
data SkipMessage = SkipMessage deriving (Show, Typeable)
instance Exception SkipMessage
skipMessage :: GribIO a
skipMessage = liftIO . throwIO $ SkipMessage
skipMessageIf :: (a -> Bool)
-> GribIO a
-> GribIO a
skipMessageIf p m = do { x <- m; when (p x) skipMessage; return x }
skipMessageIf_ :: (a -> Bool)
-> GribIO a
-> GribIO ()
skipMessageIf_ p m = do { x <- m; when (p x) skipMessage }
trySkipMessage :: IO a -> IO (Either SkipMessage a)
trySkipMessage = try
type GribIO = ReaderT GribEnv IO
runGribIO :: FilePath
-> GribIO a
-> IO [a]
runGribIO path m = envs path >>= foldr k (return [])
where k env res = trySkipMessage (runReaderT m env) >>=
either (const res) (\x -> fmap (x :) res)
runGribIO_ :: FilePath -> GribIO a -> IO ()
runGribIO_ path m = envs path >>= mapM_ (runReaderT m)
getFilename :: GribIO FilePath
getFilename = fmap filename ask
getIndex :: GribIO Int
getIndex = fmap index ask
getHandle :: GribIO GribHandle
getHandle = fmap handle ask
getDouble :: Key -> GribIO Double
getDouble key = getHandle >>= liftIO . flip gribGetDouble key
getLong :: Key -> GribIO Int
getLong key = getHandle >>= liftIO . flip gribGetLong key
getString :: Key -> GribIO String
getString key = getHandle >>= \h -> do
n <- liftIO . gribGetLength h $ key
liftIO . allocaBytes n $ \bufr -> gribGetString h key bufr n
getValues :: GribIO [Double]
getValues = getHandle >>= \h -> do
n <- liftIO . gribGetSize h $ key
liftIO . allocaArray n $ \array -> gribGetDoubleArray h key array n
where key = "values"
setGeneric :: (GribHandle -> Key -> a -> IO b) -> Key -> a -> GribIO b
setGeneric setter key value = getHandle >>= \h -> liftIO $ setter h key value
setDouble :: Key -> Double -> GribIO ()
setDouble = setGeneric gribSetDouble
setLong :: Key -> Int -> GribIO ()
setLong = setGeneric gribSetLong
setString :: Key -> String -> GribIO ()
setString key value = void $ setGeneric gribSetString key value
setValues :: [Double] -> GribIO ()
setValues = setGeneric gribSetDoubleArray "values"