{-|
Module      : Pipes.KeyValueCsv.Common
Copyright   : (c) Marcin Mrotek, 2015
License     : BSD3
Maintainer  : marcin.jan.mrotek@gmail.com
Stability   : experimental

Utility functions.
-}

{-# LANGUAGE 
    DataKinds
  , GADTs
  , FlexibleContexts
  , PolyKinds
  , RankNTypes
  , ScopedTypeVariables
  , TypeOperators
  #-}

module Pipes.KeyValueCsv.Common 
  ( module Pipes.KeyValueCsv.Common
  , Lines
  , Cells
  , Producer
  , Text
  ) where

import Pipes.KeyValueCsv.Cell
import Pipes.KeyValueCsv.Internal.Types
import Pipes.KeyValueCsv.Types.Common

import Control.Lens
import Data.Reflection
import Data.Vinyl
import Data.Vinyl.Functor
import Data.Vinyl.TypeLevel
import Data.Vinyl.Utils.Proxy
import Data.Text (Text)
import Pipes hiding (Proxy)
import qualified Pipes.Group as Group
import Pipes.Parse (Parser)
import qualified Pipes.Text as PipesText

lines 
  :: Monad m 
  => Producer Text m r 
  -> Lines m r
-- ^Split a 'Text' stream into lines.
lines = 
    Lines 
  . Group.maps Line
  . view PipesText.lines

cells 
  :: ( Monad m
     , Given Delimiter
     )
  => Line m r 
  -> Cells m r
-- ^Split a line into delimited cells.
cells =
    Cells
  . Group.maps Cell
  . view (PipesText.splits delim)
  . unLine
 where delim = getDelimiter given

useDelimiter :: Char -> (Given Delimiter => a) -> a
{-^
Provide a delimiter for a computation. 
Do not use this function if there is already a 'Given' 'Delimiter' in scope.
-}
useDelimiter = give . Delimiter

wrapParser 
 :: forall m f r . Functor m
 => Parser Text m (Either String (f r)) 
 -> CellParser m f r
-- ^Wrap a parser to use it as a type constructor for 'Rec'.
wrapParser p = Compose wrapped
 where
   wrapped :: WrapParser Text m ((Either String :. f) r)
   wrapped = WrapParser composed
   composed :: Parser Text m ((Either String :. f) r)
   composed = Compose <$> p

defaultParser'
  :: ( RecAll f rs FromCell
     , Monad m
     ) 
  => Rec Proxy rs 
  -> Rec (CellParser m f) rs
defaultParser' RNil = RNil
defaultParser' (Proxy :& ps) = wrapParser fromCell :& defaultParser' ps

defaultParser
  :: forall (m :: * -> *) (f :: k -> *) (rs :: [k])
   . ( RecAll f rs FromCell
     , Monad m
     , Record rs
     )
  => Rec (CellParser m f) rs
defaultParser = defaultParser' proxyRecord