-- | This is the non-capturing form of Text.Regex.TDFA.NewDFA.String
module Text.Regex.TDFA.NewDFA.Engine_NC_FA(execMatch) where

import Control.Monad(unless)
import Prelude hiding ((!!))

import Data.Array.MArray(MArray(newArray),unsafeFreeze)
import Data.Array.ST(STArray)
import qualified Data.IntMap.CharMap2 as CMap(findWithDefault)
import qualified Data.IntMap as IMap(null)
import qualified Data.IntSet as ISet(null)
import qualified Data.Array.MArray()
import Data.STRef(newSTRef,readSTRef,writeSTRef)
import qualified Control.Monad.ST.Strict as S(ST,runST)
import Data.Sequence(Seq)
import qualified Data.ByteString.Char8 as SBS(ByteString)
import qualified Data.ByteString.Lazy.Char8 as LBS(ByteString)

import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)
import Text.Regex.TDFA.Common hiding (indent)
import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons))
import Text.Regex.TDFA.NewDFA.MakeTest(test_singleline)

--import Debug.Trace

-- trace :: String -> a -> a
-- trace _ a = a

{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> ([] Char) -> [MatchArray] #-}
{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> (Seq Char) -> [MatchArray] #-}
{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> SBS.ByteString -> [MatchArray] #-}
{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> LBS.ByteString -> [MatchArray] #-}
execMatch :: Uncons text => Regex -> Position -> Char -> text -> [MatchArray]
execMatch (Regex { regex_dfa = DFA {d_dt=dtIn} })
          offsetIn _prevIn inputIn = S.runST goNext where

  test wt off input = test_singleline wt off '\n' input

  goNext = {-# SCC "goNext" #-} do
    winQ <- newSTRef Nothing
    let next dt offset input = {-# SCC "goNext.next" #-}
          case dt of
            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->
              if test wt offset input
                then next a offset input
                else next b offset input
            Simple' {dt_win=w,dt_trans=t, dt_other=o} -> do
              unless (IMap.null w) $
                writeSTRef winQ (Just offset)
              case uncons input of
                Nothing -> finalizeWinner
                Just (c,input') -> do
                  case CMap.findWithDefault o c t of
                    Transition {trans_single=DFA {d_id=did',d_dt=dt'}}
                      | ISet.null did' -> finalizeWinner
                      | otherwise ->
                          let offset' = succ offset
                          in seq offset' $ next dt' offset' input'

        finalizeWinner = do
          mWinner <- readSTRef winQ
          case mWinner of
            Nothing -> return []
            Just winner -> mapM (makeGroup offsetIn) [winner]

    next dtIn offsetIn inputIn

----

{- CONVERT WINNERS TO MATCHARRAY -}

makeGroup :: Position -> Position -> S.ST s MatchArray
makeGroup start stop = do
  ma <- newArray (0,0) (start,stop-start)  :: S.ST s (STArray s Int (MatchOffset,MatchLength))
  unsafeFreeze ma