-- GENERATED by C->Haskell Compiler, version 0.28.3 Switcheroo, 25 November 2017 (Haskell)
-- Edit the ORIGNAL .chs file instead!


{-# LINE 1 "src/IGraph/Algorithms/Structure.chs" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DataKinds #-}
module IGraph.Algorithms.Structure
    ( -- * Shortest Path Related Functions
      getShortestPath
    , inducedSubgraph
    , isConnected
    , isStronglyConnected
    , decompose
    , isDag
    , topSort
    , topSortUnsafe
    ) where
import qualified Foreign.C.Types as C2HSImp
import qualified Foreign.Ptr as C2HSImp
import qualified System.IO.Unsafe as C2HSImp



import           Control.Monad
import           Data.Serialize            (Serialize)
import Data.List (foldl')
import           System.IO.Unsafe          (unsafePerformIO)
import Data.Maybe
import Data.Singletons (SingI)

import Foreign
import Foreign.C.Types

import           IGraph
import IGraph.Internal.C2HS
import IGraph.Internal
{-# LINE 27 "src/IGraph/Algorithms/Structure.chs" #-}

import IGraph.Internal.Constants
{-# LINE 28 "src/IGraph/Algorithms/Structure.chs" #-}




igraphShortestPaths :: (IGraph) -> (Ptr Matrix) -> (Ptr VertexSelector) -> (Ptr VertexSelector) -> (Neimode) -> IO ()
igraphShortestPaths a1 a2 a3 a4 a5 =
  (withIGraph) a1 $ \a1' ->
  let {a2' = castPtr a2} in
  let {a3' = castPtr a3} in
  let {a4' = castPtr a4} in
  let {a5' = (fromIntegral . fromEnum) a5} in
  igraphShortestPaths'_ a1' a2' a3' a4' a5' >>= \res ->
  return ()

{-# LINE 38 "src/IGraph/Algorithms/Structure.chs" #-}


-- Calculates and returns a single unweighted shortest path from a given vertex
-- to another one. If there are more than one shortest paths between the two
-- vertices, then an arbitrary one is returned.
getShortestPath :: Graph d v e
                -> Node     -- ^ The id of the source vertex.
                -> Node     -- ^ The id of the target vertex.
                -> [Node]
getShortestPath gr s t = unsafePerformIO $ allocaVector $ \path -> do
    igraphGetShortestPath (_graph gr) path nullPtr s t IgraphOut
    map truncate <$> toList path
igraphGetShortestPath :: (IGraph) -> (Ptr Vector) -> (Ptr Vector) -> (Int) -> (Int) -> (Neimode) -> IO ()
igraphGetShortestPath a1 a2 a3 a4 a5 a6 =
  (withIGraph) a1 $ \a1' ->
  let {a2' = castPtr a2} in
  let {a3' = castPtr a3} in
  let {a4' = fromIntegral a4} in
  let {a5' = fromIntegral a5} in
  let {a6' = (fromIntegral . fromEnum) a6} in
  igraphGetShortestPath'_ a1' a2' a3' a4' a5' a6' >>= \res ->
  return ()

{-# LINE 57 "src/IGraph/Algorithms/Structure.chs" #-}


inducedSubgraph :: (Ord v, Serialize v)
                => Graph d v e
                -> [Int]
                -> Graph d v e
inducedSubgraph gr nds = unsafePerformIO $ withVerticesList nds $ \vs ->
    igraphInducedSubgraph (_graph gr) vs IgraphSubgraphCreateFromScratch >>=
        (\g -> return $ Graph g $ mkLabelToId g)
igraphInducedSubgraph :: (IGraph) -> (Ptr VertexSelector) -> (SubgraphImplementation) -> IO ((IGraph))
igraphInducedSubgraph a1 a3 a4 =
  (withIGraph) a1 $ \a1' ->
  allocaIGraph $ \a2' ->
  let {a3' = castPtr a3} in
  let {a4' = (fromIntegral . fromEnum) a4} in
  igraphInducedSubgraph'_ a1' a2' a3' a4' >>= \res ->
  addIGraphFinalizer  a2'>>= \a2'' ->
  return (a2'')

{-# LINE 71 "src/IGraph/Algorithms/Structure.chs" #-}


-- | Decides whether the graph is weakly connected.
isConnected :: Graph d v e -> Bool
isConnected gr = igraphIsConnected (_graph gr) IgraphWeak

isStronglyConnected :: Graph 'D v e -> Bool
isStronglyConnected gr = igraphIsConnected (_graph gr) IgraphStrong

igraphIsConnected :: (IGraph) -> (Connectedness) -> (Bool)
igraphIsConnected a1 a3 =
  C2HSImp.unsafePerformIO $
  (withIGraph) a1 $ \a1' ->
  alloca $ \a2' ->
  let {a3' = (fromIntegral . fromEnum) a3} in
  igraphIsConnected'_ a1' a2' a3' >>= \res ->
  peekBool  a2'>>= \a2'' ->
  return (a2'')

{-# LINE 84 "src/IGraph/Algorithms/Structure.chs" #-}


-- | Decompose a graph into connected components.
decompose :: (Ord v, Serialize v)
          => Graph d v e -> [Graph d v e]
decompose gr = unsafePerformIO $ allocaVectorPtr $ \ptr -> do
    igraphDecompose (_graph gr) ptr IgraphWeak (-1) 1
    n <- igraphVectorPtrSize ptr
    forM [0..n-1] $ \i -> do
        p <- igraphVectorPtrE ptr i
        addIGraphFinalizer (castPtr p) >>= (\g -> return $ Graph g $ mkLabelToId g)
{-# INLINE decompose #-}
igraphDecompose :: (IGraph) -> (Ptr VectorPtr) -> (Connectedness) -> (Int) -> (Int) -> IO ()
igraphDecompose a1 a2 a3 a4 a5 =
  (withIGraph) a1 $ \a1' ->
  let {a2' = castPtr a2} in
  let {a3' = (fromIntegral . fromEnum) a3} in
  let {a4' = fromIntegral a4} in
  let {a5' = fromIntegral a5} in
  igraphDecompose'_ a1' a2' a3' a4' a5' >>= \res ->
  return ()

{-# LINE 102 "src/IGraph/Algorithms/Structure.chs" #-}



-- | Checks whether a graph is a directed acyclic graph (DAG) or not.
isDag :: Graph d v e -> Bool
isDag = igraphIsDag . _graph
igraphIsDag :: (IGraph) -> (Bool)
igraphIsDag a1 =
  C2HSImp.unsafePerformIO $
  (withIGraph) a1 $ \a1' ->
  alloca $ \a2' ->
  igraphIsDag'_ a1' a2' >>= \res ->
  peekBool  a2'>>= \a2'' ->
  return (a2'')

{-# LINE 111 "src/IGraph/Algorithms/Structure.chs" #-}


-- | Calculate a possible topological sorting of the graph.
topSort :: Graph d v e -> [Node]
topSort gr | isDag gr = topSortUnsafe gr
           | otherwise = error "the graph is not acyclic"

-- | Calculate a possible topological sorting of the graph. If the graph is not
-- acyclic (it has at least one cycle), a partial topological sort is returned.
topSortUnsafe :: Graph d v e -> [Node]
topSortUnsafe gr = unsafePerformIO $ allocaVectorN n $ \res -> do
    igraphTopologicalSorting (_graph gr) res IgraphOut
    map truncate <$> toList res
  where
    n = nNodes gr
igraphTopologicalSorting :: (IGraph) -> (Ptr Vector) -> (Neimode) -> IO ()
igraphTopologicalSorting a1 a2 a3 =
  (withIGraph) a1 $ \a1' ->
  let {a2' = castPtr a2} in
  let {a3' = (fromIntegral . fromEnum) a3} in
  igraphTopologicalSorting'_ a1' a2' a3' >>= \res ->
  return ()

{-# LINE 130 "src/IGraph/Algorithms/Structure.chs" #-}


foreign import ccall safe "IGraph/Algorithms/Structure.chs.h __c2hs_wrapped__igraph_shortest_paths"
  igraphShortestPaths'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CInt -> (IO C2HSImp.CInt))))))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h igraph_get_shortest_path"
  igraphGetShortestPath'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CInt -> (C2HSImp.CInt -> (C2HSImp.CInt -> (IO C2HSImp.CInt)))))))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h __c2hs_wrapped__igraph_induced_subgraph"
  igraphInducedSubgraph'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CInt -> (IO C2HSImp.CInt)))))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h igraph_is_connected"
  igraphIsConnected'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr C2HSImp.CInt) -> (C2HSImp.CInt -> (IO C2HSImp.CInt))))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h igraph_decompose"
  igraphDecompose'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CInt -> (C2HSImp.CLong -> (C2HSImp.CLong -> (IO C2HSImp.CInt))))))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h igraph_is_dag"
  igraphIsDag'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr C2HSImp.CInt) -> (IO C2HSImp.CInt)))

foreign import ccall safe "IGraph/Algorithms/Structure.chs.h igraph_topological_sorting"
  igraphTopologicalSorting'_ :: ((C2HSImp.Ptr (IGraph)) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CInt -> (IO C2HSImp.CInt))))