{-# OPTIONS_GHC -fno-warn-unused-imports #-}

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}

module DSV.FileFoldCsv
  ( foldCsvFileWithoutHeader, foldCsvFileWithoutHeaderM
  , foldCsvFileIgnoringHeader, foldCsvFileIgnoringHeaderM
  , foldCsvFileWithZippedHeader, foldCsvFileWithZippedHeaderM
  ) where

import DSV.ByteString
import DSV.CommonDelimiters
import DSV.FileFold
import DSV.Fold
import DSV.IO
import DSV.NumberViews
import DSV.ParseStop
import DSV.Prelude
import DSV.Vector
import DSV.VectorViews
import DSV.ViewType

-- base
import Data.Foldable (traverse_)
import Data.Maybe (fromMaybe)

-- bytestring
import qualified Data.ByteString.Char8 as BS

-- foldl
import qualified Control.Foldl as L

{- |

=== Example

CSV file:

> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.premap' ('viewOr' 0 $ 'byteStringDollarsView' '<<<-' 'columnNumberView' 3) 'L.sum'
@

Result:

@
('ParseComplete', 624.84)
@

-}

foldCsvFileWithoutHeader ::
    forall m result .
    MonadIO m
    => FilePath
        -- ^ The path of a CSV file to read
    -> Fold (Vector ByteString) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileWithoutHeader :: FilePath
-> Fold (Vector ByteString) result -> m (ParseStop, result)
foldCsvFileWithoutHeader FilePath
fp Fold (Vector ByteString) result
fld =
    Delimiter
-> FilePath
-> Fold (Vector ByteString) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
MonadIO m =>
Delimiter
-> FilePath
-> Fold (Vector ByteString) result
-> m (ParseStop, result)
foldDsvFileWithoutHeader Delimiter
comma FilePath
fp Fold (Vector ByteString) result
fld

{- |

=== Example

CSV file:

> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.mapM_' ('traverse_' 'BS.putStrLn' . 'nthVectorElement' 4) *> 'L.generalize' 'L.length'
@

Output printed to the terminal:

> Dehydrated boulders
> Earthquake pills

Result:

@
('ParseComplete', 2)
@

-}

foldCsvFileWithoutHeaderM ::
    forall m result .
    (MonadCatch m, MonadMask m, MonadIO m)
    => FilePath
        -- ^ The path of a CSV file to read
    -> FoldM m (Vector ByteString) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileWithoutHeaderM :: FilePath
-> FoldM m (Vector ByteString) result -> m (ParseStop, result)
foldCsvFileWithoutHeaderM FilePath
fp FoldM m (Vector ByteString) result
fld =
    Delimiter
-> FilePath
-> FoldM m (Vector ByteString) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
(MonadCatch m, MonadMask m, MonadIO m) =>
Delimiter
-> FilePath
-> FoldM m (Vector ByteString) result
-> m (ParseStop, result)
foldDsvFileWithoutHeaderM Delimiter
comma FilePath
fp FoldM m (Vector ByteString) result
fld

{- |

=== Example

CSV file:

> Date,Vendor,Price,Product
> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.premap' ('viewOr' 0 $ 'byteStringDollarsView' '<<<-' 'columnNumberView' 3) 'L.sum'
@

Result:

@
('ParseComplete', 624.84)
@

-}

foldCsvFileIgnoringHeader ::
    forall m result .
    MonadIO m
    => FilePath
        -- ^ The path of a CSV file to read
    -> Fold (Vector ByteString) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileIgnoringHeader :: FilePath
-> Fold (Vector ByteString) result -> m (ParseStop, result)
foldCsvFileIgnoringHeader FilePath
fp Fold (Vector ByteString) result
fld =
    Delimiter
-> FilePath
-> Fold (Vector ByteString) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
MonadIO m =>
Delimiter
-> FilePath
-> Fold (Vector ByteString) result
-> m (ParseStop, result)
foldDsvFileIgnoringHeader Delimiter
comma FilePath
fp Fold (Vector ByteString) result
fld

{- |

=== Example

CSV file:

> Date,Vendor,Price,Product
> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.mapM_' ('traverse_' 'BS.putStrLn' . 'nthVectorElement' 4) *> 'L.generalize' 'L.length'
@

Output printed to the terminal:

> Dehydrated boulders
> Earthquake pills

Result:

@
('ParseComplete', 2)
@

-}

foldCsvFileIgnoringHeaderM ::
    forall m result .
    (MonadCatch m, MonadMask m, MonadIO m)
    => FilePath
        -- ^ The path of a CSV file to read
    -> FoldM m (Vector ByteString) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileIgnoringHeaderM :: FilePath
-> FoldM m (Vector ByteString) result -> m (ParseStop, result)
foldCsvFileIgnoringHeaderM FilePath
fp FoldM m (Vector ByteString) result
fld =
    Delimiter
-> FilePath
-> FoldM m (Vector ByteString) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
(MonadCatch m, MonadMask m, MonadIO m) =>
Delimiter
-> FilePath
-> FoldM m (Vector ByteString) result
-> m (ParseStop, result)
foldDsvFileIgnoringHeaderM Delimiter
comma FilePath
fp FoldM m (Vector ByteString) result
fld

{- |

=== Example

CSV file:

> Date,Vendor,Price,Product
> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.premap' ('viewOr' 0 $ 'byteStringDollarsView' '<<<-' 'lookupView' (== \"Price")) 'L.sum'
@

Result:

@
('ParseComplete', 624.84)
@

-}

foldCsvFileWithZippedHeader ::
    forall m result .
    MonadIO m
    => FilePath
        -- ^ The path of a CSV file to read
    -> Fold (Vector (ByteString, ByteString)) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileWithZippedHeader :: FilePath
-> Fold (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
foldCsvFileWithZippedHeader FilePath
fp Fold (Vector (ByteString, ByteString)) result
fld =
    Delimiter
-> FilePath
-> Fold (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
MonadIO m =>
Delimiter
-> FilePath
-> Fold (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
foldDsvFileWithZippedHeader Delimiter
comma FilePath
fp Fold (Vector (ByteString, ByteString)) result
fld

{- |

=== Example

CSV file:

> Date,Vendor,Price,Product
> 2019-03-24,Acme Co,$599.89,Dehydrated boulders
> 2019-04-18,Acme Co,$24.95,Earthquake pills

Fold:

@
'L.mapM_' ('traverse_' 'BS.putStrLn' . 'vectorLookup' (== \"Product")) *> 'L.generalize' 'L.length'
@

Output printed to the terminal:

> Dehydrated boulders
> Earthquake pills

Result:

@
('ParseComplete', 2)
@

-}

foldCsvFileWithZippedHeaderM ::
    forall m result .
    (MonadCatch m, MonadMask m, MonadIO m)
    => FilePath
        -- ^ The path of a CSV file to read
    -> FoldM m (Vector (ByteString, ByteString)) result
        -- ^ What to do with each row
    -> m (ParseStop, result)

foldCsvFileWithZippedHeaderM :: FilePath
-> FoldM m (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
foldCsvFileWithZippedHeaderM FilePath
fp FoldM m (Vector (ByteString, ByteString)) result
fld =
    Delimiter
-> FilePath
-> FoldM m (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
forall (m :: * -> *) result.
(MonadCatch m, MonadMask m, MonadIO m) =>
Delimiter
-> FilePath
-> FoldM m (Vector (ByteString, ByteString)) result
-> m (ParseStop, result)
foldDsvFileWithZippedHeaderM Delimiter
comma FilePath
fp FoldM m (Vector (ByteString, ByteString)) result
fld