{-# LANGUAGE FlexibleContexts #-}
module Text.Trifecta.Supply 
  ( Supply(..)
  , EOF(EOF)
  , supplyEOF
  -- * type restricted versions of supply
  , supplyDefault
  , supplyStrand
  , supplyHunk
  , supplyPath
  , supplyByteString
  ) where

import Control.Parallel.Strategies hiding (Done)
import Data.Monoid
import Data.Semigroup.Reducer
import Data.Foldable
import Data.Word
import Data.Semigroup.Foldable
import Data.List.NonEmpty
import Data.FingerTree as FingerTree
import qualified Data.ByteString as Strict
import qualified Data.ByteString.Lazy as Lazy
import Data.ByteString.UTF8 as UTF8
import Text.Trifecta.Path
import Text.Trifecta.Rope
import Text.Trifecta.Hunk
import Text.Trifecta.Strand
import Text.Trifecta.It

-- enumerators for our iteratee

class Supply t where
  supply :: t -> It a -> It a 
  supplyList :: [t] -> It a -> It a 
  supplyList = Prelude.foldr (\t b -> b . supply t) id

data EOF = EOF

instance Supply EOF where
  supply _ = supplyEOF

supplyEOF :: It a -> It a
supplyEOF (Cont k)     = k mempty True
supplyEOF (Done r _ a) = Done r True a
supplyEOF (Fail r _ a) = Fail r True a

supplyDefault :: Reducer t Rope => t -> It a -> It a
supplyDefault new (Done old _ a) = Done (snoc old new) False a
supplyDefault new (Fail old _ a) = Fail (snoc old new) False a
supplyDefault new (Cont k)       = k (unit new) False

supplyStrand :: Strand -> It a -> It a 
supplyStrand = supplyDefault

supplyHunk :: Hunk -> It a -> It a
supplyHunk = supplyDefault

supplyPath :: Path -> It a -> It a
supplyPath = supplyDefault

supplyByteString :: ByteString -> It a -> It a 
supplyByteString = supplyDefault

-- DO NOT WANT
instance Supply Word8 where
  supply = supplyByteString . Strict.singleton
  supplyList = supplyByteString . Strict.pack

instance Supply Char where
  supply c = supplyByteString (UTF8.fromString [c])
  supplyList = supplyByteString . UTF8.fromString

instance Supply a => Supply [a] where
  supply = supplyList

instance Supply Strict.ByteString where
  supply = supplyByteString
  supplyList = supplyList . Prelude.map (HunkStrand . hunk)

instance Supply Lazy.ByteString where
  supply = supplyList . Lazy.toChunks 

instance Supply Hunk where
  supply = supplyHunk
  supplyList = supplyList . Prelude.map HunkStrand

instance Supply Path where
  supply = supplyPath
  supplyList [] = id
  supplyList (x:xs) = supplyPath $ fold1 (x :| xs)

instance Supply Strand where
  supply = supplyStrand
  supplyList xs = supply (rope (FingerTree.fromList xs')) where
     !xs' = withStrategy (evalList rseq) xs

instance Supply Rope where
  supply = supplyDefault
  supplyList = supplyDefault . fold