{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, InstanceSigs #-}

{--# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, MultiParamTypeClasses
           , FlexibleInstances, FunctionalDependencies #-}

module TemplatesUtility (templatesSettings) where

import Control.Applicative
import Control.Monad
import Data.EitherR
import Data.List
import qualified Data.Map as DM
import System.Exit
import System.FilePath.Posix
import System.Directory
import System.IO
import System.Path.NameManip
import System.Process
import Text.Regex.PCRE

import Data.ConfigFile
import CompilationUtility
import qualified ConfigFile
import Translations
import Templates
import Printer
import Utility

data TEMPLATES_SETTINGS = TEMPLATES_SETTINGS {
  ts_executable :: FilePath,
  ts_soytojssrccompiler :: FilePath,
  ts_flags :: [String],
  ts_outputpathformat :: String, -- A format string that specifies how to build the path to each output
                                 -- file. The format string can include literal characters as well as the
                                 -- placeholders {INPUT_PREFIX}, {INPUT_DIRECTORY}, {INPUT_FILE_NAME},
                                 -- {INPUT_FILE_NAME_NO_EXT}
  ts_inputs :: [FilePath],
  ts_src_path :: FilePath,
  ts_app_path :: FilePath,
  ts_verbose :: Bool
}


instance UtilitySettings TEMPLATES_SETTINGS where
  executable = ts_executable
  toStringList a = "-jar":(ts_soytojssrccompiler a):"--outputPathFormat":(ts_outputpathformat a):
    (concat [ts_flags a,["--srcs"],[intercalate "," $ ts_inputs a]])
  utitle _ = Just "Soy template compiler"
  verbose = ts_verbose


templatesSettings :: ConfigParser -> [FilePath] -> EitherT String IO TEMPLATES_SETTINGS
templatesSettings cp inputs = TEMPLATES_SETTINGS
  <$> ConfigFile.getFile cp "DEFAULT" "utility.templates.executable"
  <*> ConfigFile.getFile cp "DEFAULT" "utility.templates.soytojssrccompiler"
  <*> (fmap words $ hoistEither $ ConfigFile.get cp "DEFAULT" "utility.templates.flags")
  <*> pure "{INPUT_DIRECTORY}/{INPUT_FILE_NAME}.TEMP"
  <*> pure inputs
  <*> (fmap dropTrailingPathSeparator $ hoistEither $ ConfigFile.get cp "DEFAULT" "src.path")
  <*> (fmap dropTrailingPathSeparator $ hoistEither $ ConfigFile.get cp "DEFAULT" "app.path")
  <*> (hoistEither $ ConfigFile.getBool cp "DEFAULT" "verbose")


instance CompilationUtility TEMPLATES_SETTINGS Translations where
  defaultValue _ = emptyTrans


  failure :: UtilityResult TEMPLATES_SETTINGS -> EitherT String IO Translations
  failure r = do
    dPut [Failure]
    closed <- catchIO $ hIsClosed $ ur_stderr r
    if closed then return () else catchIO $ hGetContents (ur_stderr r) >>= putStr
    dPut [Ln $ "Exit code: " ++ (show $ ur_exit_code r)]
    throwT "TemplatesUtility failure"


  success :: UtilityResult TEMPLATES_SETTINGS -> EitherT String IO Translations
  success r = do
    dPut [Success]
    outputs <- moveOutputs (ur_compilation_args r) (ts_inputs $ ur_compilation_args r)
    foldM filesExtractor emptyTrans $ zip (ts_inputs $ ur_compilation_args r) outputs
   where
    moveOutputs :: TEMPLATES_SETTINGS -> [FilePath] -> EitherT String IO [FilePath]
    moveOutputs ts [] = return []
    moveOutputs ts (f:fs) = do
      newName <- hoistEither $ soyToSoyJs (ts_src_path ts) (ts_app_path ts) f
      catchIO $ renameFile (f ++ ".TEMP") newName
      (:) newName <$> moveOutputs ts fs
    filesExtractor :: Translations -> (FilePath, FilePath) -> EitherT String IO Translations
    filesExtractor trans (input, output) = do
      local <- extractTrans input
      catchIO $ withFile output AppendMode $ writeTrans local
      return $ mergeTrans trans local