{-# LINE 1 "src/Database/Zookeeper/CApi.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "src/Database/Zookeeper/CApi.hsc" #-}

-- This file is part of zhk
--
-- All rights reserved.
--  
-- Redistribution and use in source and binary forms, with or without modification,
-- are permitted provided that the following conditions are met:
--  
--   Redistributions of source code must retain the above copyright notice, this
--   list of conditions and the following disclaimer.
--  
--   Redistributions in binary form must reproduce the above copyright notice, this
--   list of conditions and the following disclaimer in the documentation and/or
--   other materials provided with the distribution.
--  
--   Neither the name of the {organization} nor the names of its
--   contributors may be used to endorse or promote products derived from
--   this software without specific prior written permission.
--  
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module Database.Zookeeper.CApi
       ( -- * C to Haskell
         toStat
       , toState
       , toZKError
       , allocaStat
         -- * Haskell to C
       , withAclList
       , wrapWatcher
       , fromLogLevel
       , fromCreateFlag
       , fromCreateFlags
       , wrapAclCompletion
       , wrapDataCompletion
       , wrapVoidCompletion
       , wrapStringCompletion
       , wrapStringsCompletion
         -- * Error handling
       , tryZ
       , isZOK
       , onZOK
       , whenZOK
         -- * C functions
       , c_zooSet2
       , c_zooAWGet
       , c_zooState
       , c_zooDelete
       , c_zooSetAcl
       , c_zooAGetAcl
       , c_zooACreate
       , c_zooAddAuth
       , c_zooWExists
       , c_zooClientId
       , c_zookeeperInit
       , c_zookeeperClose
       , c_zooSetWatcher
       , c_zooRecvTimeout
       , c_isUnrecoverable
       , c_zooAWGetChildren
       , c_zooSetDebugLevel
       ) where


{-# LINE 75 "src/Database/Zookeeper/CApi.hsc" #-}

import           Foreign
import           Foreign.C
import qualified Data.ByteString as B
import           Control.Applicative
import           Database.Zookeeper.Types

tryZ :: IO CInt -> IO a -> IO (Either ZKError a)
tryZ zkIO nextIO = do
  rc <- zkIO
  rc `onZOK` nextIO

isZOK :: CInt -> Bool
isZOK rc = rc == (0)
{-# LINE 89 "src/Database/Zookeeper/CApi.hsc" #-}

onZOK :: CInt -> IO a -> IO (Either ZKError a)
onZOK rc nextIO
  | isZOK rc  = fmap Right nextIO
  | otherwise = return (Left $ toZKError rc)

whenZOK :: CInt -> IO (Either ZKError a) -> IO (Either ZKError a)
whenZOK rc succIO
  | isZOK rc  = succIO
  | otherwise = return (Left $ toZKError rc)

toStat :: Ptr CStat -> IO Stat
toStat ptr = Stat <$> ((\hsc_ptr -> peekByteOff hsc_ptr 0)) ptr
{-# LINE 102 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 8)) ptr
{-# LINE 103 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 64)) ptr
{-# LINE 104 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 16)) ptr
{-# LINE 105 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 24)) ptr
{-# LINE 106 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 32)) ptr
{-# LINE 107 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 36)) ptr
{-# LINE 108 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 40)) ptr
{-# LINE 109 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 56)) ptr
{-# LINE 110 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> ((\hsc_ptr -> peekByteOff hsc_ptr 60)) ptr
{-# LINE 111 "src/Database/Zookeeper/CApi.hsc" #-}
                  <*> liftA toEphemeralOwner (((\hsc_ptr -> peekByteOff hsc_ptr 48)) ptr)
{-# LINE 112 "src/Database/Zookeeper/CApi.hsc" #-}
    where
      toEphemeralOwner 0 = Nothing
      toEphemeralOwner c = Just c

fromCreateFlag :: CreateFlag -> CInt
fromCreateFlag Sequence  = (2)
{-# LINE 118 "src/Database/Zookeeper/CApi.hsc" #-}
fromCreateFlag Ephemeral = (1)
{-# LINE 119 "src/Database/Zookeeper/CApi.hsc" #-}

fromCreateFlags :: [CreateFlag] -> CInt
fromCreateFlags = foldr (.|.) 0 . map fromCreateFlag

fromPerm :: Perm -> CInt
fromPerm CanRead   = (1)
{-# LINE 125 "src/Database/Zookeeper/CApi.hsc" #-}
fromPerm CanAdmin  = (16)
{-# LINE 126 "src/Database/Zookeeper/CApi.hsc" #-}
fromPerm CanWrite  = (2)
{-# LINE 127 "src/Database/Zookeeper/CApi.hsc" #-}
fromPerm CanCreate = (4)
{-# LINE 128 "src/Database/Zookeeper/CApi.hsc" #-}
fromPerm CanDelete = (8)
{-# LINE 129 "src/Database/Zookeeper/CApi.hsc" #-}

fromLogLevel :: ZLogLevel -> CInt
fromLogLevel ZLogError = (1)
{-# LINE 132 "src/Database/Zookeeper/CApi.hsc" #-}
fromLogLevel ZLogWarn  = (2)
{-# LINE 133 "src/Database/Zookeeper/CApi.hsc" #-}
fromLogLevel ZLogInfo  = (3)
{-# LINE 134 "src/Database/Zookeeper/CApi.hsc" #-}
fromLogLevel ZLogDebug = (4)
{-# LINE 135 "src/Database/Zookeeper/CApi.hsc" #-}

fromPerms :: [Perm] -> CInt
fromPerms = foldr (.|.) 0 . map fromPerm

toPerms :: CInt -> [Perm]
toPerms n = buildList [ ((1), CanRead)
{-# LINE 141 "src/Database/Zookeeper/CApi.hsc" #-}
                      , ((16), CanAdmin)
{-# LINE 142 "src/Database/Zookeeper/CApi.hsc" #-}
                      , ((2), CanWrite)
{-# LINE 143 "src/Database/Zookeeper/CApi.hsc" #-}
                      , ((4), CanCreate)
{-# LINE 144 "src/Database/Zookeeper/CApi.hsc" #-}
                      , ((8), CanDelete)
{-# LINE 145 "src/Database/Zookeeper/CApi.hsc" #-}
                      ]
    where
      buildList [] = []
      buildList ((t, a):xs)
        | n .&. t == t = a : buildList xs
        | otherwise    = buildList xs

toStringList :: Ptr CStrVec -> IO [String]
toStringList strvPtr = do
  count   <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) strvPtr
{-# LINE 155 "src/Database/Zookeeper/CApi.hsc" #-}
  dataPtr <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) strvPtr
{-# LINE 156 "src/Database/Zookeeper/CApi.hsc" #-}
  buildList [] count dataPtr
    where
      buildList :: [String] -> Int32 -> Ptr CString -> IO [String]
      buildList acc 0 _   = return $ reverse acc
      buildList acc n ptr = do
        item <- peek ptr >>= peekCString
        buildList (item : acc) (n-1) (ptr `plusPtr` (sizeOf ptr))

allocaStat :: (Ptr CStat -> IO a) -> IO a
allocaStat fun = allocaBytes ((72)) fun
{-# LINE 166 "src/Database/Zookeeper/CApi.hsc" #-}

toAclList :: Ptr CAclVec -> IO AclList
toAclList aclvPtr = do
  count  <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) aclvPtr
{-# LINE 170 "src/Database/Zookeeper/CApi.hsc" #-}
  aclPtr <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) aclvPtr
{-# LINE 171 "src/Database/Zookeeper/CApi.hsc" #-}
  fmap List (buildList [] count aclPtr)
    where
      buildList :: [Acl] -> Int32 -> Ptr CAcl -> IO [Acl]
      buildList acc 0 _   = return acc
      buildList acc n ptr = do
        acl <- Acl <$> (((\hsc_ptr -> peekByteOff hsc_ptr 8)) ptr >>= peekCString)
{-# LINE 177 "src/Database/Zookeeper/CApi.hsc" #-}
                   <*> (((\hsc_ptr -> peekByteOff hsc_ptr 16)) ptr >>= peekCString)
{-# LINE 178 "src/Database/Zookeeper/CApi.hsc" #-}
                   <*> (fmap toPerms (((\hsc_ptr -> peekByteOff hsc_ptr 0)) ptr))
{-# LINE 179 "src/Database/Zookeeper/CApi.hsc" #-}
        buildList (acl : acc) (n-1) (ptr `plusPtr` ((24)))
{-# LINE 180 "src/Database/Zookeeper/CApi.hsc" #-}

withAclList :: AclList -> (Ptr CAclVec -> IO a) -> IO a
withAclList CreatorAll cont    = cont c_zooCreatorAclAll
withAclList OpenAclUnsafe cont = cont c_zooOpenAclUnsafe
withAclList ReadAclUnsafe cont = cont c_zooReadAclUnsafe
withAclList (List acls) cont   =
  allocaBytes ((16)) $ \aclvPtr -> do
{-# LINE 187 "src/Database/Zookeeper/CApi.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) aclvPtr count
{-# LINE 188 "src/Database/Zookeeper/CApi.hsc" #-}
    allocaBytes (count * ((24))) $ \aclPtr -> do
{-# LINE 189 "src/Database/Zookeeper/CApi.hsc" #-}
      ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) aclvPtr aclPtr
{-# LINE 190 "src/Database/Zookeeper/CApi.hsc" #-}
      pokeAcls acls aclvPtr aclPtr
    where
      count = length acls

      pokeAcls [] aclvPtr _              = cont aclvPtr
      pokeAcls (acl:rest) aclvPtr aclPtr = do
        withCString (aclScheme acl) $ \schemePtr -> do
          withCString (aclId acl) $ \idPtr -> do
            ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) aclPtr idPtr
{-# LINE 199 "src/Database/Zookeeper/CApi.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) aclPtr (fromPerms (aclFlags acl))
{-# LINE 200 "src/Database/Zookeeper/CApi.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) aclPtr schemePtr
{-# LINE 201 "src/Database/Zookeeper/CApi.hsc" #-}
            pokeAcls rest aclvPtr (aclPtr `plusPtr` ((24)))
{-# LINE 202 "src/Database/Zookeeper/CApi.hsc" #-}

toZKError :: CInt -> ZKError
toZKError (-101)                  = NoNodeError
{-# LINE 205 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-102)                  = NoAuthError
{-# LINE 206 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-116)                 = ClosingError
{-# LINE 207 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-117)                 = NothingError
{-# LINE 208 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-100)                = ApiError
{-# LINE 209 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-111)                = NotEmptyError
{-# LINE 210 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-103)              = BadVersionError
{-# LINE 211 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-114)              = InvalidACLError
{-# LINE 212 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-115)              = AuthFailedError
{-# LINE 213 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-110)              = NodeExistsError
{-# LINE 214 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-1)             = SystemError
{-# LINE 215 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-8)            = BadArgumentsError
{-# LINE 216 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-9)            = InvalidStateError
{-# LINE 217 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-118)            = SessionMovedError
{-# LINE 218 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-6)           = UnimplmenetedError
{-# LINE 219 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-4)          = ConnectionLossError
{-# LINE 220 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-112)          = SessionExpiredError
{-# LINE 221 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-113)         = InvalidCallbackError
{-# LINE 222 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-5)        = MarshallingError
{-# LINE 223 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-7)        = OperationTimeoutError
{-# LINE 224 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-3)       = DataInconsistencyError
{-# LINE 225 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-2)    = RuntimeInconsistencyError
{-# LINE 226 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError (-108) = NoChildrenForEphemeralsError
{-# LINE 227 "src/Database/Zookeeper/CApi.hsc" #-}
toZKError code                              = (UnknownError $ fromIntegral code)

toState :: CInt -> State
toState (3)       = ConnectedState
{-# LINE 231 "src/Database/Zookeeper/CApi.hsc" #-}
toState (1)      = ConnectingState
{-# LINE 232 "src/Database/Zookeeper/CApi.hsc" #-}
toState (2)     = AssociatingState
{-# LINE 233 "src/Database/Zookeeper/CApi.hsc" #-}
toState (-113)     = AuthFailedState
{-# LINE 234 "src/Database/Zookeeper/CApi.hsc" #-}
toState (-112) = ExpiredSessionState
{-# LINE 235 "src/Database/Zookeeper/CApi.hsc" #-}
toState code                               = UnknownState $ fromIntegral code

toEvent :: CInt -> Event
toEvent (4)       = ChildEvent
{-# LINE 239 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent (1)     = CreatedEvent
{-# LINE 240 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent (2)     = DeletedEvent
{-# LINE 241 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent (3)     = ChangedEvent
{-# LINE 242 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent (-1)     = SessionEvent
{-# LINE 243 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent (-2) = NotWatchingEvent
{-# LINE 244 "src/Database/Zookeeper/CApi.hsc" #-}
toEvent code                           = UnknownEvent $ fromIntegral code

wrapWatcher :: Maybe Watcher -> IO (FunPtr CWatcherFn)
wrapWatcher Nothing   = return nullFunPtr
wrapWatcher (Just fn) = c_watcherFn $ \zh cevent cstate cpath _ -> do
  let event = toEvent cevent
      state = toState cstate
  path <- if (cpath == nullPtr)
            then return Nothing
            else fmap Just (peekCString cpath)
  fn (Zookeeper zh) event state path

wrapAclCompletion :: AclCompletion -> IO (FunPtr CAclCompletionFn)
wrapAclCompletion fn =
  c_aclCompletionFn $ \rc aclPtr statPtr _ ->
    fn =<< (onZOK rc $ do
      aclList <- toAclList aclPtr
      stat    <- toStat statPtr
      return (aclList, stat))

wrapDataCompletion :: DataCompletion -> IO (FunPtr CDataCompletionFn)
wrapDataCompletion fn =
  c_dataCompletionFn $ \rc valPtr valLen statPtr _ ->
    fn =<< (onZOK rc $ do
      stat <- toStat statPtr
      if (valLen == -1)
        then return (Nothing, stat)
        else fmap (\s -> (Just s, stat)) (B.packCStringLen (valPtr, fromIntegral valLen)))

wrapStringCompletion :: StringCompletion -> IO (FunPtr CStringCompletionFn)
wrapStringCompletion fn =
  c_stringCompletionFn $ \rc strPtr _ ->
    fn =<< (onZOK rc $ do
      peekCString strPtr)

wrapStringsCompletion :: StringsCompletion -> IO (FunPtr CStringsCompletionFn)
wrapStringsCompletion fn =
  c_stringsCompletionFn $ \rc strvPtr _ ->
    fn =<< (onZOK rc (toStringList strvPtr))

wrapVoidCompletion :: VoidCompletion -> IO (FunPtr CVoidCompletionFn)
wrapVoidCompletion fn =
  c_voidCompletionFn $ \rc _ -> (fn =<< onZOK rc (return ()))

foreign import ccall safe "wrapper"
  c_watcherFn :: CWatcherFn
                 -> IO (FunPtr CWatcherFn)

foreign import ccall safe "wrapper"
  c_dataCompletionFn :: CDataCompletionFn
                        -> IO (FunPtr CDataCompletionFn)

foreign import ccall safe "wrapper"
  c_stringsCompletionFn :: CStringsCompletionFn
                        -> IO (FunPtr CStringsCompletionFn)

foreign import ccall safe "wrapper"
  c_stringCompletionFn :: CStringCompletionFn
                       -> IO (FunPtr CStringCompletionFn)

foreign import ccall safe "wrapper"
  c_aclCompletionFn :: CAclCompletionFn
                    -> IO (FunPtr CAclCompletionFn)

foreign import ccall safe "wrapper"
  c_voidCompletionFn :: CVoidCompletionFn
                     -> IO (FunPtr CVoidCompletionFn)

foreign import ccall safe "zookeeper.h zookeeper_init"
  c_zookeeperInit :: CString
                  -> FunPtr CWatcherFn
                  -> CInt
                  -> Ptr CClientID
                  -> Ptr ()
                  -> CInt
                  -> IO (Ptr CZHandle)

foreign import ccall safe "zookeeper.h zookeeper_close"
  c_zookeeperClose :: Ptr CZHandle -> IO ()

foreign import ccall safe "zookeeper.h zoo_set_watcher"
  c_zooSetWatcher :: Ptr CZHandle -> FunPtr CWatcherFn -> IO ()

foreign import ccall safe "zookeeper.h zoo_acreate"
  c_zooACreate :: Ptr CZHandle -> CString -> CString -> CInt -> Ptr CAclVec -> CInt -> FunPtr CStringCompletionFn -> Ptr () -> IO CInt

foreign import ccall safe "zookeeper.h zoo_delete"
  c_zooDelete :: Ptr CZHandle -> CString -> CInt -> IO CInt

foreign import ccall safe "zookeeper.h zoo_wexists"
  c_zooWExists :: Ptr CZHandle -> CString -> FunPtr CWatcherFn -> Ptr () -> Ptr CStat -> IO CInt

foreign import ccall safe "zookeeper.h zoo_state"
  c_zooState :: Ptr CZHandle -> IO CInt

foreign import ccall safe "zookeeper.h zoo_client_id"
  c_zooClientId :: Ptr CZHandle -> IO (Ptr CClientID)

foreign import ccall safe "zookeeper.h zoo_recv_timeout"
  c_zooRecvTimeout :: Ptr CZHandle -> IO CInt

foreign import ccall safe "zookeeper.h zoo_add_auth"
  c_zooAddAuth :: Ptr CZHandle -> CString -> CString -> CInt -> FunPtr CVoidCompletionFn -> Ptr () -> IO CInt

foreign import ccall safe "zookeeper.h is_unrecoverable"
  c_isUnrecoverable :: Ptr CZHandle -> IO CInt

foreign import ccall safe "zookeeper.h zoo_set_debug_level"
  c_zooSetDebugLevel :: CInt -> IO ()

foreign import ccall safe "zookeeper.h zoo_aget_acl"
  c_zooAGetAcl :: Ptr CZHandle -> CString -> FunPtr CAclCompletionFn -> Ptr () -> IO CInt

foreign import ccall safe "zookeeper.h zoo_set_acl"
  c_zooSetAcl :: Ptr CZHandle -> CString -> CInt -> Ptr CAclVec -> IO CInt

foreign import ccall safe "zookeeper.h zoo_awget"
  c_zooAWGet :: Ptr CZHandle -> CString -> FunPtr CWatcherFn -> Ptr () -> FunPtr CDataCompletionFn -> Ptr () -> IO CInt

foreign import ccall safe "zookeeper.h zoo_set2"
  c_zooSet2 :: Ptr CZHandle -> CString -> CString -> CInt -> CInt -> Ptr CStat -> IO CInt

foreign import ccall safe "zookeeper.h zoo_awget_children"
  c_zooAWGetChildren :: Ptr CZHandle -> CString -> FunPtr CWatcherFn -> Ptr () -> FunPtr CStringsCompletionFn -> Ptr () -> IO CInt

foreign import ccall safe "zookeeper.h &ZOO_CREATOR_ALL_ACL"
  c_zooCreatorAclAll :: Ptr CAclVec

foreign import ccall safe "zookeeper.h &ZOO_OPEN_ACL_UNSAFE"
  c_zooOpenAclUnsafe :: Ptr CAclVec

foreign import ccall safe "zookeeper.h &ZOO_READ_ACL_UNSAFE"
  c_zooReadAclUnsafe :: Ptr CAclVec