{-# LANGUAGE TemplateHaskell
           , OverloadedStrings
           , RecordWildCards
           , PatternGuards   #-}

module System.Posix.ARX.TMPXTools where

import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as Bytes
import Data.Char
import Data.List
import Data.Maybe
import Data.Monoid
import Numeric


import qualified Blaze.ByteString.Builder as Blaze
import Data.FileEmbed
import Data.Hashable


data Template = Template { Template -> Bool
rm0    :: Bool, {-^ Remove tmp on run success?    -}
                           Template -> Bool
rm1    :: Bool, {-^ Remove tmp on run error?      -}
                           Template -> Bool
shared :: Bool, {-^ Share directory across runs?  -}
                           Template -> ByteString
tmpdir :: ByteString,    {-^ Temp file location.  -}
                           Template -> Builder
env    :: Blaze.Builder, {-^ Stream for env text. -}
                           Template -> Builder
run    :: Blaze.Builder, {-^ Stream for run text. -}
                           Template -> Builder
dat    :: Blaze.Builder  {-^ Data text. -} }
instance Show Template where
  show :: Template -> String
show Template{Bool
Builder
ByteString
rm0 :: Template -> Bool
rm1 :: Template -> Bool
shared :: Template -> Bool
tmpdir :: Template -> ByteString
env :: Template -> Builder
run :: Template -> Builder
dat :: Template -> Builder
rm0 :: Bool
rm1 :: Bool
shared :: Bool
tmpdir :: ByteString
env :: Builder
run :: Builder
dat :: Builder
..} =
    String
"Template { tmpdir=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
Bytes.unpack ByteString
tmpdir
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" rm0=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Bool -> String
forall {a}. IsString a => Bool -> a
tf Bool
rm0 String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" rm1=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Bool -> String
forall {a}. IsString a => Bool -> a
tf Bool
rm1 String -> ShowS
forall a. [a] -> [a] -> [a]
++
              String
" shared=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Bool -> String
forall {a}. IsString a => Bool -> a
tf Bool
shared String -> ShowS
forall a. [a] -> [a] -> [a]
++  String
" ... }"
   where
    tf :: Bool -> a
tf Bool
True                  =  a
"true"
    tf Bool
False                 =  a
"false"

render                      ::  Template -> Blaze.Builder
render :: Template -> Builder
render Template{Bool
Builder
ByteString
rm0 :: Template -> Bool
rm1 :: Template -> Bool
shared :: Template -> Bool
tmpdir :: Template -> ByteString
env :: Template -> Builder
run :: Template -> Builder
dat :: Template -> Builder
rm0 :: Bool
rm1 :: Bool
shared :: Bool
tmpdir :: ByteString
env :: Builder
run :: Builder
dat :: Builder
..}          =  [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat [ ByteString -> Builder
blaze ByteString
a,
                                          Builder
flags,
                                          ByteString -> Builder
blaze ByteString
b,
                                          Builder
env,
                                          ByteString -> Builder
blaze ByteString
c,
                                          Builder
run,
                                          ByteString -> Builder
blaze ByteString
d,
                                          Builder
dat,
                                          ByteString -> Builder
blaze ByteString
e ]
 where
  flags :: Builder
flags                      =  [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat [ Builder
"rm0=", Bool -> Builder
forall {a}. IsString a => Bool -> a
tf Bool
rm0, Builder
" ; ",
                                          Builder
"rm1=", Bool -> Builder
forall {a}. IsString a => Bool -> a
tf Bool
rm1, Builder
" ; ",
                                          Builder
"shared=", Bool -> Builder
forall {a}. IsString a => Bool -> a
tf Bool
shared, Builder
" ; ",
                                          Builder
"hash=", (Int -> Builder
hexStr (Int -> Builder) -> (Builder -> Int) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Int
hash) Builder
dat, Builder
" ; ",
                                          Builder
"tmpdir=", ByteString -> Builder
blaze ByteString
tmpdir, Builder
"\n" ]
  hash :: Builder -> Int
hash                       =  Int -> Int
forall a. Num a => a -> a
abs (Int -> Int) -> (Builder -> Int) -> Builder -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Int
forall a. Hashable a => a -> Int
Data.Hashable.hash (ByteString -> Int) -> (Builder -> ByteString) -> Builder -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
Blaze.toByteString
  hexStr :: Int -> Builder
hexStr                     =  ByteString -> Builder
blaze (ByteString -> Builder) -> (Int -> ByteString) -> Int -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
Bytes.pack (String -> ByteString) -> (Int -> String) -> Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall {a}. Integral a => a -> String
hex
  hex :: a -> String
hex a
i = a -> (Int -> Char) -> a -> ShowS
forall a. Integral a => a -> (Int -> Char) -> a -> ShowS
Numeric.showIntAtBase a
16 Int -> Char
Data.Char.intToDigit a
i String
""
  blaze :: ByteString -> Builder
blaze                      =  ByteString -> Builder
Blaze.fromByteString
  tf :: Bool -> a
tf Bool
True                    =  a
"true"
  tf Bool
False                   =  a
"false"
  ByteString
a : ByteString
b : ByteString
c : ByteString
d : ByteString
e : [] = ByteString -> [ByteString]
findChunks $(embedFile "./model-scripts/tmpx.sh")

findChunks                  ::  ByteString -> [ByteString]
findChunks :: ByteString -> [ByteString]
findChunks                   =  [Maybe ByteString] -> [ByteString]
coalesce ([Maybe ByteString] -> [ByteString])
-> (ByteString -> [Maybe ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Maybe ByteString]
markHoles

coalesce                    ::  [Maybe ByteString] -> [ByteString]
coalesce :: [Maybe ByteString] -> [ByteString]
coalesce                     =  [ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse ([ByteString] -> [ByteString])
-> ([Maybe ByteString] -> [ByteString])
-> [Maybe ByteString]
-> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe ByteString] -> [ByteString]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe ByteString] -> [ByteString])
-> ([Maybe ByteString] -> [Maybe ByteString])
-> [Maybe ByteString]
-> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Maybe ByteString] -> Maybe ByteString -> [Maybe ByteString])
-> [Maybe ByteString] -> [Maybe ByteString] -> [Maybe ByteString]
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' [Maybe ByteString] -> Maybe ByteString -> [Maybe ByteString]
f []
 where
  f :: [Maybe ByteString] -> Maybe ByteString -> [Maybe ByteString]
