local p = {}
 
default_settings = {
  delimiter = ',',
  quotechar = '"',
  ignoreEmptyLines = true,
  --linebreak deviates from RFC4180, where the default linebreak is CRLF. Mediawiki newlines are linebreaks
  linebreak = '\n'
}
 
--datastring is the string containing the CSV data. settings follows the format of default_settings
--returns a table which is a squence of sequeces of fields
function parse(datastring, settings)
  if settings == nil then settings = {} end
  if type(settings) ~= 'table' then return {}, "Error, settings is not a table" end
  for k, v in pairs(default_settings) do
    if settings[k] == nil then settings[k] = default_settings[k] end
  end
 
  return readdata(datastring, settings)
end
 
function readdata(datastring, settings)
    datastring = datastring:gsub( settings.linebreak, settings.linebreak .. settings.delimiter ) .. settings.delimiter;
        
    local item_list = {};
    for v in datastring:gmatch( "([^" .. settings.delimiter .."]*)" .. settings.delimiter ) do
        table.insert( item_list, v );
    end
    
    local item_list2 = {};
    local current = ''
    local inquote = false
    for _, v in ipairs( item_list ) do
        if not inquote then
            if v:match( "^%s*" .. settings.quotechar ) then
                inquote = true;
                current = v;
            else
                table.insert( item_list2, v );
            end
        else
            current = current .. settings.delimiter .. v;
        end
        if inquote then
            if v:match( settings.quotechar .. "%s*$" ) and not current:match( "^%s*" .. settings.quotechar .. "%s*$" ) then
                current = current:match( "^%s*" .. settings.quotechar .. "(.*)" .. settings.quotechar .. "%s*$" );
                current = current:gsub( settings.linebreak .. settings.delimiter, settings.linebreak );
                current = current:gsub( settings.quotechar .. settings.quotechar, settings.quotechar );
                table.insert( item_list2, current );
                inquote = false;
                current = '';
            end            
        end
    end
          
    if current ~= '' then
        table.insert( item_list2, current );
    end
    
    local rows = {};
    item_list = {};
    local front = ''
    for _, v in ipairs(item_list2) do
        front = v:match( "(.*)" .. settings.linebreak .. "$" );
        if front ~= nil then
            if #item_list > 0 or front:len() > 0 or not settings.ignoreEmptyLines then 
                table.insert( item_list, front )
                table.insert( rows, item_list );
            end
            item_list = {};
        else
            table.insert( item_list, v );
        end
    end
    if #item_list > 0 then
        table.insert( rows, item_list );
    end
    
    return rows;
end
 
p.parse = parse
return p