module Language.Explorer.Basic
    ( Explorer
    , execute
    , executeAll
    , revert
    , dynamicRevert 
    , ExplorerM.toTree
    , mkExplorerStack
    , mkExplorerTree
    , mkExplorerGraph
    , mkExplorerGSS
    , config
    , currRef
    , Ref
    , deref
    , getTrace
    , getTraces
    , getPathsFromTo
    , getPathFromTo
    , executionGraph
    ) where

import qualified Language.Explorer.Monadic as ExplorerM
import Control.Monad.Identity

import qualified Data.IntMap as IntMap
import Data.List
import Data.Functor
import Data.Foldable
import Data.Monoid ()
import Data.Graph.Inductive.Graph (emap)

-- We shadow instead of exporting directly to make the user interaction
-- the same.
type Ref = ExplorerM.Ref
type Explorer a b = ExplorerM.Explorer a Identity b ()

currRef :: Explorer a b -> Ref
currRef :: Explorer a b -> Ref
currRef = Explorer a b -> Ref
forall programs (m :: * -> *) configs output.
Explorer programs m configs output -> Ref
ExplorerM.currRef

config :: Explorer a b -> b
config :: Explorer a b -> b
config = Explorer a b -> b
forall programs (m :: * -> *) configs output.
Explorer programs m configs output -> configs
ExplorerM.config

deref :: Explorer p c -> Ref -> Maybe c
deref :: Explorer p c -> Ref -> Maybe c
deref = Explorer p c -> Ref -> Maybe c
forall p (m :: * -> *) c o. Explorer p m c o -> Ref -> Maybe c
ExplorerM.deref

-- This should be able with func composition.
wrap :: Monad m => (a -> b -> b) -> a -> b -> m (b, ())
wrap :: (a -> b -> b) -> a -> b -> m (b, ())
wrap a -> b -> b
def a
p b
e = (b, ()) -> m (b, ())
forall (m :: * -> *) a. Monad m => a -> m a
return ((b, ()) -> m (b, ())) -> (b, ()) -> m (b, ())
forall a b. (a -> b) -> a -> b
$ (a -> b -> b
def a
p b
e, ())

-- Constructor for a exploring interpreter.
mkExplorerStack:: (Show a, Eq a, Eq b) => (a -> b -> b) -> b -> Explorer a b
mkExplorerStack :: (a -> b -> b) -> b -> Explorer a b
mkExplorerStack a -> b -> b
definterp b
conf = (a -> b -> Identity (b, ())) -> b -> Explorer a b
forall a b (m :: * -> *) o.
(Show a, Eq a, Eq b, Monad m, Monoid o) =>
(a -> b -> m (b, o)) -> b -> Explorer a m b o
ExplorerM.mkExplorerStack ((a -> b -> b) -> a -> b -> Identity (b, ())
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> a -> b -> m (b, ())
wrap a -> b -> b
definterp) b
conf

mkExplorerTree:: (Show a, Eq a, Eq b) => (a -> b -> b) -> b -> Explorer a b
mkExplorerTree :: (a -> b -> b) -> b -> Explorer a b
mkExplorerTree a -> b -> b
definterp b
conf = (a -> b -> Identity (b, ())) -> b -> Explorer a b
forall a b (m :: * -> *) o.
(Show a, Eq a, Eq b, Monad m, Monoid o) =>
(a -> b -> m (b, o)) -> b -> Explorer a m b o
ExplorerM.mkExplorerTree ((a -> b -> b) -> a -> b -> Identity (b, ())
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> a -> b -> m (b, ())
wrap a -> b -> b
definterp) b
conf

mkExplorerGraph :: (Show a, Eq a, Eq b) => (a -> b -> b) -> b -> Explorer a b
mkExplorerGraph :: (a -> b -> b) -> b -> Explorer a b
mkExplorerGraph a -> b -> b
definterp b
conf = (a -> b -> Identity (b, ())) -> b -> Explorer a b
forall a b (m :: * -> *) o.
(Show a, Eq a, Eq b, Monad m, Monoid o) =>
(a -> b -> m (b, o)) -> b -> Explorer a m b o
ExplorerM.mkExplorerGraph ((a -> b -> b) -> a -> b -> Identity (b, ())
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> a -> b -> m (b, ())
wrap a -> b -> b
definterp) b
conf

