/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "view_abstract.h"

#include <regex>

#include "cj_lambda.h"

#include "base/geometry/calc_dimension.h"
#include "base/geometry/dimension.h"
#include "core/components_ng/base/view_abstract.h"
#include "core/components_ng/base/view_abstract_model.h"
#include "core/components_ng/base/view_stack_processor.h"
#include "core/components_v2/extensions/events/on_area_change_extension.h"
#include "core/gestures/long_press_gesture.h"
#include "core/pipeline/base/constants.h"

using namespace OHOS::Ace;
using namespace OHOS::Ace::Framework;

namespace OHOS::Ace::Framework {
namespace {
const char DEFAULT_HAR_BUNDLE_NAME[] = "__harDefaultBundleName__";
const char DEFAULT_HAR_MODULE_NAME[] = "__harDefaultModuleName__";
const std::regex RESOURCE_APP_STRING_PLACEHOLDER(R"(\%((\d+)(\$)){0,1}([dsf]))", std::regex::icase);
const std::regex FLOAT_PATTERN(R"(-?(0|[1-9]\d*)(\.\d+))", std::regex::icase);
const std::string RESOURCE_TOKEN_PATTERN = "(app|sys|\\[.+?\\])\\.(\\S+?)\\.(\\S+)";
const std::string RESOURCE_NAME_PATTERN = "\\[(.+?)\\]";
constexpr int32_t UNKNOWN_RESOURCE_ID = -1;
constexpr int32_t UNKNOWN_RESOURCE_TYPE = -1;
constexpr uint32_t COLOR_ALPHA_OFFSET = 24;
constexpr uint32_t COLOR_ALPHA_VALUE = 0xFF000000;

uint32_t ColorAlphaAdapt(uint32_t origin)
{
    uint32_t result = origin;
    if ((origin >> COLOR_ALPHA_OFFSET) == 0) {
        result = origin | COLOR_ALPHA_VALUE;
    }
    return result;
}

std::string GetBundleNameFromContainer()
{
    auto container = Container::Current();
    CHECK_NULL_RETURN(container, "");
    return container->GetBundleName();
}

std::string GetModuleNameFromContainer()
{
    auto container = Container::Current();
    CHECK_NULL_RETURN(container, "");
    return container->GetModuleName();
}

void CompleteResourceObjectFromParams(
    int32_t resId, NativeResourceObject& obj, std::string& targetModule, ResourceType& resType, std::string& resName)
{
    auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
    if (!params->IsArray()) {
        LOGE("Resource params type error.");
        return;
    }
    if (resId != UNKNOWN_RESOURCE_ID) {
        return;
    }
    auto identityValue = params->GetArrayItem(0);
    if (!identityValue->IsString()) {
        return;
    }
    auto identity = identityValue->GetString();
    if (!ViewAbstract::ParseDollarResource(
            identity, targetModule, resType, resName, obj.type == UNKNOWN_RESOURCE_TYPE)) {
        return;
    }
    std::regex resNameRegex(RESOURCE_NAME_PATTERN);
    std::smatch resNameResults;
    if (std::regex_match(targetModule, resNameResults, resNameRegex)) {
        auto result = resNameResults[1].str();
        obj.moduleName = strdup(result.c_str());
    }
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        obj.type = static_cast<int32_t>(resType);
    }
}

std::string GetReplaceContentStr(
    int pos, const std::string& type, std::unique_ptr<JsonValue>& params, int32_t containCount)
{
    auto index = pos + containCount;
    if (index < 0) {
        return std::string();
    }
    auto item = params->GetArrayItem(index);
    if (type == "d") {
        if (item->IsNumber()) {
            return std::to_string(item->GetInt());
        }
    } else if (type == "s") {
        if (item->IsString()) {
            return item->GetString();
        }
    } else if (type == "f") {
        if (item->IsNumber()) {
            return std::to_string(item->GetDouble());
        }
    }
    return std::string();
}

void ReplaceHolder(std::string& originStr, std::unique_ptr<JsonValue>& params, int32_t containCount)
{
    auto size = params->GetArraySize();
    if (containCount == size) {
        return;
    }
    std::string::const_iterator start = originStr.begin();
    std::string::const_iterator end = originStr.end();
    std::smatch matches;
    bool shortHolderType = false;
    bool firstMatch = true;
    int searchTime = 0;
    while (std::regex_search(start, end, matches, RESOURCE_APP_STRING_PLACEHOLDER)) {
        std::string pos = matches[2];
        std::string type = matches[4];
        if (firstMatch) {
            firstMatch = false;
            shortHolderType = pos.length() == 0;
        } else {
            if (shortHolderType ^ (pos.length() == 0)) {
                return;
            }
        }

        std::string replaceContentStr;
        if (shortHolderType) {
            replaceContentStr = GetReplaceContentStr(searchTime, type, params, containCount);
        } else {
            replaceContentStr = GetReplaceContentStr(StringUtils::StringToInt(pos) - 1, type, params, containCount);
        }

        originStr.replace(matches[0].first - originStr.begin(), matches[0].length(), replaceContentStr);
        start = originStr.begin() + matches.prefix().length() + replaceContentStr.length();
        end = originStr.end();
        searchTime++;
    }
}
} // namespace

