-- parseCSV parses a CSV string.
-- The header `header` is used as the table header.
-- If header is Nothing, the first line of the CSV data is used as a header.
-- It returns the alignments of the columns and the table itself.
-- The cells are left or right justified.
parseCSV :: Maybe [String] -> String -> ([Alignment], [[String]])
parseCSV header csvData = (columnFormats, table)
    where
        -- CSV parser
        qm = '"'
        sep = inferSeparator csvData
        rows = case fromString qm sep csvData of
                    Exceptional{exception=Nothing, result=rs} -> joinMultiLines rs
                    Exceptional{exception=Just exc} -> errorWithoutStackTrace exc
        -- Header
        rows' = case header of
            Nothing -> rows
            Just h -> h : rows
        -- Line padding (each line must have the same length)
        maxRowLen = maximum $ map length rows'
        paddedRows = [ row ++ replicate (maxRowLen - length row) "" | row <- rows' ]
        -- Left/right alignment according to the kind of data
        columnFormats = map columnFormat $ transpose paddedRows
        table = align paddedRows columnFormats

-- Infers the most probable separator according to the frequencies of characters
parseCSV :: Maybe [String] -> String -> ([Alignment], [[String]])
parseCSV header csvData = (columnFormats, table)
    where
        -- CSV parser
        qm = '"'
        sep = inferSeparator csvData
        rows = case fromString qm sep csvData of
                    Exceptional{exception=Nothing, result=rs} -> joinMultiLines rs
                    Exceptional{exception=Just exc} -> errorWithoutStackTrace exc
        -- Header
        rows' = case header of
            Nothing -> rows
            Just h -> h : rows
        -- Line padding (each line must have the same length)
        maxRowLen = maximum $ map length rows'
        paddedRows = [ row ++ replicate (maxRowLen - length row) "" | row <- rows' ]
        -- Left/right alignment according to the kind of data
        columnFormats = map columnFormat $ transpose paddedRows
        table = align paddedRows columnFormats

-- Infers the most probable separator according to the frequencies of characters
parseCSV header csvData = (columnFormats, table)
    where
        -- CSV parser
        qm = '"'
        sep = inferSeparator csvData
        rows = case fromString qm sep csvData of
                    Exceptional{exception=Nothing, result=rs} -> joinMultiLines rs
                    Exceptional{exception=Just exc} -> errorWithoutStackTrace exc
        -- Header
        rows' = case header of
            Nothing -> rows
            Just h -> h : rows
        -- Line padding (each line must have the same length)
        maxRowLen = maximum $ map length rows'
        paddedRows = [ row ++ replicate (maxRowLen - length row) "" | row <- rows' ]
        -- Left/right alignment according to the kind of data
        columnFormats = map columnFormat $ transpose paddedRows
        table = align paddedRows columnFormats

-- Infers the most probable separator according to the frequencies of characters