-- 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 c_object = require 'mc.orm.object'
local sml = require 'sml'
local signal = require 'mc.signal'
local ctrl_commu_loss_monitor = require 'ctrl_commu_loss_monitor'
local array_dump = require 'array.array_dump'
local common_def = require 'common_def'
local log = require 'mc.logging'

local function make_array_key(controller_id, array_id)
    return string.format('%d:%d', controller_id, array_id)
end

---@class c_array: c_object
---@field Id integer
---@field UsedSpaceMiB integer
---@field TotalFreeSpaceMiB integer
---@field FreeBlocksSpaceMiB integer[]
---@field RefVolumes integer[]
---@field RefDrives string[]
---@field RefPDSlots integer[]
---@field RefPDEnclosures integer[]
---@field RefControllerId integer
---@field new fun(...): c_array
local c_array = c_object('DiskArray')   -- DiskArray 类，主键是 key 字段

local TASK_UPDATE <const> = 'update'

function c_array:ctor(obj, position)
    self.obj = obj
    self.RefController = position
    self.key = make_array_key(self.RefController, self.obj.Id)
    self.RefPDSlots = {}
    self.RefPDEnclosures = {}
    self.on_update = signal.new()
    self.on_update_ref_drives = signal.new()
end

function c_array:init()
    c_array.super.init(self)
    self:set_default_values()
    self.on_update:on(function(info)
        self:update_array_info(info)
    end)
end

-- array会被删除，所以不需要enbale_request限制
function c_array:get_array_info()
    local ok, ret = pcall(sml.get_ctrl_init_state, self.RefControllerId)
    if not ok or ret ~= 2 then
        return
    end
    ok, ret = pcall(sml.get_array_info, self.RefControllerId, self.Id)
    if not ok then
        if ret ~= common_def.SML_ERR_CTRL_STATUS_INVALID and ret ~= common_def.SML_ERR_NULL_INFTERFACE then
            ctrl_commu_loss_monitor.get_instance():update(true, self.RefControllerId)
        end
        return
    end
    ctrl_commu_loss_monitor.get_instance():update(false, self.RefControllerId)
    self.on_update:emit(ret)
end

---@param info c_array_info
function c_array:update_array_info(info)
    self.UsedSpaceMiB = info.used_space
    self.TotalFreeSpaceMiB = info.total_free_space
    self.FreeBlocksSpaceMiB = info.free_blocks_space
    self.RefVolumes = info.ld_ids
    self.RefPDSlots = info.pd_slots
    self.RefPDEnclosures = info.pd_enclosures
    self.on_update_ref_drives:emit(self)
end

function c_array:set_default_values()
    self.UsedSpaceMiB = common_def.INVALID_U32
    self.TotalFreeSpaceMiB = common_def.INVALID_U32
    self.FreeBlocksSpaceMiB = {}
    self.RefVolumes = {}
    self.RefPDSlots = {}
    self.RefPDEnclosures = {}
    self.RefDrives = {}
end

function c_array:dump_info(fp_w)
    array_dump.get_instance():dump_info(fp_w, self)
end

return c_array
