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

Parse CSV files with key-value headers.
-}

{-# LANGUAGE 
    DataKinds
  , ExplicitForAll
  , PolyKinds
  , TypeOperators 
  #-}

module Pipes.KeyValueCsv 
  ( breakLines
  , parseKeyValueCsv
  , module Pipes.KeyValueCsv.Csv
  , module Pipes.KeyValueCsv.KeyValue
  , module Pipes.KeyValueCsv.Types
  , Record (..)
  -- * Re-exports
  , Validation(..)
  ) where

import Prelude hiding (lines)

import Pipes.KeyValueCsv.Internal
import Pipes.KeyValueCsv.Internal.Types
import Pipes.KeyValueCsv.Common
import Pipes.KeyValueCsv.Csv
import Pipes.KeyValueCsv.KeyValue
import Pipes.KeyValueCsv.Types

import Control.Lens
import Data.Validation
import Data.Vinyl
import Data.Vinyl.Functor
import Data.Vinyl.Utils.Proxy

breakLines 
  :: Monad m
  => (Text -> Bool)
  -> Lines m r
  -> Lines m (Lines m r)
{-^ 
Break a stream of lines into two parts, on a line that satisfies the given predicate.
All input lines up to the breaking one will be fully read, and each (not including the breaking one) will be re-'yield'ed.
-}
breakLines p (Lines l) = Lines $ Lines <$> breakLines' p l

parseKeyValueCsv 
  :: forall (m :: * -> *) (f :: k -> *) (g :: j -> *) (hs :: [k]) (rs :: [j]) (r :: *)
   . ( Monad m
     , Record hs
     )
  => Options m f g hs rs
  -> Producer Text m r
  -> m 
     ( Rec (WithKeyValueError :. f) hs
     , Producer (Rec (WithCsvError :. g) rs) m r
    )
-- ^Read a CSV file preceded by key-value pairs.
parseKeyValueCsv options producer = useDelimiter (options^.delimiter) $ do
 (hdr, remaining)
   <- parseKeyValues (options^.kvOptions) 
    . breakLines (options^.predicate) 
    $ lines producer
 pure (hdr, parseCsv (options^.csvOptions) remaining)