{- |
Copyright  : Will Thompson, Iñaki García Etxebarria and Jonas Platte
License    : LGPL-2.1
Maintainer : Iñaki García Etxebarria (inaki@blueleaf.cc)

'GI.Gio.Interfaces.Seekable.Seekable' is implemented by streams (implementations of
'GI.Gio.Objects.InputStream.InputStream' or 'GI.Gio.Objects.OutputStream.OutputStream') that support seeking.

Seekable streams largely fall into two categories: resizable and
fixed-size.

'GI.Gio.Interfaces.Seekable.Seekable' on fixed-sized streams is approximately the same as POSIX
@/lseek()/@ on a block device (for example: attempting to seek past the
end of the device is an error).  Fixed streams typically cannot be
truncated.

'GI.Gio.Interfaces.Seekable.Seekable' on resizable streams is approximately the same as POSIX
@/lseek()/@ on a normal file.  Seeking past the end and writing data will
usually cause the stream to resize by introducing zero bytes.
-}

#define ENABLE_OVERLOADING (MIN_VERSION_haskell_gi_overloading(1,0,0) \
       && !defined(__HADDOCK_VERSION__))

module GI.Gio.Interfaces.Seekable
    (

-- * Exported types
    Seekable(..)                            ,
    noSeekable                              ,
    IsSeekable                              ,
    toSeekable                              ,


 -- * Methods
-- ** canSeek #method:canSeek#

#if ENABLE_OVERLOADING
    SeekableCanSeekMethodInfo               ,
#endif
    seekableCanSeek                         ,


-- ** canTruncate #method:canTruncate#

#if ENABLE_OVERLOADING
    SeekableCanTruncateMethodInfo           ,
#endif
    seekableCanTruncate                     ,


-- ** seek #method:seek#

#if ENABLE_OVERLOADING
    SeekableSeekMethodInfo                  ,
#endif
    seekableSeek                            ,


-- ** tell #method:tell#

#if ENABLE_OVERLOADING
    SeekableTellMethodInfo                  ,
#endif
    seekableTell                            ,


-- ** truncate #method:truncate#

#if ENABLE_OVERLOADING
    SeekableTruncateMethodInfo              ,
#endif
    seekableTruncate                        ,




    ) where

import Data.GI.Base.ShortPrelude
import qualified Data.GI.Base.ShortPrelude as SP
import qualified Data.GI.Base.Overloading as O
import qualified Prelude as P

import qualified Data.GI.Base.Attributes as GI.Attributes
import qualified Data.GI.Base.ManagedPtr as B.ManagedPtr
import qualified Data.GI.Base.GClosure as B.GClosure
import qualified Data.GI.Base.GError as B.GError
import qualified Data.GI.Base.GVariant as B.GVariant
import qualified Data.GI.Base.GValue as B.GValue
import qualified Data.GI.Base.GParamSpec as B.GParamSpec
import qualified Data.GI.Base.CallStack as B.CallStack
import qualified Data.GI.Base.Properties as B.Properties
import qualified Data.Text as T
import qualified Data.ByteString.Char8 as B
import qualified Data.Map as Map
import qualified Foreign.Ptr as FP
import qualified GHC.OverloadedLabels as OL

import qualified GI.GLib.Enums as GLib.Enums
import qualified GI.GObject.Objects.Object as GObject.Object
import {-# SOURCE #-} qualified GI.Gio.Objects.Cancellable as Gio.Cancellable

-- interface Seekable 
-- | Memory-managed wrapper type.
newtype Seekable = Seekable (ManagedPtr Seekable)
-- | A convenience alias for `Nothing` :: `Maybe` `Seekable`.
noSeekable :: Maybe Seekable
noSeekable = Nothing

#if ENABLE_OVERLOADING
type instance O.SignalList Seekable = SeekableSignalList
type SeekableSignalList = ('[ '("notify", GObject.Object.ObjectNotifySignalInfo)] :: [(Symbol, *)])

#endif

foreign import ccall "g_seekable_get_type"
    c_g_seekable_get_type :: IO GType

instance GObject Seekable where
    gobjectType = c_g_seekable_get_type


-- | Type class for types which can be safely cast to `Seekable`, for instance with `toSeekable`.
class (GObject o, O.IsDescendantOf Seekable o) => IsSeekable o
instance (GObject o, O.IsDescendantOf Seekable o) => IsSeekable o

instance O.HasParentTypes Seekable
type instance O.ParentTypes Seekable = '[GObject.Object.Object]

-- | Cast to `Seekable`, for types for which this is known to be safe. For general casts, use `Data.GI.Base.ManagedPtr.castTo`.
toSeekable :: (MonadIO m, IsSeekable o) => o -> m Seekable
toSeekable = liftIO . unsafeCastTo Seekable

