                                           fromIntegral cur)
                    else return Nothing
 
+-- | Query an element for its stream duration.
 elementQueryDuration :: ElementClass element
-                     => element
-                     -> Format
-                     -> IO (Maybe (Format, Word64))
+                     => element -- ^ @element@ - the element to query
+                     -> Format -- ^ @format@ - the format requested
+                     -> IO (Maybe (Format, Word64)) -- ^ the resulting format and value
 elementQueryDuration element format =
     alloca $ \formatPtr ->
         alloca $ \durationPtr ->

  elementSendEvent, 
  elementSeekSimple,
  elementSeek,
  onElementNoMorePads,
  afterElementNoMorePads,
  onElementPadAdded,
  afterElementPadAdded,
  onElementPadRemoved,
  afterElementPadRemoved
  
  ) where



{# context lib = "gstreamer" prefix = "gst" #}

-- | Get the flags set on the element.
elementGetFlags :: ElementClass elementT
                => elementT
                -> IO [ElementFlags]
elementGetFlags = mkObjectGetFlags

-- | Set the given flags on the element.
elementSetFlags :: ElementClass elementT
                => elementT
                -> [ElementFlags]
                -> IO ()
elementSetFlags = mkObjectSetFlags

-- | Unset the given flags on the element.
elementUnsetFlags :: ElementClass elementT
                  => elementT
                  -> [ElementFlags]
                  -> IO ()
elementUnsetFlags = mkObjectUnsetFlags

-- | Add a pad (link point) to an element. The pad's parent will be set to
--   @element@.
--   
--   Pads are not automatically activated so elements should perform
--   the needed steps to activate the pad in case this pad is added in
--   the 'StatePaused' or 'StatePlaying' state. See 'padSetActive' for
--   more information about activating pads.
--   
--   This function will emit the 'elementPadAdded' signal on the
--   element.
elementAddPad :: (ElementClass elementT, PadClass padT)
              => elementT -- ^ @element@ - 
              -> padT     -- ^ @pad@ - 
              -> IO Bool
elementAddPad element pad =
    liftM toBool $ {# call element_add_pad #} (toElement element) (toPad pad)

-- | Look for an unlinked pad to which the given pad can link. It is not
--   guaranteed that linking the pads will work, though it should work in most
--   cases.
elementGetCompatiblePad :: (ElementClass elementT, PadClass padT)
                        => elementT       -- ^ @element@ - the element for
                                          --   which a pad should be found
                        -> padT           -- ^ @pad@ - the pad to find
                                          --   a compatible one for
                        -> Caps           -- ^ @caps@ - the 'Caps' to
                                          --   use as a filter
                        -> IO (Maybe Pad) -- ^ the compatible 'Pad', or
                                          --   'Nothing' if none was found
elementGetCompatiblePad element pad caps =
    {# call element_get_compatible_pad #} (toElement element) (toPad pad) caps >>=
        maybePeek takeObject

-- | Retrieve a pad template from @element@ that is compatible with
--   @padTemplate@.  Pads from compatible templates can be linked
--   together.
elementGetCompatiblePadTemplate :: (ElementClass elementT, PadTemplateClass padTemplateT)
                                => elementT               -- ^ @element@ - 
                                -> padTemplateT           -- ^ @padTemplate@ - 
                                -> IO (Maybe PadTemplate) -- ^ the compatible'PadTemplate',
                                                          -- or 'Nothing' if none was found
elementGetCompatiblePadTemplate element padTemplate =
    {# call element_get_compatible_pad_template #} (toElement element) (toPadTemplate padTemplate) >>=
        maybePeek takeObject

-- | Retrieve a pad from the element by name. This version only
--   retrieves request pads. The pad should be released with
--   'elementReleaseRequestPad'.
elementGetRequestPad :: ElementClass elementT
                     => elementT       -- ^ @element@ - 
                     -> String         -- ^ @name@ - 
                     -> IO (Maybe Pad) -- ^ the requested 'Pad' if
                                       --   found, otherwise 'Nothing'.
elementGetRequestPad element name =
    (withUTFString name $ {# call element_get_request_pad #} (toElement element)) >>=
        maybePeek peekObject

-- | Retreive a pad from @element@ by name. This version only
--   retrieves already-existing (i.e. "static") pads.
elementGetStaticPad :: ElementClass elementT
                    => elementT -- ^ @element@ - 
                    -> String   -- ^ @name@ - 
                    -> IO (Maybe Pad) -- ^ the requested 'Pad' if
                                      --   found, otherwise 'Nothing'.
elementGetStaticPad element name =
    (withUTFString name $ {# call element_get_static_pad #} (toElement element)) >>=
        maybePeek takeObject

-- | Release a request pad that was previously obtained with
--   'elementGetRequestPad'.
elementReleaseRequestPad :: (ElementClass elementT, PadClass padT)
                         => elementT -- ^ @element@ - 
                         -> padT     -- ^ @pad@ - 
                         -> IO ()
elementReleaseRequestPad element pad =
    {# call element_release_request_pad #} (toElement element) (toPad pad)

-- | Remove @pad@ from @element@.
--   
--   This function is used by plugin developers and should not be used
--   by applications. Pads that were dynamically requested from
--   elements with 'elementGetRequestPad' should be released with the
--   'elementReleaseRequestPad' function instead.
--   
--   Pads are not automatically deactivated so elements should perform the needed
--   steps to deactivate the pad in case this pad is removed in the PAUSED or
--   PLAYING state. See 'padSetActive' for more information about
--   deactivating pads.
--   
--   The pad and the element should be unlocked when calling this function.
--   
--   This function will emit the 'padRemoved' signal on the element.
--   
--   Returns: 'True' if the pad could be removed. Can return 'False' if the
--   pad does not belong to the provided element.
elementRemovePad :: (ElementClass elementT, PadClass padT)
                 => elementT -- ^ @element@ - 
                 -> padT     -- ^ @pad@ - 
                 -> IO Bool  -- ^ 'True' if the pad was succcessfully
                             --   removed, otherwise 'False'
elementRemovePad element pad =
    liftM toBool $ {# call element_remove_pad #} (toElement element) (toPad pad)

-- | Retrieve an 'Iterator' over @element@'s pads.
elementIteratePads :: (ElementClass elementT)
                   => elementT          -- ^ @element@ - 
                   -> IO (Iterator Pad) -- ^ an iterator over the element's pads.
elementIteratePads element =
    {# call element_iterate_pads #} (toElement element) >>= takeIterator


-- | Retrieve an 'Iterator' over @element@'s sink pads.
elementIterateSinkPads :: (ElementClass elementT)
                       => elementT
                       -> IO (Iterator Pad)
elementIterateSinkPads element =
    {# call element_iterate_sink_pads #} (toElement element) >>= takeIterator

-- | Retrieve an 'Iterator' over @element@'s src pads.
elementIterateSrcPads :: (ElementClass elementT)
                      => elementT
                      -> IO (Iterator Pad)
elementIterateSrcPads element =
    {# call element_iterate_sink_pads #} (toElement element) >>= takeIterator

-- | Link @src@ to @sink@. The link must be from source to
--   sink; the other direction will not be tried. The function
--   looks for existing pads that aren't linked yet. It will request
--   new pads if necessary. Such pads must be released manually (with
--   'elementReleaseRequestPad') when unlinking. If multiple links are
--   possible, only one is established.
--   
--   Make sure you have added your elements to a 'Bin' or 'Pipeline'
--   with 'binAdd' before trying to link them.
elementLink :: (ElementClass srcT, ElementClass sinkT)
            => srcT    -- ^ @src@ - 
            -> sinkT   -- ^ @sink@ - 
            -> IO Bool -- ^ 'True' if the pads could be linked,
                       --   otherwise 'False'
elementLink src sink =
    liftM toBool $ {# call element_link #} (toElement src) (toElement sink)

-- | Unlink all source pads of the @src@ from all sink pads of the
--   @sink@.
elementUnlink :: (ElementClass srcT, ElementClass sinkT)
              => srcT
              -> sinkT
              -> IO ()
elementUnlink src sink =
    {# call element_unlink #} (toElement src) (toElement sink)

-- | Link the named pads of @src@ and @sink@.
elementLinkPads :: (ElementClass srcT, ElementClass sinkT)
                => srcT         -- ^ @src@ - the element containing the source pad
                -> Maybe String -- ^ @srcPadName@ - the name of the source pad, or 'Nothing' for any pad
                -> sinkT        -- ^ @sink@ - the element containing the sink pad
                -> Maybe String -- ^ @sinkPadName@ - the name of the sink pad, or 'Nothing' for any pad
                -> IO Bool      -- ^ 'True' if the pads could be linked, otherwise 'False'
elementLinkPads src srcPadName sink sinkPadName =
    maybeWith withUTFString sinkPadName $ \cSinkPadName ->
        maybeWith withUTFString srcPadName $ \cSrcPadName ->
            liftM toBool $ {# call element_link_pads #} (toElement src) cSrcPadName (toElement sink) cSinkPadName

-- | Unlink the named pads of @src@ and @sink@.
elementUnlinkPads :: (ElementClass srcT, ElementClass sinkT)
                  => srcT   -- ^ @src@ - 
                  -> String -- ^ @srcPadName@ - 
                  -> sinkT  -- ^ @sink@ - 
                  -> String -- ^ @sinkPadName@ - 
                  -> IO ()
elementUnlinkPads src srcPadName sink sinkPadName =
    withUTFString sinkPadName $ \cSinkPadName ->
        withUTFString srcPadName $ \cSrcPadName ->
            {# call element_unlink_pads #} (toElement src) cSrcPadName (toElement sink) cSinkPadName

-- | Link the named pads of @src@ and @sink@. A side effect is that if
--   one of the pads has no parent, it becomes a child of the parent
--   of the other element. If they have different parents, the link
--   will fail. If @caps@ is not 'Nothing', make sure that the 'Caps'
--   of the link is a subset of @caps@.
elementLinkPadsFiltered :: (ElementClass srcT, ElementClass sinkT)
                        => srcT         -- ^ @src@ - 
                        -> Maybe String -- ^ @srcPadName@ - 
                        -> sinkT        -- ^ @sink@ - 
                        -> Maybe String -- ^ @sinkPadName@ - 
                        -> Caps         -- ^ @caps@ - 
                        -> IO Bool      -- ^ 'True' if the pads could be
                                        --   linked, otherwise 'False'
elementLinkPadsFiltered src srcPadName sink sinkPadName filter =
    maybeWith withUTFString sinkPadName $ \cSinkPadName ->
        maybeWith withUTFString srcPadName $ \cSrcPadName ->
            liftM toBool $ {# call element_link_pads_filtered #} (toElement src) cSrcPadName (toElement sink) cSinkPadName filter

-- | Link @src@ to @dest@ using the given 'Caps' as a filter. The link
--   must be from source to sink; the other direction will not be
--   tried. The function looks for existing pads that aren't linked
--   yet. If will request new pads if necessary. If multiple links are
--   possible, only one is established.
--   
--   Make sure you have added your elements to a 'Bin' or 'Pipeline'
--   with 'binAdd' before trying to link them.
elementLinkFiltered :: (ElementClass srcT, ElementClass sinkT)
                    => srcT       -- ^ @src@ - 
                    -> sinkT      -- ^ @sink@ - 
                    -> Maybe Caps -- ^ @caps@ - 
                    -> IO Bool    -- ^ 'True' if the pads could be
                                  --   linked, otherwise 'False'
elementLinkFiltered src sink filter =
    liftM toBool $
        {# call element_link_filtered #} (toElement src) (toElement sink) $
            fromMaybe (Caps nullForeignPtr) filter

-- | Set the base time of @element@. See 'elementGetBaseTime' for more
--   information.
elementSetBaseTime :: ElementClass elementT
                   => elementT      -- ^ @element@ - 
                   -> ClockTimeDiff -- ^ @time@ - 
                   -> IO ()
elementSetBaseTime element time =
    {# call element_set_base_time #} (toElement element) $ fromIntegral time

-- | Return the base time of @element@. The base time is the absolute
--   time of the clock when this element was last set to
--   'StatePlaying'. Subtract the base time from the clock time to get
--   the stream time of the element.
elementGetBaseTime :: ElementClass elementT
                   => elementT         -- ^ @element@ - 
                   -> IO ClockTimeDiff -- ^ the base time of the element
elementGetBaseTime element =
    liftM fromIntegral $ {# call element_get_base_time #} (toElement element)

-- | Set the 'Bus' used by @element@. For internal use only, unless
--   you're testing elements.
elementSetBus :: (ElementClass elementT, BusClass busT)
              => elementT -- ^ @element@ - 
              -> busT     -- ^ @bus@ - 
              -> IO ()
elementSetBus element bus =
    {# call element_set_bus #} (toElement element) (toBus bus)

-- | Get the bus of @element@. Not that only a 'Pipeline' will
--   provide a bus for the application.
elementGetBus :: ElementClass elementT
              => elementT -- ^ @element@ - 
              -> IO Bus   -- ^ the bus used by the element
elementGetBus element =
    {# call element_get_bus #} (toElement element) >>= takeObject

-- | Get the factory used to create @element@.
elementGetFactory :: ElementClass elementT
                  => elementT          -- ^ @element@ - 
                  -> IO ElementFactory -- ^ the factory that created @element@
elementGetFactory element =
    {# call element_get_factory #} (toElement element) >>= peekObject

-- | Set the 'Index' used by @element@.
elementSetIndex :: (ElementClass elementT, IndexClass indexT)
                => elementT -- ^ @element@ - 
                -> indexT   -- ^ @index@ - 
                -> IO ()
elementSetIndex element index =
    {# call element_set_index #} (toElement element) (toIndex index)

-- | Get the 'Index' used by @element@.
elementGetIndex :: ElementClass elementT
                => elementT         -- ^ @element@ - 
                -> IO (Maybe Index) -- ^ the index, or 'Nothing' if @element@ has none
elementGetIndex element =
    {# call element_get_index #} (toElement element) >>= maybePeek takeObject

-- | Determine whether @element@ can be indexed.
elementIsIndexable :: ElementClass elementT
                   => elementT -- ^ @element@ - 
                   -> IO Bool  -- ^ 'True' if the element can be indexed
elementIsIndexable element =
    liftM toBool $ {# call element_is_indexable #} (toElement element)

-- | Determine whether @element@ requires a clock.
elementRequiresClock :: ElementClass elementT
                     => elementT -- ^ @element@ - 
                     -> IO Bool  -- ^ 'True' if the element requires a clock
elementRequiresClock element =
    liftM toBool $ {# call element_requires_clock #} (toElement element)

-- | Set the 'Clock' used by @element@.
elementSetClock :: (ElementClass elementT, ClockClass clockT)
                => elementT -- ^ @element@ - 
                -> clockT   -- ^ @clock@ - 
                -> IO Bool  -- ^ 'True' if the element accepted the clock
elementSetClock element clock =
    liftM toBool $ {# call element_set_clock #} (toElement element) (toClock clock)

-- | Get the 'Clock' used by @element@.
elementGetClock :: ElementClass elementT
                => elementT         -- ^ @element@ - 
                -> IO (Maybe Clock) -- ^ the clock, or 'Nothing' if @element@ has none
elementGetClock element =
    {# call element_get_clock #} (toElement element) >>= maybePeek takeObject

-- | Determine whether @element@ provides a clock. A 'Clock' provided
--   by an element can be used as the global clock for a pipeline. An
--   element that can provide a clock is only required to do so in the
--   'StatePaused' state, meaning that it is fully negotiated and has
--   allocated the resources needed to operate the clock.
elementProvidesClock :: ElementClass elementT
                     => elementT -- ^ @element@ - 
                     -> IO Bool  -- ^ 'True' if the element provides a clock
elementProvidesClock element =
    liftM toBool $ {# call element_provides_clock #} $ toElement element

-- | Get the 'Clock' provided by @element@.
--   
--   Note that an element is only required to provide a clock in the
--   'StatePaused' state. Some elements can provide a clock in other
--   states.
elementProvideClock :: ElementClass elementT
                    => elementT         -- ^ @element@ - 
                    -> IO (Maybe Clock) -- ^ a 'Clock', or 'Nothing' if
                                        --   none could be provided
elementProvideClock element =
    {# call element_provide_clock #} (toElement element) >>= maybePeek takeObject

-- | Set the state of @element@ to @state@. This function will try to
--   set the requested state by going through all the intermediary
--   states and calling the class's state change function for each.
--   
--   This function can return 'StateChangeAsync', in which case the
--   element will perform the remainder of the state change
--   asynchronously in another thread. An application can use
--   'elementGetState' to wait for the completion of the state change
--   or it can wait for a state change message on the bus.
elementSetState :: ElementClass elementT
                => elementT             -- ^ @element@ - 
                -> State                -- ^ @state@ - 
                -> IO StateChangeReturn -- ^ the result of the state change
elementSetState element state =
    liftM (toEnum . fromIntegral) $ {# call element_set_state #} (toElement element) $
        fromIntegral $ fromEnum state

-- | Get the state of @element@.
--   
--   For elements that performed an asynchronous state change, as
--   reported by 'elementSetState', this function will block up to the
--   specified timeout value for the state change to complete. If the
--   element completes the state change or goes into an error, this
--   function returns immediately with a return value of
--   'StateChangeSuccess' or 'StateChangeFailure', respectively.
--   
--   This function returns 'StateChangeNoPreroll' if the element
--   successfully changed its state but is not able to provide data
--   yet. This mostly happens for live sources that not only produce
--   data in the 'StatePlaying' state. While the state change return
--   is equivalent to 'StateChangeSuccess', it is returned to the
--   application to signal that some sink elements might not be able
--   to somplete their state change because an element is not
--   producing data to complete the preroll. When setting the element
--   to playing, the preroll will complete and playback will start.
elementGetState :: ElementClass elementT
                => elementT  -- ^ @element@ - 
                -> ClockTime -- ^ @timeout@ - 
                -> IO (StateChangeReturn, Maybe State, Maybe State)
                   -- ^ the result of the state change, the current
                   --   state, and the pending state
elementGetState element timeout =
    alloca $ \statePtr ->
        alloca $ \pendingPtr ->
            do poke statePtr (-1)   -- -1 is not use by any enum value
               poke pendingPtr (-1)
               result <- {# call element_get_state #} (toElement element)
                                                      statePtr
                                                      pendingPtr
                                                      (fromIntegral timeout)
               state <- unmarshalState statePtr
               pending <- unmarshalState pendingPtr
               return (toEnum $ fromIntegral result, state, pending)
    where unmarshalState statePtr = do
            cState <- peek statePtr
            if cState /= -1
               then return $ Just $ toEnum $ fromIntegral cState
               else return Nothing

-- | Lock the state of @element@, so state changes in the parent don't
--   affect this element any longer.
elementSetLockedState :: ElementClass elementT
                      => elementT -- ^ @element@ - 
                      -> Bool     -- ^ @lockedState@ - 'True' for locked, 'False' for unlocked
                      -> IO Bool  -- ^ 'True' if the state was changed, 'False' if bad
                                  --   parameters were given or no change was needed
elementSetLockedState element lockedState =
    liftM toBool $ {# call element_set_locked_state #} (toElement element) $ fromBool lockedState

-- | Determine whether @element@'s state is locked.
elementIsLockedState :: ElementClass elementT
                     => elementT -- ^ @element@ - 
                     -> IO Bool  -- ^ 'True' if @element@'s state is locked, 'False' otherwise
elementIsLockedState element =
    liftM toBool $ {# call element_is_locked_state #} $ toElement element

-- | Abort @element@'s state change. This function is used by elements
--   that do asynchronous state changes and find out something is wrong.
--   
--   This function should be called with the state lock held.
elementAbortState :: ElementClass elementT
                  => elementT -- ^ @element@ - 
                  -> IO ()
elementAbortState element =
    {# call element_abort_state #} $ toElement element

-- | Get a string representation of @state@.
elementStateGetName :: State  -- ^ @state@ - 
                    -> String -- ^ the name of @state@
elementStateGetName state =
    unsafePerformIO $ ({# call element_state_get_name #} $ fromIntegral $ fromEnum state) >>= peekUTFString

-- | Get a string representation of @stateRet@.
elementStateChangeReturnGetName :: StateChangeReturn -- ^ @stateRet@ - 
                                -> String            -- ^ the name of @stateRet@
elementStateChangeReturnGetName stateRet =
    unsafePerformIO $ ({# call element_state_change_return_get_name #} $ fromIntegral $ fromEnum stateRet) >>= peekUTFString

-- | Try to change the state of @element@ to the same as its
--   parent. If this function returns 'False', the state of the
--   element is undefined.
elementSyncStateWithParent :: ElementClass elementT
                           => elementT -- ^ @element@ - 
                           -> IO Bool  -- ^ 'True' if the element's state could be
                                       --   synced with its parent's state
elementSyncStateWithParent element =
    liftM toBool $ {# call element_sync_state_with_parent #} $ toElement element

