module Data.Aviation.Ersa.Concat(
  ErsaCurrentPending(..)
, currentPendingPath
, ErsaDocument(..)
, hrefs
, ersacontentsRequest
, ersacontentsResponse
, ersahrefs
, ersadocumentsResponse
, (>.>)
, traverseExitCodes
, ErsaConcatDirectories(..)
, defaultErsaConcatDirectories
, baseuri
, getersadocuments
, concatersadocuments
, ersaconcat
, defaultersaconcat
) where

import Data.Maybe
import Network.HTTP
import Network.URI
import Text.HTML.TagSoup
import System.Directory
import System.Exit
import System.FilePath
import System.IO
import System.Process
import Prelude

data ErsaCurrentPending =
  ErsaCurrent
  | ErsaPending
  deriving (Eq, Ord, Show)

currentPendingPath ::
  ErsaCurrentPending
  -> String
currentPendingPath ErsaCurrent =
  "current"
currentPendingPath ErsaPending =
  "pending"

data ErsaDocument =
  ErsaDocument {
    _pg ::
      String
  , _date ::
      String
  , _ver ::
      String
  , _ps ::
      ErsaCurrentPending
  }
  deriving (Eq, Ord, Show)

hrefs ::
  ErsaDocument
  -> Tag [Char]
  -> Maybe [Char]
hrefs (ErsaDocument _ _ _ j) (TagOpen "a" attrs) =
  case attrs of
    [("href", e)] -> 
      let (s, t) = splitAt 18 e
      in  if s == "/aip/" ++ currentPendingPath j ++ "/ersa/"
            then
              Just t
            else
              Nothing
    _ ->
      Nothing
hrefs _ _ =
  Nothing

ersacontentsRequest ::
  ErsaDocument
  -> Request String
ersacontentsRequest (ErsaDocument p d v _) =
  Request
    (URI "http:" (Just (URIAuth "" "www.airservicesaustralia.com" "")) "/aip/aip.asp" ("?pg=" ++ p ++ "&vdate=" ++ d ++ "&ver=" ++ v) "")
    GET
    []
    ""

ersacontentsResponse ::
  ErsaDocument
  -> IO String
ersacontentsResponse d =
  do  s <- simpleHTTP (ersacontentsRequest d)
      getResponseBody s

ersahrefs ::
  ErsaDocument
  -> String
  -> [String]
ersahrefs d r =
  parseTags r >>=
    maybeToList . hrefs d

ersadocumentsResponse ::
  ErsaDocument
  -> IO [String]
ersadocumentsResponse d =
  ersahrefs d <$> ersacontentsResponse d

(>.>) ::
  Monad m =>
  m ExitCode
  -> m ExitCode
  -> m ExitCode
a >.> b =
  do  e <- a
      if e == ExitSuccess
        then
          b
        else
          return e

traverseExitCodes ::
  (Monad m, Foldable t) =>
  (a -> m ExitCode)
  -> t a
  -> m ExitCode
traverseExitCodes f =
  foldr (\a b -> f a >.> b) (return ExitSuccess)

data ErsaConcatDirectories =
  ErsaConcatDirectories {
    _base ::
      ErsaDocument
      -> FilePath
  , _wgetDirectory ::
      FilePath
  , _outDirectory ::
      FilePath
  , _logDirectory ::
      FilePath
  }

defaultErsaConcatDirectories ::
  ErsaDocument
  -> ErsaConcatDirectories
defaultErsaConcatDirectories c =
  let base (ErsaDocument p d v j) =
        concat ["ersa_", currentPendingPath j, "_pg-", p, "_vdate-", d, "_ver-", v]
  in  ErsaConcatDirectories
        base
        ("dist" </> base c </> "wget")
        ("dist" </> base c </> "out")
        ("dist" </> base c </> "log")
  
baseuri ::
  String
baseuri =
  "https://www.airservicesaustralia.com/aip/pending/ersa/"

getersadocuments ::
  ErsaConcatDirectories
  -> ErsaDocument
  -> [String]
  -> IO ExitCode
getersadocuments (ErsaConcatDirectories f w _ l) d u =
  do  createDirectoryIfMissing True w
      createDirectoryIfMissing True l
      traverseExitCodes
        (\a ->  rawSystem'
                  (l </> concat [f d, ".get.err"])
                  (l </> concat [f d, ".get.out"])
                  "wget"
                  [
                    "--no-check-certificate"
                  , "-c"
                  , "--show-progress"
                  , "--directory-prefix"
                  , w
                  , baseuri ++ a
                  ])
        u

-- requires pdftk on PATH
-- requires pdftotext on PATH
concatersadocuments ::
  ErsaConcatDirectories
  -> ErsaDocument
  -> [String]
  -> IO ExitCode
concatersadocuments (ErsaConcatDirectories f w o l) d u =
  let pdfout = o </> concat [f d, ".pdf"]
  in  do  createDirectoryIfMissing True o
          createDirectoryIfMissing True l
          rawSystem'
            (l </> concat [f d, ".concat.err"])
            (l </> concat [f d, ".concat.out"])
            "pdftk"
            (map (w </>) u ++ ["output", pdfout, "verbose"]) >.>
            rawSystem'
              (l </> concat [f d, ".pdftotxt.err"])
              (l </> concat [f d, ".pdftotxt.out"])
              "pdftotext"
              [pdfout]

ersaconcat ::
  ErsaConcatDirectories
  -> ErsaDocument
  -> IO ExitCode
ersaconcat a d =
  do  r <- ersadocumentsResponse d
      getersadocuments a d r >.>
        concatersadocuments a d r

defaultersaconcat ::
  ErsaDocument
  -> IO ExitCode
defaultersaconcat d =
  ersaconcat (defaultErsaConcatDirectories d) d

rawSystem' ::
  FilePath
  -> FilePath
  -> FilePath
  -> [String]
  -> IO ExitCode
rawSystem' e o cmd args =
  withFile e AppendMode $
    \herr  ->
      withFile o AppendMode $
        \hout ->
          do
            (_, _, _, ph) <-  createProcess_ "ersaconcat" (proc cmd args) {
                                std_out = UseHandle hout
                              , std_err = UseHandle herr
                              }
            waitForProcess ph