{-# LINE 2 "./Media/Streaming/GStreamer/Core/Bin.chs" #-}
-- GIMP Toolkit (GTK) Binding for Haskell: binding to gstreamer -*-haskell-*-
--
-- Author : Peter Gavin
-- Created: 1-Apr-2007
--
-- Copyright (c) 2007 Peter Gavin
--
-- This library is free software: you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public License
-- as published by the Free Software Foundation, either version 3 of
-- the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this program. If not, see
-- <http:
--
-- GStreamer, the C library which this Haskell library depends on, is
-- available under LGPL Version 2. The documentation included with
-- this library is based on the original GStreamer documentation.
--
-- | Maintainer : gtk2hs-devel@lists.sourceforge.net
-- Stability : alpha
-- Portability : portable (depends on GHC)
--
-- Base class for elements that can contain other elements.
module Media.Streaming.GStreamer.Core.Bin (

-- * Detail
  -- | 'Bin' is an element that can contain other 'Element's, allowing
  -- them to be managed as a group. 'Pad's from the child elements
  -- can be ghosted to the bin; see 'GhostPad'. This makes the bin
  -- look like any other element, and enables creation of
  -- higher-level abstractions.
  --
  -- A new 'Bin' is created with 'binNew'. Use a 'Pipeline' instead
  -- if you want to create a toplevel bin, because a normal bin
  -- doesn't have a bus or handle clock distribution of its own.
  --
  -- After the bin has been created you will typically add elements
  -- to it with 'binAdd'. You can remove elements with 'binRemove'.
  --
  -- An element can be retrieved from a bin with 'binGetByName',
  -- using the element's name. 'binGetByNameRecurseUp' is mainly
  -- used for internal purposes and will query the parent bins when
  -- the element is not found in the current bin.
  --
  -- An iterator of elements in a bin can be retrieved with
  -- 'binIterateElements'. Various other iterators exist to retrieve
  -- the elements in a bin.
  --
  -- The 'binElementAdded' signal is fired whenever a new element is
  -- added to the bin. Likewise the 'binElementRemoved' signal is
  -- fired whenever an element is removed from the bin.

-- * Types
  Bin,
  BinClass,
  castToBin,
  gTypeBin,

-- * Bin Operations
  binNew,
  binAdd,
  binRemove,
  binGetByName,
  binGetByNameRecurseUp,
  binGetByInterface,
  binIterateElements,
  binIterateRecurse,
  binIterateSinks,
  binIterateSorted,
  binIterateSources,
  binIterateAllByInterface,
  binFindUnconnectedPad,

-- * Bin Signals
  binElementAdded,
  binElementRemoved

  ) where

import Control.Exception ( bracket_ )
import Control.Monad ( liftM )
import System.Glib.FFI
import System.Glib.GType ( GType )
import System.Glib.UTFString ( withUTFString )
import System.Glib.GList ( GList
                                              , readGList )
import Media.Streaming.GStreamer.Core.Types
{-# LINE 96 "./Media/Streaming/GStreamer/Core/Bin.chs" #-}
import Media.Streaming.GStreamer.Core.Signals
{-# LINE 97 "./Media/Streaming/GStreamer/Core/Bin.chs" #-}


{-# LINE 99 "./Media/Streaming/GStreamer/Core/Bin.chs" #-}

-- | Create a new 'Bin' with the given name.
binNew :: String -- ^ @name@ - the name to give the new 'Bin'
       -> IO Bin -- ^ the new 'Bin'
binNew name =
    withUTFString name gst_bin_new >>= takeObject . castPtr

-- | Add @element@ to @bin@, and set @element@'s parent to
-- @bin@. An 'Element' can only be added to one 'Bin' at a time.
--
-- If any of @element@'s pads are linked to other 'Pad's, they will be
-- unlinked before @element@ is added to @bin@.
binAdd :: (BinClass bin, ElementClass element)
       => bin -- ^ @bin@ - a 'Bin'
       -> element -- ^ @element@ - the element to add
       -> IO Bool -- ^ 'True' if the element could be added, 'False'
                  -- if the bin does not want to accept the element
binAdd bin element =
    liftM toBool $ (\(Bin arg1) (Element arg2) -> withForeignPtr arg1 $ \argPtr1 ->withForeignPtr arg2 $ \argPtr2 ->gst_bin_add argPtr1 argPtr2) (toBin bin) (toElement element)

-- | Remove @element@ from @bin@, unparenting it as well.
--
-- If any @element@'s pads are linked to other pads, they will be
-- unlinked before @element@ is added to @bin@.
binRemove :: (BinClass bin, ElementClass element)
          => bin -- ^ @bin@ - a 'Bin'
          -> element -- ^ @element@ - the element to remove
          -> IO Bool -- ^ 'True' if @element@ could be removed, otherwise 'False'
binRemove bin element =
    liftM toBool $ (\(Bin arg1) (Element arg2) -> withForeignPtr arg1 $ \argPtr1 ->withForeignPtr arg2 $ \argPtr2 ->gst_bin_remove argPtr1 argPtr2) (toBin bin) (toElement element)

-- | Get the 'Element' with the given name @name@ from @bin@,
-- recursing down through @bin@'s children. 'Nothing' is returned if no
-- 'Element' with the given name is found.
binGetByName :: BinClass bin
             => bin -- ^ @bin@ - a 'Bin'
             -> String -- ^ @name@ - the name to search for
             -> IO (Maybe Element) -- ^ the 'Element' with the name @name@, or 'Nothing'
binGetByName bin name =
    withUTFString name ((\(Bin arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_get_by_name argPtr1 arg2) (toBin bin)) >>= maybePeek takeObject

-- | Get the 'Element' with the given name @name@ from @bin@,
-- recursing up through @bin@'s parents. Returns 'Nothing' if no
-- element with the given name is found.
binGetByNameRecurseUp :: BinClass bin
                      => bin -- ^ @bin@ - a 'Bin'
                      -> String -- ^ @element@ - the name to search for
                      -> IO (Maybe Element) -- ^ the 'Element' with the given name, or 'Nothing'
binGetByNameRecurseUp bin name =
    withUTFString name ((\(Bin arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_get_by_name_recurse_up argPtr1 arg2) $ toBin bin) >>=
        maybePeek takeObject

-- | Find an 'Element' inside @bin@ that implements the interface
-- given by @iface@. The returned 'Element' can be casted to
-- @iface@'s type. If you want all the 'Element's that implement an
-- interface, use 'binIterateAllByInterface'.
--
-- This function recurses into child bins.
binGetByInterface :: BinClass bin
                  => bin -- ^ @bin@ - a 'Bin'
                  -> GType -- ^ @iface@ - the type of the requested interface
                  -> IO (Maybe Element) -- ^ the 'Element' inside @bin@ that implements @iface@, or 'Nothing'
binGetByInterface bin iface =
    (\(Bin arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_get_by_interface argPtr1 arg2) (toBin bin) (fromIntegral iface) >>=
        maybePeek takeObject

-- | Get an 'Iterator' over the 'Element's in @bin@.
binIterateElements :: BinClass bin
                   => bin -- ^ @bin@ - a 'Bin'
                   -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' over the 'Element's in @bin@,
                                                    -- or 'Nothing'
binIterateElements bin =
    (\(Bin arg1) -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_elements argPtr1) (toBin bin) >>=
        maybePeek takeIterator

-- | Get an 'Iterator' over the 'Element's in @bin@. This
-- iterator recurses into @bin@'s children.
binIterateRecurse :: BinClass bin
                  => bin -- ^ @bin@ - a 'Bin'
                  -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' over the 'Element's in @bin@
                                                   -- and its descendents, or 'Nothing'
binIterateRecurse bin =
    (\(Bin arg1) -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_recurse argPtr1) (toBin bin) >>=
        maybePeek takeIterator

-- | Get an iterator over the 'Element's in @bin@ that have the
-- 'ElementIsSink' flag set.
binIterateSinks :: BinClass bin
                => bin -- ^ @bin@ - a 'Bin'
                -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' over the sinks in @bin@, or 'Nothing'
binIterateSinks bin =
    (\(Bin arg1) -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_sinks argPtr1) (toBin bin) >>=
        maybePeek takeIterator

-- | Gets an iterator for the elements in this bin in topologically
-- sorted order. This means that the elements are returned from the
-- most downstream elements (sinks) to the sources.
--
-- This function is used internally to perform state changes of the
-- bin elements.
binIterateSorted :: BinClass bin
                 => bin -- ^ @bin@ - a 'Bin'
                 -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' over the 'Element's in @bin@, or 'Nothing'
binIterateSorted bin =
    (\(Bin arg1) -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_sorted argPtr1) (toBin bin) >>=
        maybePeek takeIterator

-- | Gets an iterator for all elements in the bin that have no sink
-- pads and have the 'ElementIsSink' flag unset.
binIterateSources :: BinClass bin
                  => bin -- ^ @bin@ - a 'Bin'
                  -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' on elements, or 'Nothing'
binIterateSources bin =
    (\(Bin arg1) -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_sources argPtr1) (toBin bin) >>=
        maybePeek takeIterator

-- | Looks for all elements inside the bin that implement the given
-- interface. You can safely case all elements to the given
-- interface. The function recurses inside child bins.
binIterateAllByInterface :: BinClass bin
                         => bin -- ^ @bin@ - a 'Bin'
                         -> GType -- ^ @iface@ - the interface's 'GType'
                         -> IO (Maybe (Iterator Element)) -- ^ an 'Iterator' on elements, or 'Nothing'
binIterateAllByInterface bin iface =
    (\(Bin arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_iterate_all_by_interface argPtr1 arg2) (toBin bin) (fromIntegral iface) >>=
        maybePeek takeIterator


-- | Recursively looks for elements with an unconnected pad of the
-- given direction within the specified bin. Returns an unconnected
-- pad if one is found, otherwise 'Nothing'.
--
-- Since 0.10.3.
binFindUnconnectedPad :: BinClass bin
                      => bin -- ^ @bin@ - a 'Bin'
                      -> PadDirection -- ^ @direction@ - the direction of the requested 'Pad'
                      -> IO (Maybe Pad) -- ^ an unconnected 'Pad', or 'Nothing'
binFindUnconnectedPad bin direction =
    (\(Bin arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->gst_bin_find_unconnected_pad argPtr1 arg2) (toBin bin) (fromIntegral $ fromEnum direction) >>=
        maybePeek takeObject


-- | An 'Element' has been added to the 'Bin'.
binElementAdded :: BinClass bin
                => Signal bin (Element -> IO ())
binElementAdded =
    Signal $ connect_OBJECT__NONE "element-added"

-- | An 'Element' has been removed from the 'Bin'.
binElementRemoved :: BinClass bin
                  => Signal bin (Element -> IO ())
binElementRemoved =
    Signal $ connect_OBJECT__NONE "element-added"

foreign import ccall safe "gst_bin_new"
  gst_bin_new :: ((Ptr CChar) -> (IO (Ptr Element)))

foreign import ccall safe "gst_bin_add"
  gst_bin_add :: ((Ptr Bin) -> ((Ptr Element) -> (IO CInt)))

foreign import ccall safe "gst_bin_remove"
  gst_bin_remove :: ((Ptr Bin) -> ((Ptr Element) -> (IO CInt)))

foreign import ccall safe "gst_bin_get_by_name"
  gst_bin_get_by_name :: ((Ptr Bin) -> ((Ptr CChar) -> (IO (Ptr Element))))

foreign import ccall safe "gst_bin_get_by_name_recurse_up"
  gst_bin_get_by_name_recurse_up :: ((Ptr Bin) -> ((Ptr CChar) -> (IO (Ptr Element))))

foreign import ccall safe "gst_bin_get_by_interface"
  gst_bin_get_by_interface :: ((Ptr Bin) -> (CULong -> (IO (Ptr Element))))

foreign import ccall safe "gst_bin_iterate_elements"
  gst_bin_iterate_elements :: ((Ptr Bin) -> (IO (Ptr PtrIterator)))

foreign import ccall safe "gst_bin_iterate_recurse"
  gst_bin_iterate_recurse :: ((Ptr Bin) -> (IO (Ptr PtrIterator)))

foreign import ccall safe "gst_bin_iterate_sinks"
  gst_bin_iterate_sinks :: ((Ptr Bin) -> (IO (Ptr PtrIterator)))

foreign import ccall safe "gst_bin_iterate_sorted"
  gst_bin_iterate_sorted :: ((Ptr Bin) -> (IO (Ptr PtrIterator)))

foreign import ccall safe "gst_bin_iterate_sources"
  gst_bin_iterate_sources :: ((Ptr Bin) -> (IO (Ptr PtrIterator)))

foreign import ccall safe "gst_bin_iterate_all_by_interface"
  gst_bin_iterate_all_by_interface :: ((Ptr Bin) -> (CULong -> (IO (Ptr PtrIterator))))

foreign import ccall safe "gst_bin_find_unconnected_pad"
  gst_bin_find_unconnected_pad :: ((Ptr Bin) -> (CInt -> (IO (Ptr Pad))))