RefPtr<ResourceObject> GetResourceObject(const NativeResourceObject& obj)
{
    auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
    if (!params->IsArray()) {
        return nullptr;
    }
    std::vector<ResourceObjectParams> resObjParamsList;
    auto size = params->GetArraySize();
    for (int32_t i = 0; i < size; i++) {
        auto item = params->GetArrayItem(i);
        ResourceObjectParams resObjParams {};
        if (item->IsString()) {
            resObjParams.value = item->GetString();
            resObjParams.type = ResourceObjectParamType::STRING;
        } else if (item->IsNumber()) {
            if (std::regex_match(std::to_string(item->GetDouble()), FLOAT_PATTERN)) {
                resObjParams.value = std::to_string(item->GetDouble());
                resObjParams.type = ResourceObjectParamType::FLOAT;
            } else {
                resObjParams.value = std::to_string(item->GetInt());
                resObjParams.type = ResourceObjectParamType::INT;
            }
        }
        resObjParamsList.push_back(resObjParams);
    }
    auto resourceObject = AceType::MakeRefPtr<ResourceObject>(
        obj.id, obj.type, resObjParamsList, obj.bundleName, obj.moduleName, Container::CurrentIdSafely());
    return resourceObject;
}

RefPtr<ResourceObject> GetResourceObjectByBundleAndModule(const NativeResourceObject& obj)
{
    auto resourceObject =
        AceType::MakeRefPtr<ResourceObject>(obj.bundleName, obj.moduleName, Container::CurrentIdSafely());
    return resourceObject;
}

RefPtr<ResourceWrapper> CreateResourceWrapper(const NativeResourceObject& obj, RefPtr<ResourceObject>& resourceObject)
{
    RefPtr<ResourceAdapter> resourceAdapter = nullptr;
    RefPtr<ThemeConstants> themeConstants = nullptr;
    if (SystemProperties::GetResourceDecoupling()) {
        resourceAdapter = ResourceManager::GetInstance().GetOrCreateResourceAdapter(resourceObject);
        if (!resourceAdapter) {
            return nullptr;
        }
    } else {
        CHECK_NULL_RETURN(obj.moduleName, nullptr);
        themeConstants = ViewAbstract::GetThemeConstants(obj.bundleName, obj.moduleName);
        if (!themeConstants) {
            return nullptr;
        }
    }
    auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
    return resourceWrapper;
}

RefPtr<ResourceWrapper> CreateResourceWrapper()
{
    RefPtr<ResourceAdapter> resourceAdapter = nullptr;
    RefPtr<ThemeConstants> themeConstants = nullptr;
    if (SystemProperties::GetResourceDecoupling()) {
        resourceAdapter = ResourceManager::GetInstance().GetResourceAdapter(Container::CurrentIdSafely());
        if (!resourceAdapter) {
            return nullptr;
        }
    } else {
        themeConstants = ViewAbstract::GetThemeConstants();
        if (!themeConstants) {
            return nullptr;
        }
    }
    auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
    return resourceWrapper;
}

