-- 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 bios_enum = require 'bios.types.enums'
local singleton = require 'mc.singleton'
local bs_util = require 'util.base_util'
local prop_def = require "macros.property_def"
local log = require 'mc.logging'
local bios_object = {}
bios_object.__index = bios_object

local bios_obj = {
    SystemId = 0x1,
    PasswordInitialized = 0x0,
    SystemStartupState = bios_enum.BiosStartupState.BIOS_STARTUP_STATE_OFF:value(),
    Version = "",
    BackupVersion = "",
    CurrentValueFileName = "/data/opt/currentvalue.json",
    ResultFileName = "/data/opt/result.json",
    SettingFileName = "/data/opt/setting.json",
    RegistryFileName = "/data/opt/registry.json",
    MenuData = "",
    MenuChangeFlag = 0,
    RegistryVersion = "V0.00",
    DEMTConfig = 0,
    BiosBootStage = 0,
    BiosLogPrintEnabled = 0,
    OCPCardBDF = '',
    PcieCardBDF = '',
    PcieDiskBDF = ''
}

local common_obj = {
    bios_id = 0x0,
    manu_id = 0xDB0700,
    OldSetupPassword = '',
    NewSetupPassword = '',
    UserOldSetupPassword = '',
    UserNewSetupPassword = '',
    BiosJsonFlag = 1,
    SecureBootNewFile =
        prop_def.BIOS_CONFIG_PATH .. '/' .. prop_def.NEW_SECUREBOOT_FILE,
    SecureBootCurrentFile =
        prop_def.BIOS_CONFIG_PATH .. '/' .. prop_def.CURRENT_SECUREBOOT_FILE,
    CMESFileName =
        prop_def.BIOS_CONFIG_PATH .. '/' .. prop_def.CMES_DAT,
    PsuInfoFileName =
        prop_def.BIOS_CONFIG_PATH .. '/' .. prop_def.PSU_INFO
}

local function init_prop(obj, bios_db_obj)
    obj.Version = bios_db_obj.Version
    obj.BackupVersion = bios_db_obj.BackupVersion
    obj.CurrentValueFileName = bios_obj.CurrentValueFileName
    obj.ResultFileName = bios_obj.ResultFileName
    obj.SettingFileName = bios_obj.SettingFileName
    obj.RegistryFileName = bios_obj.RegistryFileName
    obj.MenuData = bios_obj.MenuData
    obj.MenuChangeFlag = bios_obj.MenuChangeFlag
    obj.RegistryVersion = bios_db_obj.RegistryVersion
    obj.DEMTConfig = bios_obj.DEMTConfig
    if bios_db_obj.RecoverFailed then
        obj.RecoverFailed = bios_db_obj.RecoverFailed
    end
    if bios_db_obj.UpgradeFailed then
        obj.UpgradeFailed = bios_db_obj.UpgradeFailed
    end

    if bios_db_obj.TeeOSVersion then
        obj.TeeOSVersion = bios_db_obj.TeeOSVersion
    end

    if bios_db_obj.SystemStartupState and bios_db_obj.BiosBootStage then
        obj.SystemStartupState = bios_db_obj.SystemStartupState
        obj.BiosBootStage = bios_db_obj.BiosBootStage
    end

    common_obj.OldSetupPassword = bios_db_obj.OldSetupPassword
    common_obj.NewSetupPassword = bios_db_obj.NewSetupPassword
    common_obj.UserOldSetupPassword = bios_db_obj.UserOldSetupPassword
    common_obj.UserNewSetupPassword = bios_db_obj.UserNewSetupPassword
end

function bios_object.new(bios_db_obj)
    return setmetatable({obj = bios_obj, bios_db_obj = bios_db_obj}, bios_object)
end

function bios_object.new_for_csr(obj, bios_db_obj)
    init_prop(obj, bios_db_obj)
    return setmetatable({obj = obj, bios_db_obj = bios_db_obj}, bios_object)
end

function bios_object:get_bios_obj()
    return self.obj
end

function bios_object:update_bios_startup_state(state)
    self.obj.SystemStartupState = state:value()
end

function bios_object:get_bios_version()
    return self.obj.Version
end

function bios_object:get_bios_backup_version()
    return self.obj.BackupVersion
end

function bios_object:update_bios_backup_version(version)
    self.bios_db_obj.BackupVersion = version
    self.bios_db_obj:save()
    self.obj.BackupVersion = version
end

function bios_object.get_bios_id()
    return common_obj.bios_id
end

function bios_object.get_manu_id()
    return common_obj.manu_id
end

local function get_valid_version(version)
    local valid_version = ''
    for name in string.gmatch(version, '[^%z]') do
        valid_version = valid_version .. name
    end
    return valid_version
end

function bios_object:set_bios_version(version)
    local valid_version = get_valid_version(version)
    self.bios_db_obj.Version = valid_version
    self.bios_db_obj:save()
    self.obj.Version = valid_version
end

function bios_object:set_teeos_version(version)
    local valid_version = get_valid_version(version)
    self:set_prop('TeeOSVersion', valid_version)
end

function bios_object:get_current_value_file_name()
    return self.obj.CurrentValueFileName
end

local print_flag_tbl<const> = {
    ["Debug"] = prop_def.ENABLED,
    ["Disabled"] = prop_def.DISABLED
}

function bios_object:set_print_flag(flag)
    local print_flag = print_flag_tbl[flag]
    if print_flag == nil then
        print_flag = 0
    end
    if self.obj.BiosLogPrintEnabled then
        self.obj.BiosLogPrintEnabled = print_flag
        bios_obj.BiosLogPrintEnabled = print_flag
    end
end

function bios_object:set_private_prop(prop, value)
    if not common_obj[prop] then
        return false
    end
    common_obj[prop] = value
    if self.bios_db_obj[prop] then
        self.bios_db_obj[prop] = value
        self.bios_db_obj:save()
    end
    return true
end

function bios_object:set_public_prop(prop, value)
    if not self.obj[prop] then
        return false
    end
    self.obj[prop] = value
    if self.bios_db_obj[prop] ~= nil then
        self.bios_db_obj[prop] = value
        self.bios_db_obj:save()
    end
    return true
end

function bios_object:set_prop(prop, value)
    if self:set_private_prop(prop, value) then
        return true
    end
    if self:set_public_prop(prop, value) then
        return true
    end
    return false
end

function bios_object:get_prop(prop)
    local private_prop = common_obj[prop]
    if private_prop then
        return private_prop
    end
    return self.obj[prop]
end

return singleton(bios_object)