f [           ] Maybe ByteString
item       =  [Maybe ByteString
item]
  f (Just ByteString
a  : [Maybe ByteString]
t) (Just ByteString
b)   =  ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> ByteString -> ByteString
Bytes.append ByteString
a ByteString
b) Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: [Maybe ByteString]
t
  f (Maybe ByteString
Nothing : [Maybe ByteString]
t) (Just ByteString
b)   =  ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
b Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: Maybe ByteString
forall a. Maybe a
Nothing Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: [Maybe ByteString]
t
  f (Just ByteString
a  : [Maybe ByteString]
t) (Maybe ByteString
Nothing)  =  Maybe ByteString
forall a. Maybe a
Nothing Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
a Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: [Maybe ByteString]
t
  f (Maybe ByteString
Nothing : [Maybe ByteString]
t) (Maybe ByteString
Nothing)  =  Maybe ByteString
forall a. Maybe a
Nothing Maybe ByteString -> [Maybe ByteString] -> [Maybe ByteString]
forall a. a -> [a] -> [a]
: [Maybe ByteString]
t

markHoles                   ::  ByteString -> [Maybe ByteString]
markHoles :: ByteString -> [Maybe ByteString]
markHoles                    =  (ByteString -> Maybe ByteString)
-> [ByteString] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> Maybe ByteString
f ([ByteString] -> [Maybe ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [Maybe ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
Bytes.lines
 where
  f :: ByteString -> Maybe ByteString
f ByteString
l | ByteString -> Bool
isHole ByteString
l             =  Maybe ByteString
forall a. Maybe a
Nothing
      | Bool
otherwise            =  ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString
l ByteString -> Char -> ByteString
`Bytes.snoc` Char
'\n')

isHole                      ::  ByteString -> Bool
isHole :: ByteString -> Bool
isHole ByteString
line                  =  ByteString
"# To be set by tool." ByteString -> ByteString -> Bool
`Bytes.isSuffixOf` ByteString
line