{-# LINE 1 "src/Database/EJDB2/KV.hsc" #-}
{-# LANGUAGE CPP #-}

module Database.EJDB2.KV
        ( OpenFlags
        , readonlyOpenFlags
        , truncateOpenFlags
        , noTrimOnCloseOpenFlags
        , Options(..)
        , zero
        , OptionsB
        , build
        , options
        ) where

import           Foreign
import           Foreign.C.String
import           Foreign.C.Types

import qualified Database.EJDB2.WAL as WAL


-- | Database file open modes.
newtype OpenFlags = OpenFlags { unOpenFlags :: CUChar }

-- | Open storage file in read-only mode.
readonlyOpenFlags :: OpenFlags
readonlyOpenFlags = OpenFlags 2
{-# LINE 28 "src/Database/EJDB2/KV.hsc" #-}

-- | Truncate storage file on open.
truncateOpenFlags :: OpenFlags
truncateOpenFlags         = OpenFlags 4
{-# LINE 32 "src/Database/EJDB2/KV.hsc" #-}

noTrimOnCloseOpenFlags :: OpenFlags
noTrimOnCloseOpenFlags    = OpenFlags 8
{-# LINE 35 "src/Database/EJDB2/KV.hsc" #-}

allOpenFlags :: [OpenFlags]
allOpenFlags = [readonlyOpenFlags, truncateOpenFlags, noTrimOnCloseOpenFlags]

combineOpenFlags :: [OpenFlags] -> OpenFlags
combineOpenFlags = OpenFlags . foldr ((.|.) . unOpenFlags) 0

unCombineOpenFlags :: OpenFlags -> [OpenFlags]
unCombineOpenFlags (OpenFlags (CUChar oflags)) = filter f allOpenFlags
          where
            f = \(OpenFlags (CUChar value)) -> value .&. oflags /= 0

-- | IWKV storage open options
data Options =
    Options { path :: Maybe String -- ^ Path to database file
            , randomSeed :: !Word32 -- ^ Random seed used for iwu random generator
            , fmtVersion :: !Int32 -- ^ Database storage format version. Leave it as zero for the latest supported format. Used only for newly created databases
            , oflags :: ![OpenFlags] -- ^ Database file open modes
            , fileLockFailFast :: !Bool -- ^ Do not wait and raise error if database is locked by another process
            , wal :: !WAL.Options
            }

-- | Create default Options
zero :: Options
zero = Options { path = Nothing
                 , randomSeed = 0
                 , fmtVersion = 0
                 , oflags = []
                 , fileLockFailFast = False
                 , wal = WAL.zero
                 }

-- | Storable version of Options
data OptionsB =
    OptionsB { options :: Options
             , pathPtr :: ForeignPtr CChar
             }

-- | Create Storable version of Options
build :: Options -> IO OptionsB
build options = do
        pathPtr <- maybeNew newCString (path options)
        pathFPtr <- newForeignPtr finalizerFree pathPtr
        return OptionsB { options = options
                        , pathPtr = pathFPtr
                        }

instance Storable OptionsB where
        sizeOf _ = (72)
{-# LINE 84 "src/Database/EJDB2/KV.hsc" #-}
        alignment _  = 8
{-# LINE 85 "src/Database/EJDB2/KV.hsc" #-}
        peek ptr = do
                pathPtr <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 87 "src/Database/EJDB2/KV.hsc" #-}
                pathFPtr <- newForeignPtr finalizerFree nullPtr -- I'm just reading the pointer, I'm not responsable to free memory about this pointer.
                path <- maybePeek peekCString pathPtr
                random_seed <- (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 90 "src/Database/EJDB2/KV.hsc" #-}
                fmt_version <- (\hsc_ptr -> peekByteOff hsc_ptr 12) ptr
{-# LINE 91 "src/Database/EJDB2/KV.hsc" #-}
                oflags <- (\hsc_ptr -> peekByteOff hsc_ptr 16) ptr
{-# LINE 92 "src/Database/EJDB2/KV.hsc" #-}
                file_lock_fail_fast <- (\hsc_ptr -> peekByteOff hsc_ptr 17) ptr
{-# LINE 93 "src/Database/EJDB2/KV.hsc" #-}
                wal <- (\hsc_ptr -> peekByteOff hsc_ptr 24) ptr
{-# LINE 94 "src/Database/EJDB2/KV.hsc" #-}
                let options = Options
                                path
                                random_seed
                                fmt_version
                                (unCombineOpenFlags $ OpenFlags oflags)
                                file_lock_fail_fast
                                wal
                return $ OptionsB options pathFPtr
        poke ptr (OptionsB (Options path random_seed fmt_version oflags file_lock_fail_fast wal) pathPtr) = do
                withForeignPtr pathPtr $ \cPath ->
                  (\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr cPath
{-# LINE 105 "src/Database/EJDB2/KV.hsc" #-}
                (\hsc_ptr -> pokeByteOff hsc_ptr 8) ptr random_seed
{-# LINE 106 "src/Database/EJDB2/KV.hsc" #-}
                (\hsc_ptr -> pokeByteOff hsc_ptr 12) ptr fmt_version
{-# LINE 107 "src/Database/EJDB2/KV.hsc" #-}
                (\hsc_ptr -> pokeByteOff hsc_ptr 16) ptr (unOpenFlags $ combineOpenFlags oflags)
{-# LINE 108 "src/Database/EJDB2/KV.hsc" #-}
                (\hsc_ptr -> pokeByteOff hsc_ptr 17) ptr file_lock_fail_fast
{-# LINE 109 "src/Database/EJDB2/KV.hsc" #-}
                (\hsc_ptr -> pokeByteOff hsc_ptr 24) ptr wal
{-# LINE 110 "src/Database/EJDB2/KV.hsc" #-}