-- Autogenerated with DRAKON Editor 1.32
local table = table
local string = string
local pairs = pairs
local ipairs = ipairs
local type = type
local box = box

local tostring = tostring
local tonumber = tonumber
local error = error
local print = print



local math = require("math")
local clock = require("clock")

local log = require('log')
local fio = require('fio')
local json = require('json')
local msgpackffi = require('msgpackffi')
local errno = require('errno')
local fun = require('fun')
local buffer = require('buffer')
local ffi = require('ffi')
local msgpack = require('msgpack')
local pickle = require('pickle')
local utils = require("utils")



setfenv(1, {}) 


function convert_params()
    -- item 433
    local folders = box.space.folders:select()
    for _, row in ipairs(folders) do
        -- item 366
        local prow = find_params_row(row)
        -- item 367
        if prow then
            -- item 370
            transfer_params(row, prow)
        end
    end
end

function dump(path)
    local message, ok, spaces, stats
    -- item 24
    ok = false
    message = nil
    -- item 142
    ok, message = prepare_dump_folder(
        path
    )
    -- item 144
    if ok then
        -- item 147
        spaces = get_spaces()
        -- item 172
        stats = {}
        for _, space in ipairs(spaces) do
            -- item 151
            if is_user_space(space) then
                -- item 173
                stats[space] = {count=0}
                -- item 150
                ok, message = export_space(
                    stats,
                    space,
                    path
                )
                -- item 168
                if ok then
                    
                else
                    break
                end
            end
        end
        -- item 171
        ok = true
    end
    -- item 174
    print_stats(stats)
    -- item 143
    return ok, message
end