#if ENABLE_OVERLOADING
instance O.HasAttributeList Seekable
type instance O.AttributeList Seekable = SeekableAttributeList
type SeekableAttributeList = ('[ ] :: [(Symbol, *)])
#endif

#if ENABLE_OVERLOADING
#endif

#if ENABLE_OVERLOADING
type family ResolveSeekableMethod (t :: Symbol) (o :: *) :: * where
    ResolveSeekableMethod "bindProperty" o = GObject.Object.ObjectBindPropertyMethodInfo
    ResolveSeekableMethod "bindPropertyFull" o = GObject.Object.ObjectBindPropertyFullMethodInfo
    ResolveSeekableMethod "canSeek" o = SeekableCanSeekMethodInfo
    ResolveSeekableMethod "canTruncate" o = SeekableCanTruncateMethodInfo
    ResolveSeekableMethod "forceFloating" o = GObject.Object.ObjectForceFloatingMethodInfo
    ResolveSeekableMethod "freezeNotify" o = GObject.Object.ObjectFreezeNotifyMethodInfo
    ResolveSeekableMethod "getv" o = GObject.Object.ObjectGetvMethodInfo
    ResolveSeekableMethod "isFloating" o = GObject.Object.ObjectIsFloatingMethodInfo
    ResolveSeekableMethod "notify" o = GObject.Object.ObjectNotifyMethodInfo
    ResolveSeekableMethod "notifyByPspec" o = GObject.Object.ObjectNotifyByPspecMethodInfo
    ResolveSeekableMethod "ref" o = GObject.Object.ObjectRefMethodInfo
    ResolveSeekableMethod "refSink" o = GObject.Object.ObjectRefSinkMethodInfo
    ResolveSeekableMethod "runDispose" o = GObject.Object.ObjectRunDisposeMethodInfo
    ResolveSeekableMethod "seek" o = SeekableSeekMethodInfo
    ResolveSeekableMethod "stealData" o = GObject.Object.ObjectStealDataMethodInfo
    ResolveSeekableMethod "stealQdata" o = GObject.Object.ObjectStealQdataMethodInfo
    ResolveSeekableMethod "tell" o = SeekableTellMethodInfo
    ResolveSeekableMethod "thawNotify" o = GObject.Object.ObjectThawNotifyMethodInfo
    ResolveSeekableMethod "truncate" o = SeekableTruncateMethodInfo
    ResolveSeekableMethod "unref" o = GObject.Object.ObjectUnrefMethodInfo
    ResolveSeekableMethod "watchClosure" o = GObject.Object.ObjectWatchClosureMethodInfo
    ResolveSeekableMethod "getData" o = GObject.Object.ObjectGetDataMethodInfo
    ResolveSeekableMethod "getProperty" o = GObject.Object.ObjectGetPropertyMethodInfo
    ResolveSeekableMethod "getQdata" o = GObject.Object.ObjectGetQdataMethodInfo
    ResolveSeekableMethod "setData" o = GObject.Object.ObjectSetDataMethodInfo
    ResolveSeekableMethod "setProperty" o = GObject.Object.ObjectSetPropertyMethodInfo
    ResolveSeekableMethod l o = O.MethodResolutionFailed l o

instance (info ~ ResolveSeekableMethod t Seekable, O.MethodInfo info Seekable p) => OL.IsLabel t (Seekable -> p) where
#if MIN_VERSION_base(4,10,0)
    fromLabel = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)
#else
    fromLabel _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)
#endif

#endif

