-- | Functions for interacting with a graph as a directed graph

module Data.IntGraph.Directed (
  Node,
  NodeSet,
  Edge,
  IntGraph,
  empty,
  addNode,
  nodes,
  removeNode,
  addEdge,
  edges,
  removeEdge,
  fromEdges) 
  where

import qualified Data.IntMap as I
import qualified Data.Set    as S

import Data.IntGraph

-- | Add an edge to the graph
-- | If either of the nodes are not already present in the graph,
-- | They are added.
addEdge :: Edge -> IntGraph -> IntGraph
addEdge (u, v) graph = IG $ I.adjust (S.insert v) u g'
  where
    (IG g') = addNode u $ addNode v graph


-- | Turns a node with its adjecencies to a list of edges
adjacencyToList :: Node -> NodeSet -> [Edge]
adjacencyToList node neighbors = map ((,) node) $ S.elems neighbors


-- | Returns a list of all edges in the graph
edges :: IntGraph -> [Edge]
edges (IG graph) = I.foldrWithKey f [] graph
  where
    f node neighbors rest = adjacencyToList node neighbors ++ rest

-- | Remove an edge from the graph
removeEdge :: Edge -> IntGraph -> IntGraph
removeEdge (u, v) (IG graph) = IG $ I.adjust (S.delete v) u graph

-- | Turns a list of edges into a graph
fromEdges :: [Edge] -> IntGraph
fromEdges graph = foldr addEdge empty graph
