-- 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 db_util = require "util.db_util"
local setting_service = require 'service.setting_service'
local class = require 'mc.class'
local prop_def = require 'macros.property_def'
local bs_util = require 'util.base_util'
local skynet = require 'skynet'

local RET_OK < const > = 0
local RET_ERR < const > = -1
local boot_object = class()

local function create_default_obj(boot_gen_obj)
    if boot_gen_obj then
        return boot_gen_obj
    end
    local obj = {
        BootSourceOverrideMode = '',
        BootSourceOverrideEnabled = 'Once',
        BootSourceOverrideTarget = '',
        BootOptionReference = '',
        BootOrder = '',
        BootModeSupport = true,
        BootModeIpmiSettable = true
    }
    return obj
end

-- 向前兼容，当system_id为1时，先获取Boot_1的数据，如果没有则使用Boot的数据创建新数据
local function get_boot_info_tbl(db, system_id)
    local db_id = 'Boot'
    if system_id ~= prop_def.DEFAULT_SYSTEM_ID then
        db_id = 'Boot_' .. system_id
    end
    local db_info = db:select(db.BiosBootTable)
        :where(db.BiosBootTable.Id:eq(db_id)):first()
    if db_info then
        return db_info
    end
    local new_db_info = db.BiosBootTable({Id = db_id,
        BootSourceOverrideMode = 'UEFIBoot',
        BootSourceOverrideEnabled = 'Disabled',
        BootSourceOverrideTarget = 'Hdd',
        BootModeSupport = true,
        BootModeIpmiSettable = true,
        BootOrder = '/HardDiskDrive/PXE/DVDROMDrive/Others',
        PreviousBootSourceOverrideTarget = ''})
    new_db_info:save()
    return new_db_info
end

function boot_object:ctor(obj, db, system_id)
    local db_obj = get_boot_info_tbl(db, system_id)
    obj.BootSourceOverrideMode = 'UEFI'
    -- Disabled、Once、Continuous
    obj.BootSourceOverrideEnabled = db_obj.BootSourceOverrideEnabled
    -- None、Pxe、Floppy、Cd、Hdd、BiosSetup
    obj.BootSourceOverrideTarget = db_obj.BootSourceOverrideTarget
    obj.BootOptionReference = {'None', 'Pxe', 'Floppy', 'Cd', 'Hdd', 'BiosSetup', 'Others'}
    obj.BootOrder = db_util.decode_db_info(db_obj.BootOrder, 1, true)
    obj.BootModeSupport = db_obj.BootModeSupport
    obj.BootModeIpmiSettable = db_obj.BootModeIpmiSettable
    obj.PreviousBootSourceOverrideTarget = db_obj.PreviousBootSourceOverrideTarget

    self.obj = obj
    self.system_id = system_id
    self.db_obj = db_obj
end

function boot_object:get_obj()
    return self.obj
end

function boot_object:set_prop(prop_name, prop_val)
    local obj = self.obj
    if not obj then
        return RET_ERR
    end

    if self.db_obj[prop_name] ~= nil then
        if prop_name == 'BootOrder' then
            local db_order_val = db_util.encode_db_info(prop_val, 1)
            self.db_obj[prop_name] = db_order_val
        else
            self.db_obj[prop_name] = prop_val
        end
        
        self.db_obj:save()
    end

    self.obj[prop_name] = prop_val
    return RET_OK
end

function boot_object:get_prop(prop_name)
    local obj = self.obj
    if not obj then
        return nil
    end

    return obj[prop_name]
end

function boot_object:update_order_from_file()
    log:notice('[bios]update order from file, system id is %s', self.system_id)
    local setting_ser = setting_service.new()
    setting_ser:build_with_path(bs_util.get_data_path(self.system_id, 'currentvalue.json'))
    local order_json = setting_ser:get_boot_order()
    if order_json then
        self:set_prop('BootOrder', order_json)
    end
end

function boot_object:get_dump_info()
    local props = self.obj:get_all_prop_names()
    local log_info = {}
    table.insert(log_info, '------Boot tree Begin------\r\n')
    local info
    for _, prop in pairs(props) do
        info = string.format('%s:%s', prop, bs_util.dump_prop(prop, self.obj[prop]))
        table.insert(log_info, info)
        table.insert(log_info, '\r\n')
        skynet.sleep(10)
    end
    return table.concat(log_info)
end

return boot_object