-- file.lua   HMI ڴ氲ȫ淶ļģ
-- ?? Ͻļݣвʽ

_ENCRYPT_ = 0

file = {}
local CHUNK_SIZE = 2048  -- ƽ̨һ

-- ļģʽ HMI API һ£
file.mode = {
    read   = 0,  -- ֻ
    create = 1,  -- д
    append = 2   -- ׷д
}

-- ȫַָplain=true
function my_split(str, sep)
    if not str or #str == 0 then return {} end
    local t, last = {}, 0
    local s, e = string.find(str, sep, 1, true)
    while s do
        table.insert(t, string.sub(str, last + 1, s - 1))
        last = e
        s, e = string.find(str, sep, last + 1, true)
    end
    if last < #str then table.insert(t, string.sub(str, last + 1)) end
    return t
end

-- ļǷ
function file.exists(filepath)
    if type(filepath) ~= "string" or #filepath == 0 then return false end
    local ok = file_open(filepath, file.mode.read)
    if ok then file_close() end
    return ok
end

-- ȫʽȡļĽӿڣ
-- @filepath: ļ·
-- @on_chunk: ص(chunk_table, offset, is_last)
--   - chunk_table: ǰֽ (1~2048 ֽ)
--   - offset: ǰʼƫ
--   - is_last: Ƿһ
-- @return: true ɹ, false ʧ
function file.read_stream(filepath, on_chunk)
    if not file.exists(filepath) then return false end
    
    local ok = file_open(filepath, file.mode.read)
    if not ok then return false end
    
    local size = file_size()
    if size == 0 then
        file_close()
        return true
    end
    
    local blocks = math.ceil(size / CHUNK_SIZE)
    for i = 1, blocks do
        local offset = (i - 1) * CHUNK_SIZE
        if not file_seek(offset) then break end
        
        local count = (i == blocks) and (size % CHUNK_SIZE ~= 0 and size % CHUNK_SIZE or CHUNK_SIZE) or CHUNK_SIZE
        local chunk = file_read(count)
        
        if not chunk or #chunk == 0 then break end
        
        local is_last = (i == blocks)
        if not on_chunk(chunk, offset, is_last) then
            -- ص false ǰֹ
            break
        end
        feed_dog()
    end
    
    file_close()
    return true
end

-- ȫдļСݣ
-- @filepath: Ŀ·
-- @data: string  byte table (2048 ֽ)
-- @mode: file.mode.create / append
-- @return: true ɹ, false ʧ
function file.write_chunk(filepath, data, mode)

    if mode ~= file.mode.create and mode ~= file.mode.append then return false end

    local is_str = (type(data) == "string")
    local len = is_str and string.len(data) or #data

    if len == 0 then return true end
    if len > CHUNK_SIZE 
    then
        print("ERROR: write_chunk data too large (>2048)")
        return false
    end

    local ok = file_open(filepath, mode)
    if not ok then return false end

    -- ׷ģʽ趨λĩβ
    if mode == file.mode.append 
    then
        local size = file_size()
        if not file_seek(size) 
        then
            file_close()
            return false
        end
    end
    
    -- ֽ
    local buf = {}
    if is_str 
    then
        for i = 1, len do buf[i] = string.byte(data, i) end
    else
        for i = 1, len do buf[i] = data[i] end
    end
    
    local ret = file_write(buf)
    file_close()
    return ret
end

-- ȫȡСļ 4KB ļ
-- @as_string: trueַ, falseֽ
-- @max_size: СĬ 4096
function file.read_small(as_string, filepath, max_size)
    max_size = max_size or 4096
    if not file.exists(filepath) then return nil end
    
    local ok = file_open(filepath, file.mode.read)
    if not ok then return nil end
    
    local size = file_size()
    if size > max_size then
        file_close()
        return nil  -- ܾļ
    end
    
    local chunk = file_read(size)
    file_close()
    
    if not chunk then return nil end
    
    if as_string then
        local str = ""
        for _, b in ipairs(chunk) do
            str = str .. string.char(b)
        end
        return str
    else
        return chunk
    end
end