RefPtr<ThemeConstants> ViewAbstract::GetThemeConstants(const std::string& bundleName, const std::string& moduleName)
{
    auto currentObj = Container::Current();
    if (!currentObj) {
        LOGW("container is null");
        return nullptr;
    }
    auto pipelineContext = currentObj->GetPipelineContext();
    if (!pipelineContext) {
        LOGE("pipeline context is null!");
        return nullptr;
    }
    auto themeManager = pipelineContext->GetThemeManager();
    if (!themeManager) {
        LOGE("theme manager is null!");
        return nullptr;
    }
    return themeManager->GetThemeConstants(bundleName, moduleName);
}

void ViewAbstract::CjEnabled(bool enabled)
{
    ViewAbstractModel::GetInstance()->SetEnabled(enabled);
}

void ViewAbstract::CompleteResourceObject(NativeResourceObject& obj, std::string& bundleName, std::string& moduleName)
{
    int32_t resId = UNKNOWN_RESOURCE_ID;
    CompleteResourceObjectInner(obj, bundleName, moduleName, resId);
}

void ViewAbstract::CompleteResourceObjectWithBundleName(
    NativeResourceObject& obj, std::string& bundleName, std::string& moduleName, int32_t& resId)
{
    CompleteResourceObjectInner(obj, bundleName, moduleName, resId);
}

void ViewAbstract::CompleteResourceObjectInner(
    NativeResourceObject& obj, std::string& bundleName, std::string& moduleName, int32_t& resIdValue)
{
    ResourceType resType;
    std::string targetModule;
    std::string resName;
    resIdValue = obj.id;
    if (resIdValue == UNKNOWN_RESOURCE_ID) {
        CompleteResourceObjectFromParams(resIdValue, obj, targetModule, resType, resName);
    }
    bundleName = obj.bundleName;
    if (obj.moduleName) {
        moduleName = obj.moduleName;
    }

    if ((bundleName.empty() && !moduleName.empty()) || bundleName == DEFAULT_HAR_BUNDLE_NAME) {
        bundleName = GetBundleNameFromContainer();
        obj.bundleName = bundleName.c_str();
    }
    if (moduleName == DEFAULT_HAR_MODULE_NAME) {
        moduleName = GetModuleNameFromContainer();
        obj.moduleName = moduleName.c_str();
    }
}

bool ViewAbstract::ConvertResourceType(const std::string& typeName, ResourceType& resType)
{
    static const std::unordered_map<std::string, ResourceType> resTypeMap {
        { "color", ResourceType::COLOR },
        { "media", ResourceType::MEDIA },
        { "float", ResourceType::FLOAT },
        { "string", ResourceType::STRING },
        { "plural", ResourceType::PLURAL },
        { "pattern", ResourceType::PATTERN },
        { "boolean", ResourceType::BOOLEAN },
        { "integer", ResourceType::INTEGER },
        { "strarray", ResourceType::STRARRAY },
        { "intarray", ResourceType::INTARRAY },
        { "symbol", ResourceType::SYMBOL },
    };
    auto it = resTypeMap.find(typeName);
    if (it == resTypeMap.end()) {
        return false;
    }
    resType = it->second;
    return true;
}

bool ViewAbstract::ParseDollarResource(const std::string& resPath, std::string& targetModule, ResourceType& resType,
    std::string& resName, bool isParseType)
{
    std::smatch results;
    std::regex tokenRegex(RESOURCE_TOKEN_PATTERN);
    if (!std::regex_match(resPath, results, tokenRegex)) {
        return false;
    }
    targetModule = results[1];
    std::string typeName = results[2];
    if (isParseType && !ConvertResourceType(typeName, resType)) {
        return false;
    }
    resName = resPath;
    return true;
}

