-- Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
-- 
-- this file licensed under the 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 skynet = require 'skynet'
local log = require 'mc.logging'
local class = require 'mc.class'
local Singleton = require 'mc.singleton'
local cooling_device_base = require 'basic_cooling.cooling_device.base'
local cooling_enums = require 'basic_cooling.define.cooling_enums'
local cooling_fans = class(cooling_device_base)

local FAN_OBJ_ADD_TIMEOUT_TIMES <const> = 30 -- 风扇对象添加超时次数，累计时间为600s
local MAX_HARDWARE_PWM = 255
local MAX_LEVEL = 100
function cooling_fans:init()
    self.super.init(self)
    self.syn_id = 'FanId'
    self.interface = 'bmc.kepler.Systems.CoolingFan'
    self.class_name = 'CoolingFan'
    self.pwm_name = 'HardwarePWM'

    skynet.fork_once(function()
        for i = 1, FAN_OBJ_ADD_TIMEOUT_TIMES, 1 do
            -- 如果风扇对象添加完成直接退出
            if self.obj_add_complete_flag then
                log:notice('Fan object timeout detection exit')
                break
            end
            skynet.sleep(2000)
        end
        local fan_id_string = ''
        for _, fan_obj in pairs(self.obj_table) do
            fan_id_string = fan_id_string .. ' ' .. fan_obj[self.syn_id]
        end
        if self.obj_add_complete_flag == false then
            -- 达到超时时间且风扇板分发缺失时，强制进行一次检测以启动cooling调速服务
            log:notice('Fan object timeout detection starting, expect fan board num: %s, cur fan board num: %s',
                self.board_add_complete_num, self.board_num
            )
            log:notice('%s object id identify result: %s', self.class_name, fan_id_string)
            if self.board_add_complete_num < self.board_num and self.board_add_complete_num ~= 0 then
                self:update_cooling_device_obj_identify_result()
            end
        end
    end)
end

-- 未设置过持久化的手动转速开启持久化的手动模式
function cooling_fans:set_all_cooling_device_manual_level_init(ctrl_mode_persist_type)
    for _, obj in pairs(self.objs) do
        obj.Level = (obj.HardwarePWM + 0.5) * MAX_LEVEL // MAX_HARDWARE_PWM
        if ctrl_mode_persist_type == cooling_enums.persist_type.ResetPer then
            obj.ManualSpeedPercentResetPersist = (obj.HardwarePWM + 0.5) * MAX_LEVEL // MAX_HARDWARE_PWM
        elseif ctrl_mode_persist_type == cooling_enums.persist_type.PoweroffPer then
            obj.ManualSpeedPercentPoweroffPersist = (obj.HardwarePWM + 0.5) * MAX_LEVEL // MAX_HARDWARE_PWM 
        end
    end
end

-- 组件启动时设置所有风扇的手动转速
function cooling_fans:set_all_cooling_device_manual_level_persist_start(ctrl_mode, level, ctrl_mode_persist_type)
    if ctrl_mode == cooling_enums.modes.Auto then
        for _, obj in pairs(self.objs) do
            obj.Level = level
        end
        return
    end
    if ctrl_mode_persist_type == cooling_enums.persist_type.ResetPer then
        for _, obj in pairs(self.objs) do
            obj.Level = obj.ManualSpeedPercentResetPersist
        end
    elseif ctrl_mode_persist_type == cooling_enums.persist_type.PoweroffPer then
        for _, obj in pairs(self.objs) do
            obj.Level = obj.ManualSpeedPercentPoweroffPersist
        end
    end
end

--设置所有风扇的手动转速
function cooling_fans:set_all_cooling_device_manual_level_persist(level, ctrl_mode_persist_type)
    for _, obj in pairs(self.objs) do
        obj.Level = level
        if ctrl_mode_persist_type == cooling_enums.persist_type.ResetPer then
            obj.ManualSpeedPercentResetPersist = level
        elseif ctrl_mode_persist_type == cooling_enums.persist_type.PoweroffPer then
            obj.ManualSpeedPercentPoweroffPersist = level
        end
    end
end

-- 设置单个风扇的手动转速
function cooling_fans:set_single_cooling_device_manual_level(id, level, ctrl_mode_persist_type)
    if not self.objs[id] then
        log:error("The %s whose id %s does not exist", self.class_name, id)
        return false
    end
    self.objs[id].Level = level
    if ctrl_mode_persist_type == cooling_enums.persist_type.ResetPer then
        self.objs[id].ManualSpeedPercentResetPersist = level
    elseif ctrl_mode_persist_type == cooling_enums.persist_type.PoweroffPer then
        self.objs[id].ManualSpeedPercentPoweroffPersist = level
    end
    return true
end

return Singleton(cooling_fans)