module Graph where
import Data.List

data Op = Add
        | Sub
        | Mul
        | Div
        | Put String
        | Get String
        | App String
          deriving (Eq,Show)

data Node = Node { inputs::[String]
                 , op::Op
                 , outputs::[String]
                 }
          deriving (Eq,Show)

data Graph = Graph { inlets::[String]
                   , outlets::[String]
                   , nodes::[Node]
                   }
           deriving (Eq,Show)

graphSquare = Graph { inlets=["x"]
                    , outlets=["x2"]
                    , nodes=[Node ["x","x"] Mul ["x2"]]
                    }

graphMac = Graph { inlets=["a","b","c"]
                 , outlets=["e"]
                 , nodes=[Node ["a","b"] Mul ["d"]
                         ,Node ["c","d"] Add ["e"]
                         ]
                 }

graphHypot = Graph { inlets=["x","y"]
                   , outlets=["z"]
                   , nodes=[Node ["x"] (App "square") ["x2"]
                           ,Node ["y"] (App "square") ["y2"]
                           ,Node ["x2","y2"] Add ["z2"]
                           ,Node ["z2"] (App "sqrt") ["z"]
                           ]
                   }

graphDefs = [("square",graphSquare)
            ,("mac",graphMac)
            ,("hypot",graphHypot)
            ]

findDefn var nodes =
    find (elem var.outputs) nodes

mustComeBefore::Node->Node->Bool
mustComeBefore n1 n2 =
    intersect (outputs n1) (inputs n2) /= [] ||
    case (op n1,op n2) of
      (Get x, Put y) -> x == y
      _ -> False

mentionedStatesInGraph  graph =
    nub $ concatMap mentionedStatesInNode (nodes graph)
mentionedStatesInNode node =
    case op node of
      Put a -> [a]
      Get a -> [a]
      _ -> []

mentionedVarsInGraph graph =
    nub $ inlets graph ++ outlets graph ++
    concatMap mentionedVarsInNode (nodes graph)

mentionedVarsInNode node =
    inputs node ++ outputs node