-- method Seekable::can_seek
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "seekable", argType = TInterface (Name {namespace = "Gio", name = "Seekable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TBasicType TBoolean)
-- throws : False
-- Skip return : False

foreign import ccall "g_seekable_can_seek" g_seekable_can_seek ::
    Ptr Seekable ->                         -- seekable : TInterface (Name {namespace = "Gio", name = "Seekable"})
    IO CInt

{- |
Tests if the stream supports the 'GI.Gio.Structs.SeekableIface.SeekableIface'.
-}
seekableCanSeek ::
    (B.CallStack.HasCallStack, MonadIO m, IsSeekable a) =>
    a
    {- ^ /@seekable@/: a 'GI.Gio.Interfaces.Seekable.Seekable'. -}
    -> m Bool
    {- ^ __Returns:__ 'True' if /@seekable@/ can be seeked. 'False' otherwise. -}
seekableCanSeek seekable = liftIO $ do
    seekable' <- unsafeManagedPtrCastPtr seekable
    result <- g_seekable_can_seek seekable'
    let result' = (/= 0) result
    touchManagedPtr seekable
    return result'

#if ENABLE_OVERLOADING
data SeekableCanSeekMethodInfo
instance (signature ~ (m Bool), MonadIO m, IsSeekable a) => O.MethodInfo SeekableCanSeekMethodInfo a signature where
    overloadedMethod _ = seekableCanSeek

#endif

-- method Seekable::can_truncate
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "seekable", argType = TInterface (Name {namespace = "Gio", name = "Seekable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TBasicType TBoolean)
-- throws : False
-- Skip return : False

foreign import ccall "g_seekable_can_truncate" g_seekable_can_truncate ::
    Ptr Seekable ->                         -- seekable : TInterface (Name {namespace = "Gio", name = "Seekable"})
    IO CInt

{- |
Tests if the length of the stream can be adjusted with
'GI.Gio.Interfaces.Seekable.seekableTruncate'.
-}
seekableCanTruncate ::
    (B.CallStack.HasCallStack, MonadIO m, IsSeekable a) =>
    a
    {- ^ /@seekable@/: a 'GI.Gio.Interfaces.Seekable.Seekable'. -}
    -> m Bool
    {- ^ __Returns:__ 'True' if the stream can be truncated, 'False' otherwise. -}
seekableCanTruncate seekable = liftIO $ do
    seekable' <- unsafeManagedPtrCastPtr seekable
    result <- g_seekable_can_truncate seekable'
    let result' = (/= 0) result
    touchManagedPtr seekable
    return result'

#if ENABLE_OVERLOADING
data SeekableCanTruncateMethodInfo
instance (signature ~ (m Bool), MonadIO m, IsSeekable a) => O.MethodInfo SeekableCanTruncateMethodInfo a signature where
    overloadedMethod _ = seekableCanTruncate

#endif

-- method Seekable::seek
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "seekable", argType = TInterface (Name {namespace = "Gio", name = "Seekable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "offset", argType = TBasicType TInt64, direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #goffset.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "type", argType = TInterface (Name {namespace = "GLib", name = "SeekType"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekType.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "cancellable", argType = TInterface (Name {namespace = "Gio", name = "Cancellable"}), direction = DirectionIn, mayBeNull = True, argDoc = Documentation {rawDocText = Just "optional #GCancellable object, %NULL to ignore.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TBasicType TBoolean)
-- throws : True
-- Skip return : False

foreign import ccall "g_seekable_seek" g_seekable_seek ::
    Ptr Seekable ->                         -- seekable : TInterface (Name {namespace = "Gio", name = "Seekable"})
    Int64 ->                                -- offset : TBasicType TInt64
    CUInt ->                                -- type : TInterface (Name {namespace = "GLib", name = "SeekType"})
    Ptr Gio.Cancellable.Cancellable ->      -- cancellable : TInterface (Name {namespace = "Gio", name = "Cancellable"})
    Ptr (Ptr GError) ->                     -- error
    IO CInt

{- |
Seeks in the stream by the given /@offset@/, modified by /@type@/.

Attempting to seek past the end of the stream will have different
results depending on if the stream is fixed-sized or resizable.  If
the stream is resizable then seeking past the end and then writing
will result in zeros filling the empty space.  Seeking past the end
of a resizable stream and reading will result in EOF.  Seeking past
the end of a fixed-sized stream will fail.

Any operation that would result in a negative offset will fail.

If /@cancellable@/ is not 'Nothing', then the operation can be cancelled by
triggering the cancellable object from another thread. If the operation
was cancelled, the error 'GI.Gio.Enums.IOErrorEnumCancelled' will be returned.
-}
seekableSeek ::
    (B.CallStack.HasCallStack, MonadIO m, IsSeekable a, Gio.Cancellable.IsCancellable b) =>
    a
    {- ^ /@seekable@/: a 'GI.Gio.Interfaces.Seekable.Seekable'. -}
    -> Int64
    {- ^ /@offset@/: a @/goffset/@. -}
    -> GLib.Enums.SeekType
    {- ^ /@type@/: a 'GI.GLib.Enums.SeekType'. -}
    -> Maybe (b)
    {- ^ /@cancellable@/: optional 'GI.Gio.Objects.Cancellable.Cancellable' object, 'Nothing' to ignore. -}
    -> m ()
    {- ^ /(Can throw 'Data.GI.Base.GError.GError')/ -}
seekableSeek seekable offset type_ cancellable = liftIO $ do
    seekable' <- unsafeManagedPtrCastPtr seekable
    let type_' = (fromIntegral . fromEnum) type_
    maybeCancellable <- case cancellable of
        Nothing -> return nullPtr
        Just jCancellable -> do
            jCancellable' <- unsafeManagedPtrCastPtr jCancellable
            return jCancellable'
    onException (do
        _ <- propagateGError $ g_seekable_seek seekable' offset type_' maybeCancellable
        touchManagedPtr seekable
        whenJust cancellable touchManagedPtr
        return ()
     ) (do
        return ()
     )

#if ENABLE_OVERLOADING
data SeekableSeekMethodInfo
instance (signature ~ (Int64 -> GLib.Enums.SeekType -> Maybe (b) -> m ()), MonadIO m, IsSeekable a, Gio.Cancellable.IsCancellable b) => O.MethodInfo SeekableSeekMethodInfo a signature where
    overloadedMethod _ = seekableSeek

#endif

-- method Seekable::tell
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "seekable", argType = TInterface (Name {namespace = "Gio", name = "Seekable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TBasicType TInt64)
-- throws : False
-- Skip return : False

foreign import ccall "g_seekable_tell" g_seekable_tell ::
    Ptr Seekable ->                         -- seekable : TInterface (Name {namespace = "Gio", name = "Seekable"})
    IO Int64

{- |
Tells the current position within the stream.
-}
seekableTell ::
    (B.CallStack.HasCallStack, MonadIO m, IsSeekable a) =>
    a
    {- ^ /@seekable@/: a 'GI.Gio.Interfaces.Seekable.Seekable'. -}
    -> m Int64
    {- ^ __Returns:__ the offset from the beginning of the buffer. -}
seekableTell seekable = liftIO $ do
    seekable' <- unsafeManagedPtrCastPtr seekable
    result <- g_seekable_tell seekable'
    touchManagedPtr seekable
    return result

#if ENABLE_OVERLOADING
data SeekableTellMethodInfo
instance (signature ~ (m Int64), MonadIO m, IsSeekable a) => O.MethodInfo SeekableTellMethodInfo a signature where
    overloadedMethod _ = seekableTell

#endif

-- method Seekable::truncate
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "seekable", argType = TInterface (Name {namespace = "Gio", name = "Seekable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GSeekable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "offset", argType = TBasicType TInt64, direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "new length for @seekable, in bytes.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "cancellable", argType = TInterface (Name {namespace = "Gio", name = "Cancellable"}), direction = DirectionIn, mayBeNull = True, argDoc = Documentation {rawDocText = Just "optional #GCancellable object, %NULL to ignore.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TBasicType TBoolean)
-- throws : True
-- Skip return : False

foreign import ccall "g_seekable_truncate" g_seekable_truncate ::
    Ptr Seekable ->                         -- seekable : TInterface (Name {namespace = "Gio", name = "Seekable"})
    Int64 ->                                -- offset : TBasicType TInt64
    Ptr Gio.Cancellable.Cancellable ->      -- cancellable : TInterface (Name {namespace = "Gio", name = "Cancellable"})
    Ptr (Ptr GError) ->                     -- error
    IO CInt

{- |
Sets the length of the stream to /@offset@/. If the stream was previously
larger than /@offset@/, the extra data is discarded. If the stream was
previouly shorter than /@offset@/, it is extended with NUL (\'\\0\') bytes.

If /@cancellable@/ is not 'Nothing', then the operation can be cancelled by
triggering the cancellable object from another thread. If the operation
was cancelled, the error 'GI.Gio.Enums.IOErrorEnumCancelled' will be returned. If an
operation was partially finished when the operation was cancelled the
partial result will be returned, without an error.
-}
seekableTruncate ::
    (B.CallStack.HasCallStack, MonadIO m, IsSeekable a, Gio.Cancellable.IsCancellable b) =>
    a
    {- ^ /@seekable@/: a 'GI.Gio.Interfaces.Seekable.Seekable'. -}
    -> Int64
    {- ^ /@offset@/: new length for /@seekable@/, in bytes. -}
    -> Maybe (b)
    {- ^ /@cancellable@/: optional 'GI.Gio.Objects.Cancellable.Cancellable' object, 'Nothing' to ignore. -}
    -> m ()
    {- ^ /(Can throw 'Data.GI.Base.GError.GError')/ -}
seekableTruncate seekable offset cancellable = liftIO $ do
    seekable' <- unsafeManagedPtrCastPtr seekable
    maybeCancellable <- case cancellable of
        Nothing -> return nullPtr
        Just jCancellable -> do
            jCancellable' <- unsafeManagedPtrCastPtr jCancellable
            return jCancellable'
    onException (do
        _ <- propagateGError $ g_seekable_truncate seekable' offset maybeCancellable
        touchManagedPtr seekable
        whenJust cancellable touchManagedPtr
        return ()
     ) (do
        return ()
     )

#if ENABLE_OVERLOADING
data SeekableTruncateMethodInfo
instance (signature ~ (Int64 -> Maybe (b) -> m ()), MonadIO m, IsSeekable a, Gio.Cancellable.IsCancellable b) => O.MethodInfo SeekableTruncateMethodInfo a signature where
    overloadedMethod _ = seekableTruncate

#endif