{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
module Dhall.Format
    ( 
      Format(..)
    , format
    ) where
import Data.Foldable (for_)
import Dhall.Pretty  (CharacterSet (..), annToAnsiStyle)
import Dhall.Util
    ( Censor
    , CheckFailed (..)
    , Header (..)
    , OutputMode (..)
    , PossiblyTransitiveInput (..)
    , Transitivity (..)
    )
import qualified Control.Exception
import qualified Data.Text.IO
import qualified Data.Text.Prettyprint.Doc                 as Pretty
import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty.Terminal
import qualified Data.Text.Prettyprint.Doc.Render.Text     as Pretty.Text
import qualified Dhall.Import
import qualified Dhall.Pretty
import qualified Dhall.Util
import qualified System.AtomicWrite.Writer.LazyText        as AtomicWrite.LazyText
import qualified System.Console.ANSI
import qualified System.FilePath
import qualified System.IO
data Format = Format
    { characterSet :: CharacterSet
    , censor       :: Censor
    , input        :: PossiblyTransitiveInput
    , outputMode   :: OutputMode
    }
format :: Format -> IO ()
format (Format { input = input0, ..}) = go input0
  where
    go input = do
        let directory = case input of
                NonTransitiveStandardInput ->
                    "."
                PossiblyTransitiveInputFile file _ ->
                    System.FilePath.takeDirectory file
        let status = Dhall.Import.emptyStatus directory
        let layoutHeaderAndExpr (Header header, expr) =
                Dhall.Pretty.layout
                    (   Pretty.pretty header
                    <>  Dhall.Pretty.prettyCharacterSet characterSet expr
                    <>  "\n")
        (originalText, transitivity) <- case input of
            PossiblyTransitiveInputFile file transitivity -> do
                text <- Data.Text.IO.readFile file
                return (text, transitivity)
            NonTransitiveStandardInput -> do
                text <- Data.Text.IO.getContents
                return (text, NonTransitive)
        headerAndExpr@(_, parsedExpression) <- Dhall.Util.getExpressionAndHeaderFromStdinText censor originalText
        case transitivity of
            Transitive ->
                for_ parsedExpression $ \import_ -> do
                    maybeFilepath <- Dhall.Import.dependencyToFile status import_
                    for_ maybeFilepath $ \filepath ->
                        go (PossiblyTransitiveInputFile filepath Transitive)
            NonTransitive ->
                return ()
        let docStream = layoutHeaderAndExpr headerAndExpr
        let formattedText = Pretty.Text.renderStrict docStream
        case outputMode of
            Write ->
                case input of
                    PossiblyTransitiveInputFile file _ ->
                        if originalText == formattedText
                            then return ()
                            else AtomicWrite.LazyText.atomicWriteFile
                                    file
                                    (Pretty.Text.renderLazy docStream)
                    NonTransitiveStandardInput -> do
                        supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout
                        Pretty.Terminal.renderIO
                            System.IO.stdout
                            (if supportsANSI
                                then (fmap annToAnsiStyle docStream)
                                else (Pretty.unAnnotateS docStream))
            Check ->
                if originalText == formattedText
                    then return ()
                    else do
                        let command = "format"
                        let modified = "formatted"
                        Control.Exception.throwIO CheckFailed{..}