module Data.Deciparsec.Scan where
import Control.Applicative
import Data.Monoid

import Data.Deciparsec.Internal
import Data.Deciparsec.Internal.Types
import Data.Deciparsec.TokenSeq (Token, TokenSeq)
import qualified Data.Deciparsec.TokenSeq as TS

data Scan st s = Continue st | Finished !Int s


class TokenSeq s t => ScannableTokenSeq s t | s -> t where
    scan :: Monad m => st -> (st -> t -> Maybe st) -> ParserT s u m s

instance Token t => ScannableTokenSeq [t] t where
    scan st0 p = do
      res <- (concat . reverse) <$> go [] st0
      updatePosSeq res
      return res
        where scanner !n s st = if null s then Continue st else maybe (Finished n s) (scanner (n+1) (tail s)) $ p st (head s)
              go acc st = do
                   input <- getI
                   case scanner 0 input st of
                     Finished n s -> putI s >> return (take n input:acc)
                     Continue st' -> putI [] >> wantInput >>= \more -> if more then go (input:acc) st' else return $ input:acc

{-
-- scanTS :: (Monad m, TokenSeq s t) => st -> (st -> t -> Maybe st) -> ParserT s u m s
scanTS st0 p = do
  res <- (TS.concat . reverse) <$> go p  [] st0
  updatePosSeq res
  return res
--  where
-}

scanner :: TokenSeq s t => (st -> t -> Maybe st) -> Int -> s -> st -> Scan st s
scanner p !n s st = if TS.null s then Continue st
                       else maybe (Finished n s) (scanner p (n+1) (TS.tail s)) $ p st (TS.head s)

go p acc st = do
  input <- getI
  case scanner p 0 input st of
    Finished n s -> putI s >> return (fst (TS.splitAt n input):acc)
    Continue st' -> putI empty >> wantInput >>= \more -> if more then go p (input:acc) st' else return $ input:acc
