    {- |
    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.Initable.Initable' is implemented by objects that can fail during
    initialization. If an object implements this interface then
    it must be initialized as the first thing after construction,
    either via 'GI.Gio.Interfaces.Initable.initableInit' or 'GI.Gio.Interfaces.AsyncInitable.asyncInitableInitAsync'
    (the latter is only available if it also implements 'GI.Gio.Interfaces.AsyncInitable.AsyncInitable').

    If the object is not initialized, or initialization returns with an
    error, then all operations on the object except 'GI.GObject.Objects.Object.objectRef' and
    'GI.GObject.Objects.Object.objectUnref' are considered to be invalid, and have undefined
    behaviour. They will often fail with @/g_critical()/@ or @/g_warning()/@, but
    this must not be relied on.

    Users of objects implementing this are not intended to use
    the interface method directly, instead it will be used automatically
    in various ways. For C applications you generally just call
    @/g_initable_new()/@ directly, or indirectly via a @/foo_thing_new()/@ wrapper.
    This will call 'GI.Gio.Interfaces.Initable.initableInit' under the cover, returning 'Nothing' and
    setting a 'GError' on failure (at which point the instance is
    unreferenced).

    For bindings in languages where the native constructor supports
    exceptions the binding could check for objects implemention @/GInitable/@
    during normal construction and automatically initialize them, throwing
    an exception on failure.

    /Since: 2.22/
    -}

    #define ENABLE_OVERLOADING \
           (!defined(__HADDOCK_VERSION__))

    module GI.Gio.Interfaces.Initable
        (

    -- * Exported types
        Initable(..)                            ,
        noInitable                              ,
        IsInitable                              ,
        toInitable                              ,

     -- * Methods
    -- ** init #method:init#

    #if ENABLE_OVERLOADING
        InitableInitMethodInfo                  ,
    #endif
        initableInit                            ,

    -- ** newv #method:newv#

        initableNewv                            ,

        ) 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.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.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.GObject.Objects.Object as GObject.Object
    import qualified GI.GObject.Structs.Parameter as GObject.Parameter
    import {-# SOURCE #-} qualified GI.Gio.Objects.Cancellable as Gio.Cancellable

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

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

    #endif

    foreign import ccall "g_initable_get_type"
        c_g_initable_get_type :: IO GType

    instance GObject Initable where
        gobjectType _ = c_g_initable_get_type

    -- | Type class for types which can be safely cast to `Initable`, for instance with `toInitable`.
    class GObject o => IsInitable o
    #if MIN_VERSION_base(4,9,0)
    instance {-# OVERLAPPABLE #-} (GObject a, O.UnknownAncestorError Initable a) =>
        IsInitable a
    #endif
    instance IsInitable Initable
    instance GObject.Object.IsObject Initable

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

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

    #if ENABLE_OVERLOADING
    #endif

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

    instance (info ~ ResolveInitableMethod t Initable, O.MethodInfo info Initable p) => O.IsLabelProxy t (Initable -> p) where
        fromLabelProxy _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)

    #if MIN_VERSION_base(4,9,0)
    instance (info ~ ResolveInitableMethod t Initable, O.MethodInfo info Initable p) => O.IsLabel t (Initable -> 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

    #endif

    -- method Initable::init
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "initable", argType = TInterface (Name {namespace = "Gio", name = "Initable"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GInitable.", 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_initable_init" g_initable_init ::
        Ptr Initable ->                         -- initable : TInterface (Name {namespace = "Gio", name = "Initable"})
        Ptr Gio.Cancellable.Cancellable ->      -- cancellable : TInterface (Name {namespace = "Gio", name = "Cancellable"})
        Ptr (Ptr GError) ->                     -- error
        IO CInt

    {- |
    Initializes the object implementing the interface.

    This method is intended for language bindings. If writing in C,
    @/g_initable_new()/@ should typically be used instead.

    The object must be initialized before any real use after initial
    construction, either with this function or 'GI.Gio.Interfaces.AsyncInitable.asyncInitableInitAsync'.

    Implementations may also support cancellation. If /@cancellable@/ is not 'Nothing',
    then initialization 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 /@cancellable@/ is not 'Nothing' and
    the object doesn\'t support cancellable initialization the error
    'GI.Gio.Enums.IOErrorEnumNotSupported' will be returned.

    If the object is not initialized, or initialization returns with an
    error, then all operations on the object except 'GI.GObject.Objects.Object.objectRef' and
    'GI.GObject.Objects.Object.objectUnref' are considered to be invalid, and have undefined
    behaviour. See the [introduction][ginitable] for more details.

    Callers should not assume that a class which implements 'GI.Gio.Interfaces.Initable.Initable' can be
    initialized multiple times, unless the class explicitly documents itself as
    supporting this. Generally, a class’ implementation of @/init()/@ can assume
    (and assert) that it will only be called once. Previously, this documentation
    recommended all 'GI.Gio.Interfaces.Initable.Initable' implementations should be idempotent; that
    recommendation was relaxed in GLib 2.54.

    If a class explicitly supports being initialized multiple times, it is
    recommended that the method is idempotent: multiple calls with the same
    arguments should return the same results. Only the first call initializes
    the object; further calls return the result of the first call.

    One reason why a class might need to support idempotent initialization is if
    it is designed to be used via the singleton pattern, with a
    'GI.GObject.Structs.ObjectClass.ObjectClass'.@/constructor/@ that sometimes returns an existing instance.
    In this pattern, a caller would expect to be able to call 'GI.Gio.Interfaces.Initable.initableInit'
    on the result of @/g_object_new()/@, regardless of whether it is in fact a new
    instance.

    /Since: 2.22/
    -}
    initableInit ::
        (B.CallStack.HasCallStack, MonadIO m, IsInitable a, Gio.Cancellable.IsCancellable b) =>
        a
        {- ^ /@initable@/: a 'GI.Gio.Interfaces.Initable.Initable'. -}
        -> Maybe (b)
        {- ^ /@cancellable@/: optional 'GI.Gio.Objects.Cancellable.Cancellable' object, 'Nothing' to ignore. -}
        -> m ()
        {- ^ /(Can throw 'Data.GI.Base.GError.GError')/ -}
    initableInit initable cancellable = liftIO $ do
        initable' <- unsafeManagedPtrCastPtr initable
        maybeCancellable <- case cancellable of
            Nothing -> return nullPtr
            Just jCancellable -> do
                jCancellable' <- unsafeManagedPtrCastPtr jCancellable
                return jCancellable'
        onException (do
            _ <- propagateGError $ g_initable_init initable' maybeCancellable
            touchManagedPtr initable
            whenJust cancellable touchManagedPtr
            return ()
         ) (do
            return ()
         )

    #if ENABLE_OVERLOADING
    data InitableInitMethodInfo
    instance (signature ~ (Maybe (b) -> m ()), MonadIO m, IsInitable a, Gio.Cancellable.IsCancellable b) => O.MethodInfo InitableInitMethodInfo a signature where
        overloadedMethod _ = initableInit

    #endif

    -- method Initable::newv
    -- method type : MemberFunction
    -- Args : [Arg {argCName = "object_type", argType = TBasicType TGType, direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GType supporting #GInitable.", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "n_parameters", argType = TBasicType TUInt, direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "the number of parameters in @parameters", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "parameters", argType = TCArray False (-1) 1 (TInterface (Name {namespace = "GObject", name = "Parameter"})), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "the parameters to use to construct the object", 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 : [Arg {argCName = "n_parameters", argType = TBasicType TUInt, direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "the number of parameters in @parameters", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- returnType : Just (TInterface (Name {namespace = "GObject", name = "Object"}))
    -- throws : True
    -- Skip return : False

    foreign import ccall "g_initable_newv" g_initable_newv ::
        CGType ->                               -- object_type : TBasicType TGType
        Word32 ->                               -- n_parameters : TBasicType TUInt
        Ptr GObject.Parameter.Parameter ->      -- parameters : TCArray False (-1) 1 (TInterface (Name {namespace = "GObject", name = "Parameter"}))
        Ptr Gio.Cancellable.Cancellable ->      -- cancellable : TInterface (Name {namespace = "Gio", name = "Cancellable"})
        Ptr (Ptr GError) ->                     -- error
        IO (Ptr GObject.Object.Object)

    {-# DEPRECATED initableNewv ["(Since version 2.54)","Use @/g_object_new_with_properties()/@ and","'GI.Gio.Interfaces.Initable.initableInit' instead. See 'GI.GObject.Structs.Parameter.Parameter' for more information."] #-}
    {- |
    Helper function for constructing 'GI.Gio.Interfaces.Initable.Initable' object. This is
    similar to 'GI.GObject.Objects.Object.objectNewv' but also initializes the object
    and returns 'Nothing', setting an error on failure.

    /Since: 2.22/
    -}
    initableNewv ::
        (B.CallStack.HasCallStack, MonadIO m, Gio.Cancellable.IsCancellable a) =>
        GType
        {- ^ /@objectType@/: a 'GType' supporting 'GI.Gio.Interfaces.Initable.Initable'. -}
        -> [GObject.Parameter.Parameter]
        {- ^ /@parameters@/: the parameters to use to construct the object -}
        -> Maybe (a)
        {- ^ /@cancellable@/: optional 'GI.Gio.Objects.Cancellable.Cancellable' object, 'Nothing' to ignore. -}
        -> m GObject.Object.Object
        {- ^ __Returns:__ a newly allocated
         'GI.GObject.Objects.Object.Object', or 'Nothing' on error /(Can throw 'Data.GI.Base.GError.GError')/ -}
    initableNewv objectType parameters cancellable = liftIO $ do
        let nParameters = fromIntegral $ length parameters
        let objectType' = gtypeToCGType objectType
        parameters' <- mapM unsafeManagedPtrGetPtr parameters
        parameters'' <- packBlockArray 32 parameters'
        maybeCancellable <- case cancellable of
            Nothing -> return nullPtr
            Just jCancellable -> do
                jCancellable' <- unsafeManagedPtrCastPtr jCancellable
                return jCancellable'
        onException (do
            result <- propagateGError $ g_initable_newv objectType' nParameters parameters'' maybeCancellable
            checkUnexpectedReturnNULL "initableNewv" result
            result' <- (wrapObject GObject.Object.Object) result
            mapM_ touchManagedPtr parameters
            whenJust cancellable touchManagedPtr
            freeMem parameters''
            return result'
         ) (do
            freeMem parameters''
         )

    #if ENABLE_OVERLOADING
    #endif