mkExplorerGSS :: (Show a, Eq a, Eq b) => (a -> b -> b) -> b -> Explorer a b
mkExplorerGSS :: (a -> b -> b) -> b -> Explorer a b
mkExplorerGSS a -> b -> b
definterp b
conf = (a -> b -> Identity (b, ())) -> b -> Explorer a b
forall a b (m :: * -> *) o.
(Show a, Eq a, Eq b, Monad m, Monoid o) =>
(a -> b -> m (b, o)) -> b -> Explorer a m b o
ExplorerM.mkExplorerGSS ((a -> b -> b) -> a -> b -> Identity (b, ())
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> a -> b -> m (b, ())
wrap a -> b -> b
definterp) b
conf

execute :: (Eq c, Eq p) =>  p -> Explorer p c -> Explorer p c
execute :: p -> Explorer p c -> Explorer p c
execute p
p Explorer p c
e = (Explorer p c, ()) -> Explorer p c
forall a b. (a, b) -> a
fst ((Explorer p c, ()) -> Explorer p c)
-> (Explorer p c, ()) -> Explorer p c
forall a b. (a -> b) -> a -> b
$ Identity (Explorer p c, ()) -> (Explorer p c, ())
forall a. Identity a -> a
runIdentity (Identity (Explorer p c, ()) -> (Explorer p c, ()))
-> Identity (Explorer p c, ()) -> (Explorer p c, ())
forall a b. (a -> b) -> a -> b
$ p -> Explorer p c -> Identity (Explorer p c, ())
forall c p o (m :: * -> *).
(Eq c, Eq p, Eq o, Monad m, Monoid o) =>
p -> Explorer p m c o -> m (Explorer p m c o, o)
ExplorerM.execute p
p Explorer p c
e

executeAll :: (Eq c, Eq p) => [p] -> Explorer p c -> Explorer p c
executeAll :: [p] -> Explorer p c -> Explorer p c
executeAll [p]
p Explorer p c
e = (Explorer p c, ()) -> Explorer p c
forall a b. (a, b) -> a
fst ((Explorer p c, ()) -> Explorer p c)
-> (Explorer p c, ()) -> Explorer p c
forall a b. (a -> b) -> a -> b
$ Identity (Explorer p c, ()) -> (Explorer p c, ())
forall a. Identity a -> a
runIdentity (Identity (Explorer p c, ()) -> (Explorer p c, ()))
-> Identity (Explorer p c, ()) -> (Explorer p c, ())
forall a b. (a -> b) -> a -> b
$ [p] -> Explorer p c -> Identity (Explorer p c, ())
forall c p o (m :: * -> *).
(Eq c, Eq p, Eq o, Monad m, Monoid o) =>
[p] -> Explorer p m c o -> m (Explorer p m c o, o)
ExplorerM.executeAll [p]
p Explorer p c
e

dynamicRevert :: Bool -> Ref -> Explorer p c -> Maybe (Explorer p c)
dynamicRevert :: Bool -> Ref -> Explorer p c -> Maybe (Explorer p c)
dynamicRevert = Bool -> Ref -> Explorer p c -> Maybe (Explorer p c)
forall p (m :: * -> *) c o.
Bool -> Ref -> Explorer p m c o -> Maybe (Explorer p m c o)
ExplorerM.dynamicRevert

revert :: ExplorerM.Ref -> Explorer p c -> Maybe (Explorer p c)
revert :: Ref -> Explorer p c -> Maybe (Explorer p c)
revert = Ref -> Explorer p c -> Maybe (Explorer p c)
forall p (m :: * -> *) c o.
Ref -> Explorer p m c o -> Maybe (Explorer p m c o)
ExplorerM.revert