bool ViewAbstract::ParseCjString(NativeResourceObject& obj, std::string& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
    if (!params->IsArray()) {
        LOGE("Resource params type error.");
        return false;
    }
    if (obj.id == UNKNOWN_RESOURCE_ID) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
            auto originStr = resourceWrapper->GetStringByName(param->GetString());
            ReplaceHolder(originStr, params, 1);
            result = originStr;
        } else if (obj.type == static_cast<int32_t>(ResourceType::PLURAL)) {
            auto countVal = params->GetArrayItem(1);
            if (!countVal->IsNumber()) {
                return false;
            }
            int count = countVal->GetInt();
            auto pluralStr = resourceWrapper->GetPluralStringByName(param->GetString(), count);
            // cangjie remains consistent with arkts
            ReplaceHolder(pluralStr, params, 2);
            result = pluralStr;
        } else {
            return false;
        }
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
        auto originStr = resourceWrapper->GetString(static_cast<uint32_t>(obj.id));
        ReplaceHolder(originStr, params, 0);
        result = originStr;
    } else if (obj.type == static_cast<int32_t>(ResourceType::PLURAL)) {
        auto countVal = params->GetArrayItem(0);
        if (!countVal->IsNumber()) {
            return false;
        }
        int count = countVal->GetInt();
        auto pluralStr = resourceWrapper->GetPluralString(static_cast<uint32_t>(obj.id), count);
        ReplaceHolder(pluralStr, params, 1);
        result = pluralStr;
    } else if (obj.type == static_cast<int32_t>(ResourceType::FLOAT)) {
        result = std::to_string(resourceWrapper->GetDouble(static_cast<uint32_t>(obj.id)));
    } else if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
        result = std::to_string(resourceWrapper->GetInt(static_cast<uint32_t>(obj.id)));
    } else {
        return false;
    }
    return true;
}

bool ViewAbstract::ParseCjMedia(NativeResourceObject& obj, std::string& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    return ParseCjMediaInternal(obj, result);
}