function export_row(row, fh, space)
    local length_str, row_str
    -- item 217
    row_str = msgpack.encode(row)
    -- item 219
    length_str = pickle.pack("i", #row_str)
    -- item 220
    if (fh:write(length_str)) and (fh:write(row_str)) then
        -- item 224
        return true, nil
    else
        -- item 225
        return false, "could not export row for " .. space
    end
end

function export_space(stats, space, path)
    local fh, filename, space_obj, stat
    -- item 180
    local ok = false
    local message = nil
    -- item 175
    space_obj = box.space[space]
    -- item 183
    filename = fio.pathjoin(
        path,
        space
    )
    -- item 176
    fh = fio.open(
        filename,
        {"O_CREAT", "O_TRUNC", "O_WRONLY"},
        438
    )
    -- item 184
    if fh then
        -- item 226
        stat = stats[space]
        local normal_197
        normal_197 = 1
        for i, row in space_obj:pairs() do
            -- item 199
            ok, message = export_row(
                row,
                fh,
                space
            )
            -- item 200
            if ok then
                
            else
                normal_197 = 0
                break
            end
            -- item 227
            stat.count = stat.count + 1
        end
        if normal_197 == 1 then
            -- item 188
            ok = true
        end
    else
        -- item 187
        message = "could not create file " .. filename
    end
    -- item 177
    if fh then
        -- item 181
        fh:close()
    end
    -- item 182
    return ok, message
end

function find_params_row(folder_row)
    -- item 376
    local space_id = folder_row[1]
    local folder_id = folder_row[2]
    -- item 377
    local items = box.space.items:select{
    	space_id, folder_id}
    for _, row in ipairs(items) do
        -- item 385
        local data = row[4]
        -- item 380
        if data.type == "params" then
            -- item 383
            return row
        end
    end
    -- item 384
    return nil
end

function get_spaces()
    local spaces
    -- item 9
    spaces = {}
    for name, space in pairs(box.space) do
        -- item 8
        table.insert(
            spaces,
            name
        )
    end
    -- item 5
    return spaces
end

function import_row(fh, space_obj, space)
    local done, inserted, length, length_str, message, ok, row, row_str
    -- item 332
    ok = false
    done = false
    message = nil
    -- item 328
    length_str = fh:read(4)
    -- item 329
    if (length_str) and (not (#length_str == 0)) then
        -- item 326
        length = pickle.unpack(
            "i",
            length_str
        )
        -- item 336
        if length then
            -- item 337
            row_str = fh:read(length)
            -- item 338
            if row_str then
                -- item 339
                row = msgpack.decode(row_str)
                -- item 340
                if row then
                    -- item 342
                    inserted = space_obj:insert(row)
                    -- item 343
                    if type(inserted) == "table" then
                        -- item 341
                        ok = true
                    else
                        -- item 346
                        message = "unique constraint violation: " ..
                          space
                    end
                else
                    -- item 334
                    message = "could not read " .. space
                end
            else
                -- item 334
                message = "could not read " .. space
            end
        else
            -- item 334
            message = "could not read " .. space
        end
    else
        -- item 349
        ok = true
        done = true
    end
    -- item 333
    return ok, done, message
end

function import_space(file, stats)
    local done, fh, message, ok, space, space_obj, stat
    -- item 291
    ok = false
    message = nil
    -- item 292
    space = fio.basename(file)
    -- item 293
    space_obj = box.space[space]
    -- item 294
    if space_obj then
        -- item 307
        fh = fio.open(
            file,
            {"O_RDONLY"}
        )
        -- item 308
        if fh then
            -- item 306
            stat = {count=0}
            stats[space] = stat
            while true do
                -- item 312
                ok, done, message = import_row(
                    fh,
                    space_obj,
                    space
                )
                -- item 350
                if done then
                    break
                end
                -- item 357
                stat.count = stat.count + 1
            end
        else
            -- item 311
            message = "could not open file " .. file
        end
    else
        -- item 297
        log.info("space " .. space ..
         " does not exist")
        -- item 358
        ok = true
    end
    -- item 298
    if fh then
        -- item 301
        fh:close()
    end
    -- item 302
    return ok, message
end

function is_user_space(name)
    -- item 136
    if (tonumber(name) == nil) and (not (name:sub(1, 1) == "_")) then
        -- item 139
        return true
    else
        -- item 140
        return false
    end
end

function parse_params(text)
    -- item 402
    local params = ""
    local keywords = nil
    -- item 404
    if text then
        -- item 409
        local lines = utils.split_trim(text, "\n")
        -- item 408
        if #lines == 0 then
            
        else
            -- item 417
            local first_parts = utils.split_trim(
            	lines[1],
            	" "
            )
            -- item 418
            local start, i
            local params_list = {}
            local keys = false
            keywords = {}
            -- item 419
            if utils.contains(first_parts, "async") then
                -- item 422
                keywords["async"] = true
                keys = true
            end
            -- item 423
            if utils.contains(first_parts, "export") then
                -- item 426
                keywords["export"] = true
                keys = true
            end
            -- item 427
            if keys then
                -- item 431
                start = 2
            else
                -- item 430
                start = 1
                keywords = nil
            end
            -- item 4100001
            i = start
            while true do
                -- item 4100002
                if i <= #lines then
                    
                else
                    break
                end
                -- item 412
                local line = lines[i]
                -- item 416
                table.insert(
                	params_list,
                	line
                )
                -- item 4100003
                i = i + 1
            end
            -- item 432
            params = utils.join(params_list, "\n")
        end
    end
    -- item 403
    return keywords, params
end

function prepare_dump_folder(path)
    local message, ok, out_folder, pattern
    -- item 107
    message = nil
    ok = false
    -- item 100
    out_folder = fio.stat(path)
    -- item 102
    if out_folder then
        -- item 108
        if out_folder:is_dir() then
            -- item 121
            pattern = fio.pathjoin(path, "*")
            for k, file in pairs(fio.glob(pattern)) do
                -- item 122
                if fio.stat(file):is_dir() then
                    
                else
                    -- item 125
                    ok = fio.unlink(file)
                    -- item 126
                    if ok then
                        
                    else
                        -- item 127
                        message = "could not delete " .. file
                        break
                    end
                end
            end
            -- item 130
            ok = true
        else
            -- item 110
            message = path .. " is not a folder"
        end
    else
        -- item 101
        ok = fio.mkdir(path)
        -- item 105
        if ok then
            
        else
            -- item 111
            message = "could not create folder " .. path
        end
    end
    -- item 112
    return ok, message
end

function print_stats(stats)
    for space, stat in pairs(stats) do
        -- item 196
        print(
            space,
            stat.count
        )
    end
end

function read_dump_folder(path)
    local folder, message, ok, pattern, result
    -- item 246
    message = nil
    ok = false
    result = nil
    -- item 243
    folder = fio.stat(path)
    -- item 244
    if folder then
        -- item 247
        if folder:is_dir() then
            -- item 254
            result = {}
            -- item 257
            pattern = fio.pathjoin(path, "*")
            for k, file in pairs(fio.glob(pattern)) do
                -- item 258
                if fio.stat(file):is_dir() then
                    
                else
                    -- item 261
                    table.insert(
                        result,
                        file
                    )
                end
            end
        else
            -- item 249
            message = path .. " is not a folder"
        end
    else
        -- item 253
        message = "folder " .. path ..
         " does not exist"
    end
    -- item 252
    return result, message
end

function restore(path)
    local files, message, ok, stats
    -- item 262
    ok = false
    message = nil
    -- item 265
    files, message = read_dump_folder(
        path
    )
    -- item 266
    if files then
        -- item 269
        stats = {}
        local normal_270
        normal_270 = 1
        for _, file in ipairs(files) do
            -- item 272
            ok, message = import_space(
                file,
                stats
            )
            -- item 273
            if ok then
                
            else
                normal_270 = 0
                break
            end
        end
        if normal_270 == 1 then
            -- item 276
            ok = true
        end
    end
    -- item 264
    print_stats(stats)
    -- item 263
    return ok, message
end

function transfer_params(folder_row, item_row)
    -- item 391
    local space_id = item_row[1]
    local folder_id = item_row[2]
    local item_id = item_row[3]
    local idata = item_row[4]
    -- item 392
    local fdata = folder_row[3]
    -- item 395
    local keywords, params = parse_params(idata.text)
    -- item 401
    fdata.params = params
    fdata.keywords = keywords
    -- item 394
    box.space.folders:replace {
    	space_id,
    	folder_id,
    	fdata
    }
    -- item 393
    box.space.items:delete {
    	space_id,
    	folder_id,
    	item_id
    }
end


return {
	dump = dump,
	restore = restore,
	convert_params = convert_params
}
