-- | This module contains functions for managing connections between nodes
module GEGL.Connection
  ( gegl_node_link
  , gegl_node_link_many
  , gegl_node_connect_to
  , gegl_node_connect_from
  , gegl_node_disconnect
  ) where

import Foreign.C.String (newCString)
import Foreign.Marshal.Alloc (free)
import Foreign.ForeignPtr (withForeignPtr)

import qualified GEGL.FFI.Connection as FFI
import GEGL.FFI.Node (GeglNode(..))

-- | Simple function to connect the @output@ pad of the source to the @input@ pad of the sink.
gegl_node_link
  :: GeglNode -- ^ Source node
  -> GeglNode -- ^ Sink node
  -> IO ()
gegl_node_link (GeglNode fsource) (GeglNode fsink) =
  withForeignPtr fsource (\source -> withForeignPtr fsink (\sink ->
    FFI.c_gegl_node_link source sink))

-- | Function to link together a chain of nodes
gegl_node_link_many
  :: [GeglNode] -- ^ List of nodes to connect ordered from first source to last sink.
  -> IO ()
gegl_node_link_many []    = return ()
gegl_node_link_many ([n]) = return ()
gegl_node_link_many (n:ns) = do
  gegl_node_link n (head ns)
  gegl_node_link_many ns

-- | Make connections between specific pads of nodes
gegl_node_connect_to
  :: GeglNode -- ^ Source node
  -> String   -- ^ Name <of the output pad from the source node
  -> GeglNode -- ^ Sink node
  -> String   -- ^ Name of the input pad to the sink node
  -> IO Bool
gegl_node_connect_to (GeglNode fsource) outpad (GeglNode fsink) inpad = do
  coutpad <- newCString outpad
  cinpad  <- newCString inpad
  cout <-
    withForeignPtr fsource (\source ->
      withForeignPtr fsink (\sink ->
        FFI.c_gegl_node_connect_to source coutpad sink cinpad))
  free coutpad
  free cinpad
  if cout == 0
    then return False
    else return True

-- | Make connections between specific pads of nodes.
--   Order of nodes and pads is reversed to the order in 'gegl_node_connect_to'.
gegl_node_connect_from
  :: GeglNode -- ^ Sink node
  -> String   -- ^ Nam of the input pad to the sink node
  -> GeglNode -- ^ Sink node
  -> String   -- ^ Name of the input pad to the sink node
  -> IO Bool
gegl_node_connect_from (GeglNode fsink) inpad (GeglNode fsource) outpad = do
  cinpad  <- newCString inpad
  coutpad <- newCString outpad
  cout <- withForeignPtr fsink (\sink ->
    withForeignPtr fsource (\source ->
      FFI.c_gegl_node_connect_from sink cinpad source coutpad))
  free cinpad
  free coutpad
  if cout == 0
    then return False
    else return True

-- | Disconnect a node connected to specified input pad
gegl_node_disconnect
  :: GeglNode -- Node to disconnect from
  -> String   -- Name of pad to e disconnected
  -> IO Bool  -- returns @True@ if a node was disconnected, otherwise @False@
gegl_node_disconnect (GeglNode fnode) pad = do
  cpad <- newCString pad
  cout <- withForeignPtr fnode $ flip FFI.c_gegl_node_disconnect cpad
  free cpad
  if cout == 0
    then return False
    else return True