-- 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 singleton = require 'mc.singleton'
local c_super_pod_label_object = require 'super_pod_label_object'
local class = require 'mc.class'
local c_object = require 'mc.orm.object'
local custom_messages = require 'messages.custom'
local log = require 'mc.logging'
local ipmi_msg = require 'chassis.ipmi.ipmi_message'
local ipmi = require 'mc.ipmi'
local cc = ipmi.types.Cc
local bs = require 'mc.bitstring'
local MIN_SUPERPOD_SIZE<const> = 1
local MAX_SUPERPOD_SIZE<const> = 384

local c_super_pod_label_collection = class()

function c_super_pod_label_collection:ctor()
end

function c_super_pod_label_collection:SetSuperPodId(ctx, SuperPodId)
    local super_pod_label_object = c_object('SuperPodLabel').collection:find({Id = 1})
    if not super_pod_label_object then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodId(%d) failed', SuperPodId)
        error(custom_messages.ResourceNotFound('SuperPodLabel'))
    end
    local res = super_pod_label_object:update_super_pod_id(SuperPodId)
    if not res then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodId(%d) failed', SuperPodId)
        error(custom_messages.ResourceNotFound('SuperPodId'))
    end
    log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodId(%d) successfully', SuperPodId)
    return true
end

function c_super_pod_label_collection:SetServerIndex(ctx, ServerIndex)
    local super_pod_label_object = c_object('SuperPodLabel').collection:find({Id = 1})
    if not super_pod_label_object then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set ServerIndex(%d) failed', ServerIndex)
        error(custom_messages.ResourceNotFound('SuperPodLabel'))
    end
    local res = super_pod_label_object:update_server_index(ServerIndex)
    if not res then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set ServerIndex(%d) failed', ServerIndex)
        error(custom_messages.ResourceNotFound('ServerIndex'))
    end
    log:operation(ctx:get_initiator(), 'Chassis', 'Set ServerIndex(%d) successfully', ServerIndex)
    return true
end

function c_super_pod_label_collection:SetSuperPodSize(ctx, SuperPodSize)
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodSize(%d) failed', SuperPodSize)
        error(custom_messages.ResourceNotFound('SuperPodLabel'))
    end

    local res = super_pod_label_object:update_super_pod_size(SuperPodSize)
    if not res then
        log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodSize(%d) failed', SuperPodSize)
        error(custom_messages.ResourceNotFound('SuperPodSize'))
    end
    log:operation(ctx:get_initiator(), 'Chassis', 'Set SuperPodSize(%d) successfully', SuperPodSize)
    return true
end

function c_super_pod_label_collection:RestoreDefaults(ctx)
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        log:operation(ctx:get_initiator(), 'Chassis', 'Restore SuperPodLabel to the default value failed')
        error(custom_messages.ResourceNotFound('SuperPodLabel'))
    end
    local res = super_pod_label_object:restore_defaults()
    if not res then
        log:operation(ctx:get_initiator(), 'Chassis', 'Restore SuperPodLabel to the default value failed')
        error(custom_messages.ResourceNotFound('SuperPodLabel'))
    end
    log:operation(ctx:get_initiator(), 'Chassis', 'Restore SuperPodLabel to the default value successfully')
    return true
end

function c_super_pod_label_collection:ipmi_get_superpod_label_info(req, ctx)
    local rsp = ipmi_msg.GetSuperPodLabelInfoRsp.new()
    rsp.ManufactureId = 0x0007db
    rsp.EndFlag = 0
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodLabel failed')
        rsp.CompletionCode = cc.DataNotAvailable
        return rsp
    end
    rsp.Data = bs.new('<<SuperPodId:4/unit:8,ServerIndex:2/unit:8,SuperPodSize:2/unit:8>>'):pack({
        SuperPodId = super_pod_label_object.SuperPodId,
        ServerIndex = super_pod_label_object.ServerIndex,
        SuperPodSize = super_pod_label_object.SuperPodSize
    })
    rsp.CompletionCode = cc.Success
    return rsp
