--   This file is part of Reno desktop.
--
--  Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
--  Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>. 

-- Various utilitiy parsers
local parsers = {}

local function split_strings(text)
    -- probably the cleanest function to split by strings i've written
    local split = {}
    while text:find("\"") do
        local strstart = text:find("\"")
        while text:sub(strstart-1,strstart-1) == "\\" do
            strstart = text:find("\"",strstart+1)
        end
        local strend = text:find("\"",strstart+1)
        while text:sub(strend-1,strend-1) == "\\" do
            strend = text:find("\"",strend+1)
        end
        if not strend then
            return nil, "String not closed at "..strstart
        end
        local before_string = text:sub(1,strstart-1)
        local string = text:sub(strstart,strend):gsub("\\\"","\"")
        text = text:sub(strend+1,-1)
        table.insert(split,before_string)
        table.insert(split,string)
    end
    table.insert(split,text)
    return split
end

parsers.conf = function(cfgtext)
    cfgtext = cfgtext:gsub("#[^\n]*","")
    local split_by_strings,err = split_strings(cfgtext)
    if not split_by_strings then
        error(err)
    end
    local struct = {global = {}}
    local block = "global"
    local last_string_key = nil
    local err
    for k,v in pairs(split_by_strings) do
        if not v:match("^\".*\"$") then
            v:gsub("[^\n]*",function(line)
                -- Nothing
                if line:match("^%s*$") then
                    return
                end
                -- Namespace block
                if line:match("^%s*%[[^%]]-%]%s*$") then
                    block = line:match("%[([^%]]-)%]")
                    struct[block] = {}
                    return
                end
                -- String/Multiline string assignment
                if line:match("^%s*[^=]-%s*=%s*$") then
                    last_string_key = line:match("^%s*([^=]-)%s*=%s*$")
                    return
                end
                -- Number/boolean assignment
                local key,value = line:match("^%s*([^=]-)%s*=%s*(.-)%s*$")    
                -- number
                if value:match("^[%d%.]*$") then
                    value = tonumber(value)
                -- bool
                elseif (value:lower() == "yes") or (value:lower() == "no") then
                    value = (value:lower() == "yes")
                end
                struct[block][key] = value
            end)
        else
            struct[block][last_string_key] = v:sub(2,-2)
        end
    end
    return struct
end
return parsers
