{-
    Copyright 2015 Markus Ongyerth, Stephan Guenther

    This file is part of Monky.

    Monky is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Monky is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Monky.  If not, see <http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE CPP #-}
{-|
Module      : Monky.Blkid
Description : Minimal access to liblkid
Maintainer  : ongy
Stability   : experimental
Portability : Linux

This module allows access to libblkid functionality

Since the library does not have to exist on every system we link
against it on runtime when needed.
We don't have a handle or something cool like that, so we will just
load it when needed und unload again after
-}
module Monky.Blkid
  ( evaluateTag
  , evaluateSpec
  , evaluateTag'
  , evaluateSpec'
  , withLibBlkid
  )
where

import Monky.Template

import Foreign.Ptr
import Foreign.C.String
import Foreign.Marshal.Alloc

#if MIN_VERSION_base(4,8,0)
#else
import Control.Applicative ((<$>))
#endif


data Cache

importLib "LibBlkid" "libblkid.so"
  [ ( "c_evt", "blkid_evaluate_tag", "CString -> CString -> Ptr Cache -> IO CString")
  , ( "c_evs", "blkid_evaluate_spec", "CString -> Ptr Cache -> IO CString")
  ]

getAndFreeString :: CString -> IO String
getAndFreeString ptr = do
  ret <- peekCString ptr
  free ptr
  return ret


maybeGetString :: CString -> IO (Maybe String)
maybeGetString ptr = if ptr == nullPtr
    then return Nothing
    else Just <$> getAndFreeString ptr

-- |Version to reuse the LibBlkid
evaluateTag' :: String -> String -> LibBlkid -> IO (Maybe String)
evaluateTag' t v l = do
  ptr <- withCString t (\ct -> withCString v (\cv -> c_evt l ct cv nullPtr))
  maybeGetString ptr

-- |version to reuse the LibBlkid
evaluateSpec' :: String -> LibBlkid -> IO (Maybe String)
evaluateSpec' s l = do
  ptr <- withCString s (\cs -> c_evs l cs nullPtr)
  maybeGetString ptr

-- |Evaluate a tag
evaluateTag :: String -> String -> IO (Maybe String)
evaluateTag t v = withLibBlkid $ evaluateTag' t v

-- |Evaluate a spec
evaluateSpec :: String -> IO (Maybe String)
evaluateSpec = withLibBlkid . evaluateSpec'

-- |Execute an IO action with an instance of LibBlkid
withLibBlkid :: (LibBlkid -> IO a) -> IO a
withLibBlkid a = do
  l <- getLibBlkid
  ret <- a l
  destroyLibBlkid l
  return ret