﻿B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=7.8
@EndOfDesignText@
'Based on CSVParser v1.00 (https://www.b4x.com/android/forum/threads/b4x-csvparser-csv-parser-and-generator.110901)
'Changes by WM: added methods ParseToMaps, GetHeaders

Sub Class_Globals
	Private CurrentIndex As Int
End Sub

Public Sub Initialize
	
End Sub

Public Sub GenerateString(Table As List, SeparatorChar As String) As String
	Dim eol As String = Chr(10)
	If Table.Size = 0 Then Return ""
	Dim sb As StringBuilder
	sb.Initialize
	For Each row() As String In Table
		For i = 0 To row.Length - 1
			Dim Wrap As Boolean
			Dim word As String = row(i)
			If word.Contains(SeparatorChar) Then Wrap = True
			If word.Contains(QUOTE) Then
				Wrap = True
				word = word.Replace(QUOTE, $""""$)
			End If
			If Wrap Then
				sb.Append(QUOTE).Append(word).Append(QUOTE)
			Else
				sb.Append(word)
			End If
			sb.Append(SeparatorChar)
		Next
		sb.Remove(sb.Length - 1, sb.Length)
		sb.Append(eol)
	Next
	sb.Remove(sb.Length - eol.Length, sb.Length)
	Return sb.ToString
End Sub

Public Sub Parse(Input As String, SeparatorChar As String, SkipFirstRow As Boolean) As List
	SeparatorChar = SeparatorChar.CharAt(0)
	Dim Result As List
	Result.Initialize
	If Input = "" Then Return Result
	CurrentIndex = 0
	Dim count As Int = ReadLine(Input, Null, True, SeparatorChar)
	If SkipFirstRow = False Then CurrentIndex = 0
	Do While CurrentIndex < Input.Length
		Dim row(count) As String
		ReadLine(Input, row, False, SeparatorChar)
		Result.Add(row)
	Loop
	Return Result
End Sub

Private Sub ReadLine(Input As String, Row() As String, JustCount As Boolean, Sep As String) As Int
	Dim InsideQuotes As Boolean
	Dim sb As StringBuilder
	sb.Initialize
	Dim count As Int
	Do While CurrentIndex <= Input.Length
		Dim c As String
		If CurrentIndex < Input.Length Then
			c = Input.CharAt(CurrentIndex)
		Else
			c = Chr(10)
		End If
		If InsideQuotes Then
			If c = QUOTE Then
				'double quotes
				If CurrentIndex < Input.Length - 1 And Input.CharAt(CurrentIndex + 1) = QUOTE Then
					sb.Append(QUOTE)
					CurrentIndex = CurrentIndex + 1
				Else
					InsideQuotes = False
				End If
			Else
				sb.Append(c)
			End If
		Else
			If c = Chr(13) Then
				CurrentIndex = CurrentIndex + 1
				Continue
			Else If c = Chr(10) Then
				If JustCount = False Then Row(count) = sb.ToString
				count = count + 1
				CurrentIndex = CurrentIndex + 1
				Exit
			Else If c = Sep Then
				If JustCount = False Then Row(count) = sb.ToString
				sb.Remove(0, sb.Length)
				count = count + 1
				InsideQuotes = False
			Else If c = QUOTE Then
				InsideQuotes = True
			Else
				sb.Append(c)
			End If
		End If
		CurrentIndex = CurrentIndex + 1
	Loop
	Return count
End Sub

' Returns a list with the headers found in the first line.
' If lowerCase is true, all values are shifted to lowercase.
Public Sub GetHeaders(Input As String, SeparatorChar As String, lowerCase As Boolean) As List ' Added by WM
	Dim i As Int
	SeparatorChar = SeparatorChar.CharAt(0)
	Dim Result As List
	Result.Initialize
	If Input = "" Then Return Result
	CurrentIndex = 0
	Dim count As Int = ReadLine(Input, Null, True, SeparatorChar)
	CurrentIndex = 0
	Dim row(count) As String
	ReadLine(Input, row, False, SeparatorChar)
	For i = 0 To (row.Length - 1)
		If lowerCase Then
			Result.Add(row(i).ToLowerCase)
		Else
			Result.Add(row(i))
		End If
	Next
	Return Result
End Sub

' Assumes the first row contains headers.
' Returns a list of maps. Each map contains, for all headers: key=header, value=value found in the data row.
' If lowerCase is true, all keys in the maps are shifted to lowercase.
Public Sub ParseToMaps(Input As String, SeparatorChar As String, lowerCase As Boolean) As List ' Added by WM

	Dim headers As List = GetHeaders(Input, SeparatorChar, lowerCase)
	Dim i As Int

	SeparatorChar = SeparatorChar.CharAt(0)
	Dim Result As List
	Result.Initialize
	If Input = "" Then Return Result
	CurrentIndex = 0
	Dim count As Int = ReadLine(Input, Null, True, SeparatorChar)
	Do While CurrentIndex < Input.Length
		Dim row(count) As String
		ReadLine(Input, row, False, SeparatorChar)
		Dim m As Map
		m.Initialize
		For i = 0 To (row.Length - 1)
			m.Put(headers.Get(i).As(String), row(i))
		Next
		Result.Add(m)
	Loop
	Return Result
End Sub