end

function c_super_pod_label_collection:ipmi_set_superpod_label_info(req, ctx)
    local rsp = ipmi_msg.SetSuperPodLabelInfoRsp.new()
    rsp.ManufactureId = 0x0007db
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodLabel failed')
        rsp.CompletionCode = cc.DataNotAvailable
        return rsp
    end
    local super_pod_id = (req.Data:byte(4) << 24) | req.Data:byte(3) << 16 | (req.Data:byte(2) << 8) | req.Data:byte(1)
    local server_index = (req.Data:byte(6) << 8) | req.Data:byte(5)
    local super_pod_size =  (req.Data:byte(8) << 8) | req.Data:byte(7)
    if super_pod_size < MIN_SUPERPOD_SIZE or super_pod_size > MAX_SUPERPOD_SIZE then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodLabel failed')
        rsp.CompletionCode = cc.ParmOutOfRange
        return rsp
    end
    local res = super_pod_label_object:update_super_pod_id(super_pod_id)
    res = super_pod_label_object:update_server_index(server_index) and res
    res = super_pod_label_object:update_super_pod_size(super_pod_size) and res
    if not res then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodLabel failed')
        rsp.CompletionCode = cc.ResponseError
        return rsp
    end
    ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodLabel successfully')
    rsp.CompletionCode = cc.Success
    return rsp
end

function c_super_pod_label_collection:ipmi_set_super_pod_id(req, ctx)
    local rsp = ipmi_msg.SetSuperPodIdRsp.new()
    rsp.ManufactureId = 0x0007db
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodId failed')
        rsp.CompletionCode = cc.DataNotAvailable
        return rsp
    end
    local super_pod_id = (req.Data:byte(4) << 24) | req.Data:byte(3) << 16 | (req.Data:byte(2) << 8) | req.Data:byte(1)
    local res = super_pod_label_object:update_super_pod_id(super_pod_id)
    if not res then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodId failed')
        rsp.CompletionCode = cc.ResponseError
        return rsp
    end
    ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodId successfully')
    rsp.CompletionCode = cc.Success
    return rsp
end

function c_super_pod_label_collection:ipmi_set_server_index(req, ctx)
    local rsp = ipmi_msg.SetServerIndexRsp.new()
    rsp.ManufactureId = 0x0007db
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set ServerIndex failed')
        rsp.CompletionCode = cc.DataNotAvailable
        return rsp
    end
    local server_index = (req.Data:byte(2) << 8) | req.Data:byte(1)
    local res = super_pod_label_object:update_server_index(server_index)
    if not res then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set ServerIndex failed')
        rsp.CompletionCode = cc.ResponseError
        return rsp
    end
    ipmi.ipmi_operation_log(ctx, 'chassis', 'Set ServerIndex successfully')
    rsp.CompletionCode = cc.Success
    return rsp
end

function c_super_pod_label_collection:ipmi_set_super_pod_size(req, ctx)
    local rsp = ipmi_msg.SetSuperPodSizeRsp.new()
    rsp.ManufactureId = 0x0007db
    local super_pod_label_object = c_super_pod_label_object.collection:find({Id = 1})
    if not super_pod_label_object then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodSize failed')
        rsp.CompletionCode = cc.DataNotAvailable
        return rsp
    end
    local super_pod_size = (req.Data:byte(2) << 8) | req.Data:byte(1)
    local res = super_pod_label_object:update_super_pod_size(super_pod_size)
    if not res then
        ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodSize failed')
        rsp.CompletionCode = cc.ResponseError
        return rsp
    end
    ipmi.ipmi_operation_log(ctx, 'chassis', 'Set SuperPodSize successfully')
    rsp.CompletionCode = cc.Success
    return rsp
end

return singleton(c_super_pod_label_collection)