bool ViewAbstract::ParseCjMediaInternal(NativeResourceObject& obj, std::string& result)
{
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::RAWFILE)) {
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (!param->IsString()) {
            return false;
        }
        auto fileName = param->GetString();
        result = resourceWrapper->GetRawfile(fileName);
        return true;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::MEDIA)) {
            result = resourceWrapper->GetMediaPathByName(param->GetString());
            return true;
        }
        if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
            result = resourceWrapper->GetStringByName(param->GetString());
            return true;
        }
        return false;
    } else if (obj.type == static_cast<int32_t>(ResourceType::MEDIA)) {
        result = resourceWrapper->GetMediaPath(static_cast<uint32_t>(obj.id));
        return true;
    } else if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
        result = resourceWrapper->GetString(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjSymbolId(NativeResourceObject& obj, uint32_t& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        auto symbol = resourceWrapper->GetSymbolByName(param->GetString().c_str());
        if (!symbol) {
            return false;
        }
        result = symbol;
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::SYMBOL)) {
        result = resourceWrapper->GetSymbolById(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjColor(NativeResourceObject& obj, Color& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        result = resourceWrapper->GetColorByName(param->GetString());
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
        auto value = resourceWrapper->GetString(static_cast<uint32_t>(obj.id));
        return Color::ParseColorString(value, result);
    }
    if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
        auto value = resourceWrapper->GetInt(static_cast<uint32_t>(obj.id));
        result = Color(ColorAlphaAdapt(value));
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::COLOR)) {
        result = resourceWrapper->GetColor(static_cast<uint32_t>(obj.id));
        result.SetResourceId(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjDimension(
    NativeResourceObject& obj, CalcDimension& result, DimensionUnit defaultUnit, bool isSupportPercent)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
            auto value = resourceWrapper->GetStringByName(param->GetString());
            return StringUtils::StringToCalcDimensionNG(value, result, false, defaultUnit);
        }
        if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
            auto value = std::to_string(resourceWrapper->GetIntByName(param->GetString()));
            return StringUtils::StringToDimensionWithUnitNG(value, result, defaultUnit);
        }
        result = resourceWrapper->GetDimensionByName(param->GetString());
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
        auto value = resourceWrapper->GetString(static_cast<uint32_t>(obj.id));
        return StringUtils::StringToCalcDimensionNG(value, result, false, defaultUnit);
    }
    if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
        auto value = std::to_string(resourceWrapper->GetInt(static_cast<uint32_t>(obj.id)));
        return StringUtils::StringToDimensionWithUnitNG(value, result, defaultUnit);
    }
    if (obj.type == static_cast<int32_t>(ResourceType::FLOAT)) {
        result = resourceWrapper->GetDimension(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjDimensionVP(NativeResourceObject& obj, CalcDimension& result, bool isSupportPercent)
{
    return ParseCjDimension(obj, result, DimensionUnit::VP, isSupportPercent);
}

bool ViewAbstract::ParseCjDimensionFP(NativeResourceObject& obj, CalcDimension& result, bool isSupportPercent)
{
    return ParseCjDimension(obj, result, DimensionUnit::FP, isSupportPercent);
}

bool ViewAbstract::ParseCjDouble(NativeResourceObject& obj, double& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
            auto value = resourceWrapper->GetStringByName(param->GetString());
            return StringUtils::StringToDouble(value, result);
        }
        if (obj.type == static_cast<int32_t>(ResourceType::FLOAT)) {
            result = resourceWrapper->GetDoubleByName(param->GetString());
            return true;
        }
        if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
            result = resourceWrapper->GetIntByName(param->GetString());
            return true;
        }
        return false;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::STRING)) {
        auto value = resourceWrapper->GetString(static_cast<uint32_t>(obj.id));
        return StringUtils::StringToDouble(value, result);
    }
    if (obj.type == static_cast<int32_t>(ResourceType::FLOAT)) {
        result = resourceWrapper->GetDouble(static_cast<uint32_t>(obj.id));
        return true;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::INTEGER)) {
        result = resourceWrapper->GetInt(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjInteger(NativeResourceObject& obj, int32_t& result)
{
    return ParseCjInteger<int32_t>(obj, result);
}

bool ViewAbstract::ParseCjInteger(NativeResourceObject& obj, uint32_t& result)
{
    return ParseCjInteger<uint32_t>(obj, result);
}

bool ViewAbstract::ParseCjBool(NativeResourceObject& obj, bool& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::BOOLEAN)) {
            result = resourceWrapper->GetBooleanByName(param->GetString());
            return true;
        }
        return false;
    }

    if (obj.type == static_cast<int32_t>(ResourceType::BOOLEAN)) {
        result = resourceWrapper->GetBoolean(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjIntegerArray(NativeResourceObject& obj, std::vector<uint32_t>& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::INTARRAY)) {
            result = resourceWrapper->GetIntArrayByName(param->GetString());
            return true;
        }
        return false;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::INTARRAY)) {
        result = resourceWrapper->GetIntArray(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

bool ViewAbstract::ParseCjStringArray(NativeResourceObject& obj, std::vector<std::string>& result)
{
    std::string bundleName;
    std::string moduleName;
    CompleteResourceObject(obj, bundleName, moduleName);
    if (obj.type == UNKNOWN_RESOURCE_TYPE) {
        return false;
    }
    auto resourceObject = GetResourceObjectByBundleAndModule(obj);
    auto resourceWrapper = CreateResourceWrapper(obj, resourceObject);
    if (!resourceWrapper) {
        return false;
    }
    if (obj.id == -1) {
        if (!obj.paramsJsonStr) {
            return false;
        }
        auto params = JsonUtil::ParseJsonString(obj.paramsJsonStr);
        if (!params->IsArray()) {
            return false;
        }
        auto param = params->GetArrayItem(0);
        if (obj.type == static_cast<int32_t>(ResourceType::STRARRAY)) {
            result = resourceWrapper->GetStringArrayByName(param->GetString());
            return true;
        }
        return false;
    }
    if (obj.type == static_cast<int32_t>(ResourceType::STRARRAY)) {
        result = resourceWrapper->GetStringArray(static_cast<uint32_t>(obj.id));
        return true;
    }
    return false;
}

void ViewAbstract::ParseOnCreateMenu(CjOnCreateMenu& cjOnCreateMenu, NG::OnCreateMenuCallback& onCreateMenuCallback)
{
    WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
    auto cjCallback = [func = CJLambda::Create(cjOnCreateMenu), node = frameNode, instanceId = Container::CurrentId()](
                          const std::vector<NG::MenuItemParam>& systemMenuItems) -> std::vector<NG::MenuOptionsParam> {
        ContainerScope scope(instanceId);
        auto pipelineContext = PipelineContext::GetCurrentContext();
        std::vector<NG::MenuOptionsParam> menuParams;
        CHECK_NULL_RETURN(pipelineContext, menuParams);
        pipelineContext->UpdateCurrentActiveNode(node);
        auto cjMenuItems = new std::vector<FfiTextMenuItem>(systemMenuItems.size());
        for (size_t i = 0; i < systemMenuItems.size(); i++) {
            FfiTextMenuItem item;
            auto content = systemMenuItems[i].menuOptionsParam.content;
            auto icon = systemMenuItems[i].menuOptionsParam.icon;
            item.content = content.has_value() ? Utils::MallocCString(content.value()) : Utils::MallocCString("");
            item.icon = icon.has_value() ? Utils::MallocCString(icon.value()) : Utils::MallocCString("");
            item.id = Utils::MallocCString(systemMenuItems[i].menuOptionsParam.id);
            (*cjMenuItems)[i] = item;
        }
        auto vectorResult = func(cjMenuItems);
        auto menuItemsArray = reinterpret_cast<std::vector<FfiTextMenuItem>*>(vectorResult);
        for (size_t i = 0; i < menuItemsArray->size(); i++) {
            auto ffiMenuItem = (*menuItemsArray)[i];
            NG::MenuOptionsParam menuOptionsParam;
            menuOptionsParam.content =
                ffiMenuItem.content.value ? std::make_optional(ffiMenuItem.content.value) : std::nullopt;
            menuOptionsParam.icon = ffiMenuItem.icon.value ? std::make_optional(ffiMenuItem.icon.value) : std::nullopt;
            menuOptionsParam.id = ffiMenuItem.id.value;
            menuParams.emplace_back(menuOptionsParam);
        }
        delete menuItemsArray;
        return menuParams;
    };
    onCreateMenuCallback = cjCallback;
}

void ViewAbstract::ParseOnMenuItemClick(
    CjOnMenuItemClick& cjOnMenuItemClick, NG::OnMenuItemClickCallback& onMenuItemClick)
{
    WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
    auto cjCallback = [func = CJLambda::Create(cjOnMenuItemClick), node = frameNode,
                          instanceId = Container::CurrentId()](NG::MenuItemParam menuOptionsParam) -> bool {
        ContainerScope scope(instanceId);
        auto pipelineContext = PipelineContext::GetCurrentContext();
        CHECK_NULL_RETURN(pipelineContext, false);
        pipelineContext->UpdateCurrentActiveNode(node);
        auto content = menuOptionsParam.menuOptionsParam.content;
        auto icon = menuOptionsParam.menuOptionsParam.icon;
        FfiTextMenuItem ffiTextMenuItem;
        ffiTextMenuItem.content =
            content.has_value() ? Utils::MallocCString(content.value()) : Utils::MallocCString("");
        ffiTextMenuItem.icon = icon.has_value() ? Utils::MallocCString(icon.value()) : Utils::MallocCString("");
        ffiTextMenuItem.id = Utils::MallocCString(menuOptionsParam.menuOptionsParam.id);
        return func(ffiTextMenuItem, menuOptionsParam.start, menuOptionsParam.end);
    };
    onMenuItemClick = cjCallback;
}

bool ViewAbstract::ParseEditMenuOptions(CjOnCreateMenu& cjOnCreateMenu, CjOnMenuItemClick& cjOnMenuItemClick,
    NG::OnCreateMenuCallback& onCreateMenuCallback, NG::OnMenuItemClickCallback& onMenuItemClick)
{
    ParseOnCreateMenu(cjOnCreateMenu, onCreateMenuCallback);
    ParseOnMenuItemClick(cjOnMenuItemClick, onMenuItemClick);
    return true;
}
} // namespace OHOS::Ace::Framework