-- Brainfuck compiler

import Parse
import System.Environment (getArgs)
import qualified System.Directory
import System.Console.Docopt (optionsWithUsageFile, getArg, isPresent, command, argument, shortOption)
import Control.Monad (when, unless)
import System.IO (hGetContents, stdin)
import FileUtilities (splitAtExt)
import System.Exit (exitSuccess, exitFailure)
import Link
import Assemble

bfcLibraryPath = "./Linux64Lib.o"
version = "0.1.0"

defaultOverhead = [ "[section .text]"
                  , "extern puts"
                  , "extern gets"
                  , "extern exit"
                  , "extern init"
                  , "global main"
                  , "main:"
                  , "call init"
                  ]

oops :: String -> IO ()
oops string = putStrLn $ "[OOPS]: " ++ string

parseAssembleAndLink :: String -> String -> IO ()
parseAssembleAndLink code output = do
    putStrLn "Compiling..."
    writeFile asmfile nasmcode
    putStrLn "Assembling..."
    assemble asmfile objectfile
    putStrLn "Linking..."
    link [objectfile, bfcLibraryPath] output
    putStrLn "Done!"
    where asmfile = output ++ ".asm"
          objectfile = output ++ ".o"
          nasmcode = (unlines.(generateNASM defaultOverhead).parse) code

main :: IO ()
main = do
    args <- optionsWithUsageFile "USAGE.txt"
    print args
    when (args `isPresent` (argument "<file>")) $ do
        path <- args `getArg` (argument "<file>")
        exists <- System.Directory.doesFileExist path
        unless (exists) $ do
            oops $ "The file " ++ show path ++ " does not exist in the current directory"
            exitFailure
        outputfile <- if args `isPresent` (shortOption 'o')
                           then args `getArg` (shortOption 'o')
                           else return $ (fst.splitAtExt) path
        contents <- readFile path
        parseAssembleAndLink contents outputfile
        exitSuccess
    contents <- hGetContents stdin
    (putStr.unlines.(generateNASM defaultOverhead).parse) contents
    exitSuccess
