module ShouldSucceed where

-- import TheUtils
import qualified Data.Set as Set
import Data.Set (Set)
import Data.List (partition )

data Digraph vertex = MkDigraph [vertex]

type Edge  vertex = (vertex, vertex)
type Cycle vertex = [vertex]

mkDigraph = MkDigraph

stronglyConnComp :: Eq vertex => [Edge vertex] -> [vertex] -> [[vertex]]
stronglyConnComp es vs
  = snd (span_tree (new_range reversed_edges)
                    ([],[])
                   ( snd (dfs (new_range es) ([],[]) vs) )
         )
 where
   reversed_edges = map swap es

   swap :: Edge v -> Edge v
   swap (x,y) = (y, x)

   new_range    []       w = []
   new_range ((x,y):xys) w
        = if x==w
          then (y : (new_range xys w))
          else (new_range xys w)

   span_tree r (vs,ns) []   = (vs,ns)
   span_tree r (vs,ns) (x:xs)
        | x `elem` vs = span_tree r (vs,ns) xs
        | otherwise = span_tree r (vs',(x:ns'):ns) xs
          where
            (vs',ns') = dfs r (x:vs,[]) (r x)

dfs r (vs,ns)   []   = (vs,ns)
dfs r (vs,ns) (x:xs) | x `elem` vs = dfs r (vs,ns) xs
                     | otherwise = dfs r (vs',(x:ns')++ns) xs
                                   where
                                     (vs',ns') = dfs r (x:vs,[]) (r x)


isCyclic :: Eq vertex => [Edge vertex] -> [vertex] -> Bool
isCyclic edges [v] = (v,v) `elem` edges
isCyclic edges vs = True


topSort :: (Eq vertex) => [Edge vertex] -> [vertex]
              -> MaybeErr [vertex] [[vertex]]


topSort edges vertices
 = case cycles of
        [] -> Succeeded [v | [v] <- singletons]
        _  -> Failed cycles
   where
   sccs = stronglyConnComp edges vertices
   (cycles, singletons) = partition (isCyclic edges) sccs


type FlattenedDependencyInfo vertex name code
   = [(vertex, Set name, Set name, code)]

mkVertices :: FlattenedDependencyInfo vertex name code -> [vertex]
mkVertices info = [ vertex | (vertex,_,_,_) <- info]

mkEdges :: (Ord name) =>
            [vertex]
         -> FlattenedDependencyInfo vertex name code
         -> [Edge vertex]

mkEdges vertices flat_info
 = [ (source_vertex, target_vertex)
   | (source_vertex, _, used_names, _) <- flat_info,
     target_name   <- Set.toList used_names,
     target_vertex <- vertices_defining target_name flat_info
   ]
 where
   vertices_defining name flat_info
    = [ vertex |  (vertex, names_defined, _, _) <- flat_info,
                name `Set.member` names_defined
      ]

lookupVertex :: (Eq vertex) =>
                 FlattenedDependencyInfo vertex name code
              -> vertex
              -> code

lookupVertex flat_info vertex
 = head code_list
 where
   code_list = [ code | (vertex',_,_,code) <- flat_info, vertex == vertex']


isRecursiveCycle :: (Eq vertex) => Cycle vertex -> [Edge vertex] -> Bool
isRecursiveCycle [vertex] edges = (vertex, vertex) `elem` edges
isRecursiveCycle cycle    edges = True



-- may go to TheUtils

data MaybeErr a b = Succeeded a | Failed b

