-- SerializeLib

-- getString
-- Converts the contents of a table to a simple text format. Child class names will
-- be prefixed with a "-".
-- Arguments
--   obj: the object or table to encode
--   name: the name of the object, will be embedded in the returned data
-- returns: string containing the JSON encoded value of obj

function getString(obj,name,i)
    if i == nil then i=-1 end
    local ret=""
    local val=""
    
    if type(obj) == "nil" then
        val = "nil"
    elseif type(obj) == "number" or type(obj) == "boolean" then
        val = tostring(obj)
    elseif type(obj) == "string" then
        val = escape(obj)
    elseif type(obj) == "userdata" then
        name="userdata:" .. name
        val = escape(tostring(obj))
    elseif type(obj) == "table" then
        if name ~= nil and obj.is_a ~= nil then
            name = "class:" .. name
        end
        
        if name ~= nil then val = "{" end
        for k,v in pairs(obj) do
            if tostring(k):sub(1,1) ~= "_" then
                local s=getString(v,k,i+1)
                if s ~= "" then
                    val = val .. s
                end
            end
        end
        if name ~= nil then
            val = val .. string.rep(" ",i) .. "}\n"
        end
    else
        name=""
        val=""
    end
    
    if name ~= nil and name ~= "" then
        -- ret = ret .. string.rep(" ",i) .. name .. "="
        ret = ret .. string.rep(" ",i)
    end
    if val ~= "" then
        ret = ret .. val .. ","
    end
    
    -- ******* pretty much only good for use in this project
    ret = string.gsub(ret, ",}\n,}\n,", "}\n}") --format end of table
    ret = string.gsub(ret, " (-)", "%1") --remove spaces in front of minus signs
    ret = string.gsub(ret, "{{ ", "{\n\t{") --format start of table
    ret = string.gsub(ret, ",}\n,{ ", "},\n\t{") --format table to have one subtable per line
    return ret
end

-- escape special characters in a string
function escape(str)
    local ret=str
    ret = ret:gsub("\\","\\\\")
    ret = ret:gsub("\"","\\\"")
    ret = ret:gsub("\n","\\n")
    ret = ret:gsub("\r","\\r")
    return "\"" .. ret .. "\""
end

function unescape(str)
    local ret=str
    if ret:sub(1,1)=="\"" then ret=ret:sub(2) end
    if ret:sub(-1,-1)=="\"" then ret=ret:sub(1,-2) end
    ret = ret:gsub("\\\\","\\")
    ret = ret:gsub("\\\"","\"")
    ret = ret:gsub("\\n","\n")
    ret = ret:gsub("\\r","\r")
    return ret
end

-- loadTable
--   loads a table with the values from data
--   child tables will be loaded in to new tables
-- Example:
--   data="{letters:{1:"a",2:"b"},numbers(1:1,2:2}}"
--   t={}
--   loadTable(t,data)
--
--   results:
--     t.letters={"a","b"}
--     t.numbers={1,2}
-- Arguments:
--   myTable: the table or object to populate
--   data: string data encoded with getString
-- Returns: nothing
function loadTable(myTable,data,startPos)
    if startPos == nil then startPos=1 end
    local len=data:len()
    local pos=0
    local key=""
    local val=""
    
    while pos ~= nil and startPos ~= nil and startPos <= len do
        while data:sub(startPos,startPos) <= " " and startPos <= len do
            startPos = startPos + 1
        end
        if data:sub(startPos,startPos) == "}" then
            return startPos+1
        end
        if startPos > len then
            return startPos
        end
        
        pos=data:find("=",startPos,true)
        if pos ~= nil then
            key=data:sub(startPos,pos-1)
            local n=tonumber(key)
            if n ~= nil then key = n end
            startPos=pos+1
            pos=data:find("\n",startPos,true)
            if pos == nil then pos=len+1 end
            val=data:sub(startPos,pos-1)
            startPos=pos+1
            if val == "class {" then
                local child={}
                myTable["class:" .. key]=child
                startPos = loadTable(child,data,startPos)
            elseif val == "{" then
                local child={}
                myTable[key]=child
                startPos = loadTable(child,data,startPos)
            elseif val:sub(1,1) == "\"" then
            myTable[key]=unescape(val)
        elseif val == "true" then
            myTable[key]=true
        elseif val == "false" then
            myTable[key]=false
        elseif val:sub(1,8)=="userdata" then
            myTable["userdata:key"]=val:sub(10)
        else
            myTable[key]=tonumber(val)
        end
    end
end

return startPos
end


