- | Builds a size-change graph for a call
sizeChangeGraph :: Call DataEnv (Substitution Size) -> SizeChangeGraph DataEnv (Sym, Size)
sizeChangeGraph (f, subs, g) = (f, mapMaybe toSCArc subs, g)
  where
    toSCArc :: (Sym, DataPosition Size) -> Maybe (SCArc (Sym, Size))
    toSCArc (y, arg) = do
      let fData = controlPointData f
      let argSize = getData arg
      let roots = filter (\(x,_) -> x `elem` parameterRoots argSize) fData
      let comparisons =
            map (\(x, DataPos xSize) -> (x, DataPos xSize, compare argSize xSize)) $ roots
            --if null roots then fData else roots
      (x, DataPos initSize, ord) <- minOrder comparisons Nothing
      case ord of
        LT -> Just (DataPos (x, initSize), Descending, DataPos (y, argSize))
        EQ -> Just (DataPos (x, initSize), NonIncreasing, DataPos (y, argSize))
        GT -> Nothing
                 
    parameterRoots :: Size -> [Sym]
    parameterRoots (Param x)     = [x]
    parameterRoots (D s)         = parameterRoots s
    parameterRoots (C s)         = parameterRoots s
    parameterRoots (NotMin s)    = parameterRoots s
    parameterRoots (Multiple ss) = concat $ map parameterRoots ss
    parameterRoots _             = []

    minOrder :: Ord c => [(a, b, c)] -> Maybe (a, b, c) -> Maybe (a, b, c)
    minOrder []                     acc                     = acc
    minOrder (el@(_, _, ord) : xs)  Nothing                 = minOrder xs (Just el)
    minOrder (new@(_, _, ord) : xs) old@(Just (_, _, ord')) = if ord < ord' 
                                                              then minOrder xs (Just new)
                                                              else minOrder xs old

sizeChangeGraph :: Call DataEnv (Substitution Size) -> SizeChangeGraph DataEnv (Sym, Size)
sizeChangeGraph (f, subs, g) = (f, mapMaybe toSCArc subs, g)
  where
    toSCArc :: (Sym, DataPosition Size) -> Maybe (SCArc (Sym, Size))
    toSCArc (y, arg) = do
      let fData = controlPointData f
      let argSize = getData arg
      let roots = filter (\(x,_) -> x `elem` parameterRoots argSize) fData
      let comparisons =
            map (\(x, DataPos xSize) -> (x, DataPos xSize, compare argSize xSize)) $ roots
            --if null roots then fData else roots
      (x, DataPos initSize, ord) <- minOrder comparisons Nothing
      case ord of
        LT -> Just (DataPos (x, initSize), Descending, DataPos (y, argSize))
        EQ -> Just (DataPos (x, initSize), NonIncreasing, DataPos (y, argSize))
        GT -> Nothing
                 
    parameterRoots :: Size -> [Sym]
    parameterRoots (Param x)     = [x]
    parameterRoots (D s)         = parameterRoots s
    parameterRoots (C s)         = parameterRoots s
    parameterRoots (NotMin s)    = parameterRoots s
    parameterRoots (Multiple ss) = concat $ map parameterRoots ss
    parameterRoots _             = []

    minOrder :: Ord c => [(a, b, c)] -> Maybe (a, b, c) -> Maybe (a, b, c)
    minOrder []                     acc                     = acc
    minOrder (el@(_, _, ord) : xs)  Nothing                 = minOrder xs (Just el)
    minOrder (new@(_, _, ord) : xs) old@(Just (_, _, ord')) = if ord < ord' 
                                                              then minOrder xs (Just new)
                                                              else minOrder xs old
sizeChangeGraph (f, subs, g) = (f, mapMaybe toSCArc subs, g)
  where
    toSCArc :: (Sym, DataPosition Size) -> Maybe (SCArc (Sym, Size))
    toSCArc (y, arg) = do
      let fData = controlPointData f
      let argSize = getData arg
      let roots = filter (\(x,_) -> x `elem` parameterRoots argSize) fData
      let comparisons =
            map (\(x, DataPos xSize) -> (x, DataPos xSize, compare argSize xSize)) $ roots
            --if null roots then fData else roots
      (x, DataPos initSize, ord) <- minOrder comparisons Nothing
      case ord of
        LT -> Just (DataPos (x, initSize), Descending, DataPos (y, argSize))
        EQ -> Just (DataPos (x, initSize), NonIncreasing, DataPos (y, argSize))
        GT -> Nothing
                 
    parameterRoots :: Size -> [Sym]
    parameterRoots (Param x)     = [x]
    parameterRoots (D s)         = parameterRoots s
    parameterRoots (C s)         = parameterRoots s
    parameterRoots (NotMin s)    = parameterRoots s
    parameterRoots (Multiple ss) = concat $ map parameterRoots ss
    parameterRoots _             = []

    minOrder :: Ord c => [(a, b, c)] -> Maybe (a, b, c) -> Maybe (a, b, c)
    minOrder []                     acc                     = acc
    minOrder (el@(_, _, ord) : xs)  Nothing                 = minOrder xs (Just el)
    minOrder (new@(_, _, ord) : xs) old@(Just (_, _, ord')) = if ord < ord' 
                                                              then minOrder xs (Just new)
                                                              else minOrder xs old