-- 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 log = require 'mc.logging'
local skynet = require 'skynet'
local class = require 'mc.class'

local led_tube_object = class()

local LED_TUBE_MAX_NUM <const> = 3
local LED_TUBE_SHOW_DATA <const> = {
    ['0'] = 0x3F, ['1'] = 0x06, ['2'] = 0x5B, ['3'] = 0x4F, ['4'] = 0x66,
    ['5'] = 0x6D, ['6'] = 0x7D, ['7'] = 0x07, ['8'] = 0x7F, ['9'] = 0x6F,
    ['-'] = 0x40, ['A'] = 0x77, ['b'] = 0x7C, ['C'] = 0x39, ['d'] = 0x5E,
    ['E'] = 0x79, ['F'] = 0x71, ['G'] = 0x3D, ['H'] = 0x76, ['L'] = 0x38,
    ['n'] = 0x54, ['P'] = 0x73, ['q'] = 0x67, ['r'] = 0x50, ['t'] = 0x78,
    ['U'] = 0x3E, ['y'] = 0x6E, [' '] = 0x00,
    -- 上面是标准写法，以下支持兼容字母的大小写，增加容错
    ['a'] = 0x77, ['B'] = 0x7C, ['c'] = 0x39, ['D'] = 0x5E, ['e'] = 0x79,
    ['f'] = 0x71, ['g'] = 0x3D, ['h'] = 0x76, ['l'] = 0x38, ['N'] = 0x54,
    ['p'] = 0x73, ['Q'] = 0x67, ['R'] = 0x50, ['T'] = 0x78, ['u'] = 0x3E,
    ['Y'] = 0x6E
}

local led_tube_switch <const> = { 'LeftLedTube', 'MidLedTube', 'RightLedTube' }

function led_tube_object:ctor(led_disp_ctrl)
    self.led_disp_ctrl = led_disp_ctrl
    self.display_info = '   '
end

function led_tube_object:is_support_led_tube()
    return self.led_disp_ctrl['LedTubeSupport'] == true
end

-- 设置单个led指示灯
function led_tube_object:set_single_tube_value(led_num, show_data)
    if not led_tube_switch[led_num] or not LED_TUBE_SHOW_DATA[show_data] then
        log:error('[ledtube] led number or data to be displayed is invalid')
        return false
    end
    log:debug('[ledtube] %s will be set 0x%x', led_tube_switch[led_num], LED_TUBE_SHOW_DATA[show_data])
    self.display_info = self.display_info:sub(1, led_num - 1) .. show_data .. self.display_info:sub(led_num + 1, -1)
    local ok, err = pcall(function()
        self.led_disp_ctrl[led_tube_switch[led_num]] = LED_TUBE_SHOW_DATA[show_data]
    end)
    if not ok then
        log:debug('[ledtube] dispaly control fail, error: %s', err)
    end
    return ok
end

-- 设置全部led指示灯
function led_tube_object:set_all_tube_value(led_data)
    if not self:is_support_led_tube() then
        log:debug('[ledtube] led tube is not supported')
        return
    end
    if #led_data ~= LED_TUBE_MAX_NUM then
        log:error('[ledtube] the data length should be %d', LED_TUBE_MAX_NUM)
        return
    end

    local light_cnt = 0
    local co = coroutine.running()
    local deal_light_res = function ()
        light_cnt = light_cnt + 1
        if light_cnt == LED_TUBE_MAX_NUM then
            skynet.wakeup(co)
        end
    end
    for i = 1, LED_TUBE_MAX_NUM do
        skynet.fork(function()
            self:set_single_tube_value(i, led_data:sub(i, i))
            deal_light_res()
        end)
    end
    skynet.wait(co)
end

function led_tube_object:get_display_info()
    return self.display_info
end

return led_tube_object
