{-
Simple command line tool to experiment with simple-sql-parser

Commands:

parse: parse sql from file, stdin or from command line
lex: lex sql same
indent: parse then pretty print sql

TODO: this is supposed to be a simple example, but it's a total mess
write some simple helpers so it's all in text?

-}

{-# LANGUAGE TupleSections #-}
import System.Environment (getArgs)
import Control.Monad (forM_, when)
import Data.Maybe (isJust)
import System.Exit (exitFailure)
import Data.List (intercalate)
import Text.Show.Pretty (ppShow)
--import Control.Applicative

import qualified Data.Text as T

import Language.SQL.SimpleSQL.Pretty
    (prettyStatements)
import Language.SQL.SimpleSQL.Parse
    (parseStatements
    ,prettyError)
import qualified Language.SQL.SimpleSQL.Lex as L
import Language.SQL.SimpleSQL.Dialect (ansi2011)


main :: IO ()
main = do
    args <- getArgs
    case args of
        [] -> do
              showHelp $ Just "no command given"
        (c:as) -> do
             let cmd = lookup c commands
             maybe (showHelp (Just "command not recognised"))
                   (\(_,cmd') -> cmd' as)
                   cmd

commands :: [(String, (String,[String] -> IO ()))]
commands =
    [("help", helpCommand)
    ,("parse", parseCommand)
    ,("lex", lexCommand)
    ,("indent", indentCommand)]

showHelp :: Maybe String -> IO ()
showHelp msg = do
          maybe (return ()) (\e -> putStrLn $ "Error: " ++ e) msg
          putStrLn "Usage:\n SimpleSqlParserTool command args"
          forM_ commands $ \(c, (h,_)) -> do
               putStrLn $ c ++ "\t" ++ h
          when (isJust msg) $ exitFailure

helpCommand :: (String,[String] -> IO ())
helpCommand =
    ("show help for this progam", \_ -> showHelp Nothing)

getInput :: [String] -> IO (FilePath,String)
getInput as =
    case as of
      ["-"] -> ("",) <$> getContents
      ("-c":as') -> return ("", unwords as')
      [filename] -> (filename,) <$> readFile filename
      _ -> showHelp (Just "arguments not recognised") >> error ""

parseCommand :: (String,[String] -> IO ())
parseCommand =
  ("parse SQL from file/stdin/command line (use -c to parse from command line)"
  ,\args -> do
      (f,src) <- getInput args
      either (error . T.unpack . prettyError)
          (putStrLn . ppShow)
          $ parseStatements ansi2011 (T.pack f) Nothing (T.pack src)
  )

lexCommand :: (String,[String] -> IO ())
lexCommand =
  ("lex SQL from file/stdin/command line (use -c to parse from command line)"
  ,\args -> do
      (f,src) <- getInput args
      either (error . T.unpack . L.prettyError)
             (putStrLn . intercalate ",\n" . map show)
             $ L.lexSQL ansi2011 (T.pack f) Nothing (T.pack src)
  )


indentCommand :: (String,[String] -> IO ())
indentCommand =
  ("parse then pretty print SQL from file/stdin/command line (use -c to parse from command line)"
  ,\args -> do
      (f,src) <- getInput args
      either (error . T.unpack . prettyError)
          (putStrLn . T.unpack . prettyStatements ansi2011)
          $ parseStatements ansi2011 (T.pack f) Nothing (T.pack src)

  )