removeOutput :: ((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput :: ((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput ((Ref, c)
s, (p
p, o
_), (Ref, c)
t) = ((Ref, c)
s, p
p, (Ref, c)
t)

incomingEdges :: Ref -> Explorer p c -> [((Ref, c), p, (Ref, c))]
incomingEdges :: Ref -> Explorer p c -> [((Ref, c), p, (Ref, c))]
incomingEdges Ref
r Explorer p c
e = (((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput ([((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))])
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> a -> b
$ Ref -> Explorer p c -> [((Ref, c), (p, ()), (Ref, c))]
forall p (m :: * -> *) c o.
Ref -> Explorer p m c o -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.incomingEdges Ref
r Explorer p c
e

getTrace :: Explorer p c -> [((Ref, c), p, (Ref, c))]
getTrace :: Explorer p c -> [((Ref, c), p, (Ref, c))]
getTrace Explorer p c
e = (((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput ([((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))])
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> a -> b
$ Explorer p c -> [((Ref, c), (p, ()), (Ref, c))]
forall p (m :: * -> *) c o.
Explorer p m c o -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.getTrace Explorer p c
e

getTraces :: Explorer p c -> [[((Ref, c), p, (Ref, c))]]
getTraces :: Explorer p c -> [[((Ref, c), p, (Ref, c))]]
getTraces Explorer p c
e = ([((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))])
-> [[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]]
forall a b. (a -> b) -> [a] -> [b]
map ((((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput) ([[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]])
-> [[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]]
forall a b. (a -> b) -> a -> b
$ Explorer p c -> [[((Ref, c), (p, ()), (Ref, c))]]
forall p (m :: * -> *) c o.
Explorer p m c o -> [[((Ref, c), (p, o), (Ref, c))]]
ExplorerM.getTraces Explorer p c
e

getPathsFromTo :: Explorer p c -> Ref -> Ref -> [[((Ref, c), p, (Ref, c))]]
getPathsFromTo :: Explorer p c -> Ref -> Ref -> [[((Ref, c), p, (Ref, c))]]
getPathsFromTo Explorer p c
e Ref
s Ref
t = ([((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))])
-> [[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]]
forall a b. (a -> b) -> [a] -> [b]
map ((((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput) ([[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]])
-> [[((Ref, c), (p, ()), (Ref, c))]] -> [[((Ref, c), p, (Ref, c))]]
forall a b. (a -> b) -> a -> b
$ Explorer p c -> Ref -> Ref -> [[((Ref, c), (p, ()), (Ref, c))]]
forall p (m :: * -> *) c o.
Explorer p m c o -> Ref -> Ref -> [[((Ref, c), (p, o), (Ref, c))]]
ExplorerM.getPathsFromTo Explorer p c
e Ref
s Ref
t

getPathFromTo :: Explorer p c -> Ref -> Ref -> [((Ref, c), p, (Ref, c))]
getPathFromTo :: Explorer p c -> Ref -> Ref -> [((Ref, c), p, (Ref, c))]
getPathFromTo Explorer p c
e Ref
s Ref
t = (((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput ([((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))])
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> a -> b
$ Explorer p c -> Ref -> Ref -> [((Ref, c), (p, ()), (Ref, c))]
forall p (m :: * -> *) c o.
Explorer p m c o -> Ref -> Ref -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.getPathFromTo Explorer p c
e Ref
s Ref
t

executionGraph :: Explorer p c -> (Ref, [Ref], [((Ref, c), p, (Ref, c))])
executionGraph :: Explorer p c -> (Ref, [Ref], [((Ref, c), p, (Ref, c))])
executionGraph Explorer p c
e = (Ref
curr, [Ref]
nodes, (((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c)))
-> [((Ref, c), (p, ()), (Ref, c))] -> [((Ref, c), p, (Ref, c))]
forall a b. (a -> b) -> [a] -> [b]
map ((Ref, c), (p, ()), (Ref, c)) -> ((Ref, c), p, (Ref, c))
forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput [((Ref, c), (p, ()), (Ref, c))]
graph)
  where
    (Ref
curr, [Ref]
nodes, [((Ref, c), (p, ()), (Ref, c))]
graph) = Explorer p c -> (Ref, [Ref], [((Ref, c), (p, ()), (Ref, c))])
forall p (m :: * -> *) c o.
Explorer p m c o -> (Ref, [Ref], [((Ref, c), (p, o), (Ref, c))])
ExplorerM.executionGraph Explorer p c
e