module Text.ShellEscape.EscapeVector where

import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as ByteString

import Data.Vector (Vector)
import qualified Data.Vector as Vector
import qualified Data.Vector.Mutable as Vector

import qualified Text.ShellEscape.Put as Put


type EscapeVector escapingMode = Vector (Char, escapingMode)

escWith :: (Char -> escapingMode) -> ByteString -> EscapeVector escapingMode
escWith cf b                 =  Vector.create $ do
  v                         <-  Vector.new (ByteString.length b)
  sequence_ . snd $ ByteString.foldl' (f v) (0, []) b
  return v
 where
  f v (i, ops) c             =  (i + 1, Vector.write v i (c, cf c) : ops)


stripEsc                    ::  Vector (Char, escapingMode) -> ByteString
stripEsc v                   =  ByteString.unfoldr f . fst $ Vector.unzip v
 where
  f v | Vector.null v        =  Nothing
      | otherwise            =  Just (Vector.unsafeHead v, Vector.unsafeTail v)

interpretEsc v f finish init =  (eval . (finish lastMode :)) instructions
 where
  eval                       =  Put.runPut' . sequence_ . reverse
  (instructions, lastMode)   =  Vector.foldl' f' init v
   where
    f' (list, mode) (c, e)   =  (put:list, mode')
     where
      (put, mode')           =  f mode (c, e)