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

'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: attmepting 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.
-}

module GI.Gio.Interfaces.Seekable
    ( 

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


 -- * Methods
-- ** canSeek #method:canSeek#
    SeekableCanSeekMethodInfo               ,
    seekableCanSeek                         ,


-- ** canTruncate #method:canTruncate#
    SeekableCanTruncateMethodInfo           ,
    seekableCanTruncate                     ,


-- ** seek #method:seek#
    SeekableSeekMethodInfo                  ,
    seekableSeek                            ,


-- ** tell #method:tell#
    SeekableTellMethodInfo                  ,
    seekableTell                            ,


-- ** truncate #method:truncate#
    SeekableTruncateMethodInfo              ,
    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.GError as B.GError
import qualified Data.GI.Base.GVariant as B.GVariant
import qualified Data.GI.Base.GParamSpec as B.GParamSpec
import qualified Data.GI.Base.CallStack as B.CallStack
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 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 
newtype Seekable = Seekable (ManagedPtr Seekable)
noSeekable :: Maybe Seekable
noSeekable = Nothing

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

foreign import ccall "g_seekable_get_type"
    c_g_seekable_get_type :: IO GType

instance GObject Seekable where
    gobjectType _ = c_g_seekable_get_type
    

class GObject o => IsSeekable o
#if MIN_VERSION_base(4,9,0)
instance {-# OVERLAPPABLE #-} (GObject a, O.UnknownAncestorError Seekable a) =>
    IsSeekable a
#endif
instance IsSeekable Seekable
instance GObject.Object.IsObject Seekable

toSeekable :: IsSeekable o => o -> IO Seekable
toSeekable = unsafeCastTo Seekable

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

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 "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 "replaceData" o = GObject.Object.ObjectReplaceDataMethodInfo
    ResolveSeekableMethod "replaceQdata" o = GObject.Object.ObjectReplaceQdataMethodInfo
    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) => O.IsLabelProxy t (Seekable -> p) where
    fromLabelProxy _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)

#if MIN_VERSION_base(4,9,0)
instance (info ~ ResolveSeekableMethod t Seekable, O.MethodInfo info Seekable p) => O.IsLabel t (Seekable -> p) where
    fromLabel _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)
#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'

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

-- 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 stream can be truncated.
-}
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'

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

-- 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 ()
     )

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

-- 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

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

-- 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 "a #goffset.", 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

{- |
Truncates a stream with a given @/offset/@.

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@/: a @/goffset/@. -}
    -> 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 ()
     )

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