module Language.Prolog.NanoProlog.Interpreter where

import            Language.Prolog.NanoProlog.NanoProlog
import            Text.ParserCombinators.UU
import            System.Environment
import            System.IO

-- * Running the Interpreter
-- ** The main interpreter
-- | The `main` program prompt for a file with Prolog rules and call the main
-- interpreter loop
run :: IO ()
run =  do  args  <- getArgs
           fn    <- case args of
                      []     -> do  hSetBuffering stdin LineBuffering
                                    putStrLn "File with rules?"
                      (x:_)  -> return x
           s     <- readFile fn
           let (rules, errors) = startParse (pList pRule) s
           if null errors  then  do  mapM_ print rules
                                     loop rules
                           else  do  putStrLn "No rules parsed"
                                     mapM_ print errors

-- | `loop` ask for a goal, and enuartes all solutions found, each preceded by
-- a trace conatining the rules applied in a tree-like fashion
loop :: [Rule] -> IO ()
loop rules = do  putStrLn "goal? "
                 s <- getLine
                 unless (s == "quit") $
                   do  let (goal, errors) = startParse pFun s
                       if null errors
                         then  printSolutions (solve rules emptyEnv [("0",goal)])
                         else  do  putStrLn "Some goals were expected:"
                                   mapM_ print errors
                       loop rules

-- | `printSolutions` takes the result of a treewalk, which constructs
-- all the proofs, and pairs them with their final
-- substitutions. Alternative approaches in printing are to print the
-- raw proofs, i.e. without applying the final substitution (remove
-- the @subst env@ ). This nicely shows how the intermediate variables
-- come into life. By including the test on the length the facts
-- directly stemming from the data base are not printed. This makes
-- the proofs much shorter, but a bit less complete.
printSolutions ::  Result -> IO ()
printSolutions result = sequence_
  [  do  sequence_  [  putStrLn (prefix ++ " " ++ show (subst env pr))
                    |  (prefix, pr) <- reverse proof
         putStr "substitution: "
         putStrLn (show env)
         void getLine
  |  (proof, env) <- enumerateDepthFirst [] result ]