-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local Pca9555 = {
    offset_width = 1,
}

local CommonI2c = require "protocol.CommonI2c"
local JsonParser = require "data.JsonParser"
local log = require "log"
local cjson = require "cjson"

local default_file = "../chip/template/default_pca9555.json"

function Pca9555:new(o, offset_width)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.offset_width = offset_width
    return o
end

local Pca9555Parser = {
    prot_parser = {},
    data_parser = {},
    SIZE_IDX = 2,
    DATA_IDX = 3
}

function Pca9555Parser:new(o, prot_parser, data_parser)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.prot_parser = prot_parser
    self.data_parser = data_parser
    return o
end

function Pca9555Parser:parse(offset)
    local key = string.format("0x%02x", offset)
    log:print(LOG_DEBUG, "key: %s", key)
    self.value = self.data_parser:get_value(key)
    if self.value == nil then
        return false
    end

    log:print(LOG_DEBUG, "value: %s", cjson.encode(self.value))

    self.size = self.value[self.SIZE_IDX]
    self.data = {}
    for i = self.DATA_IDX, #self.value do
        table.insert(self.data, tonumber(self.value[i], 16))
    end
    if self.size ~= #self.data then
        log:print(LOG_DEBUG, string.format("size error, get size(%d), real size(%d)", self.size, #self.data))
        return false
    end

    return true
end

function Pca9555Parser:read_data(length)
    local offset = self.prot_parser:parse_offset()
    -- 奇数转为偶数，寄存器顺序反转
    local odd_flag = false
    if offset & 1 == 1 then
        odd_flag = true
        offset = offset - 1
    end
    local ret = self:parse(offset)
    if ret ~= true then
        log:print(LOG_DEBUG, "read data parser fail")
        return
    end


    local tmp = {}
    if odd_flag then
        for i = #self.data, 1, -1 do
            table.insert(tmp, self.data[i])
        end
    else
        tmp = self.data
    end

    log:print(LOG_DEBUG, cjson.encode(tmp))

    if length > self.size then
        return
    end
    local result = {}
    for i = 1, math.min(length, #tmp) do
        result[i] = tmp[i]
    end
    return result
end

function Pca9555Parser:write_data(data)
    local offset = self.prot_parser:parse_offset()
    -- 奇数转为偶数，寄存器顺序反转
    local odd_flag = false
    if offset & 1 == 1 then
        odd_flag = true
        offset = offset - 1
    end
    local ret = self:parse(offset)
    if ret ~= true then
        log:print(LOG_DEBUG, "write data parser fail")
        return
    end
    local write_data = self.prot_parser:parse_data()

    local tmp = {}
    if odd_flag then
        for i = #write_data, 1, -1 do
            table.insert(tmp, write_data[i])
        end
    else
        tmp = write_data
    end

    local i = self.DATA_IDX
    local j = 1

    while i <= #self.value and j <= #tmp do
        self.value[i] = string.format("%02x", tmp[j])
        i = i + 1
        j = j + 1
    end
    log:print(LOG_DEBUG, cjson.encode(self.value))

    local key = string.format("0x%02x", offset);
    self.data_parser:set_value(key, self.value)
    self.data_parser:write_file()
end

function Pca9555:read(tx_buffer, length, filename)
    if #tx_buffer < 2 then
        return
    end
    local common_i2c = CommonI2c:new(nil, tx_buffer, self.offset_width)
    local json_parser = JsonParser:new(nil, filename, default_file)

    local pca9555_parser = Pca9555Parser:new(nil, common_i2c, json_parser)
    return pca9555_parser:read_data(length)
end

function Pca9555:write(tx_buffer, filename)
    if #tx_buffer < 2 then
        return
    end
    local common_i2c = CommonI2c:new(nil, tx_buffer, self.offset_width)
    local json_parser = JsonParser:new(nil, filename, default_file)

    local pca9555_parser = Pca9555Parser:new(nil, common_i2c, json_parser)
    pca9555_parser:write_data()
end

return Pca9555