/*
 * Copyright (C) 2022-2025 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 "accessibility_event_info_parcel.h"
#include "accessibility_element_info_parcel.h"
#include "hilog_wrapper.h"
#include "parcel_util.h"

namespace OHOS {
namespace Accessibility {
AccessibilityEventInfoParcel::AccessibilityEventInfoParcel(const AccessibilityEventInfo &eventInfo)
    : AccessibilityEventInfo(eventInfo)
{
}

bool AccessibilityEventInfoParcel::ReadFromParcelFirstPart(Parcel &parcel)
{
    uint32_t eventType = TYPE_VIEW_INVALID;
    uint32_t gestureType = GESTURE_INVALID;
    int32_t triggerAction = ACCESSIBILITY_ACTION_INVALID;
    int32_t textMoveStep = STEP_CHARACTER;
    int32_t windowContentChangeTypes = CONTENT_CHANGE_TYPE_INVALID;
    int32_t windowChangeTypes = WINDOW_UPDATE_INVALID;
    int32_t category = CATEGORY_INVALID;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, eventType);
    eventType_ = static_cast<EventType>(eventType);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, gestureType);
    gestureType_ = static_cast<GestureType>(gestureType);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, bundleName_);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, triggerAction);
    triggerAction_ = static_cast<ActionType>(triggerAction);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, timeStamp_);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, textMoveStep);
    textMoveStep_ = static_cast<TextMoveUnit>(textMoveStep);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, windowContentChangeTypes);
    windowContentChangeTypes_ = static_cast<WindowsContentChangeTypes>(windowContentChangeTypes);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, windowChangeTypes);
    windowChangeTypes_ = static_cast<WindowUpdateType>(windowChangeTypes);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, category);
    category_ = static_cast<NotificationCategory>(category);
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, pageId_);
    return true;
}

bool AccessibilityEventInfoParcel::ReadFromParcelSecondPart(Parcel &parcel)
{
    int64_t componentId = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, componentId);
    SetSource(componentId);
    int32_t windowId = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, windowId);
    SetWindowId(windowId);
    int32_t currentIndex = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, currentIndex);
    SetCurrentIndex(currentIndex);
    int32_t beginIndex = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, beginIndex);
    SetBeginIndex(beginIndex);
    int32_t endIndex = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, endIndex);
    SetEndIndex(endIndex);
    int32_t contentSize = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, contentSize);
    std::string content;
    if (!ContainerSecurityVerify(parcel, contentSize, contents_.max_size())) {
        return false;
    }
    for (auto i = 0 ; i < contentSize; i++) {
        READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, content);
        AddContent(content);
    }
    std::string componentType;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, componentType);
    SetComponentType(componentType);
    std::string description;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, description);
    SetDescription(description);
    std::string beforeText;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, beforeText);
    SetBeforeText(beforeText);
    std::string latestContent;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, latestContent);
    SetLatestContent(latestContent);
    int64_t elementId = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, elementId);

    int32_t itemCounts = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, itemCounts);
    SetItemCounts(itemCounts);
    sptr<AccessibilityElementInfoParcel> elementInfoParcel =
	    parcel.ReadStrongParcelable<AccessibilityElementInfoParcel>();
    if (elementInfoParcel == nullptr) {
        HILOG_ERROR("ReadStrongParcelable elementInfo failed.");
        return false;
    }
    SetElementInfo(*elementInfoParcel);
    return true;
}

bool AccessibilityEventInfoParcel::ReadFromParcelThirdPart(Parcel &parcel)
{
    std::string textAnnouncedForAccessibility;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, textAnnouncedForAccessibility);
    SetTextAnnouncedForAccessibility(textAnnouncedForAccessibility);

    std::string inspectorKey;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, inspectorKey);
    SetInspectorKey(inspectorKey);

    int32_t requestFocusElementId = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, requestFocusElementId);
    SetRequestFocusElementId(requestFocusElementId);

    std::string bundleName;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, bundleName);
    SetResourceBundleName(bundleName);
 
    std::string moduleName;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, moduleName);
    SetResourceModuleName(moduleName);
 
    uint32_t resourceId = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, resourceId);
    SetResourceId(resourceId);

    int32_t paramsSize = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, paramsSize);
    int32_t paramsType;
    std::string params;
    if (!ContainerSecurityVerify(parcel, paramsSize, resourceParams_.max_size())) {
        return false;
    }
    for (int32_t i = 0 ; i < paramsSize; i++) {
        READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, paramsType);
        READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, params);
        resourceParams_.emplace_back(std::make_tuple(paramsType, params));
    }
    sptr<ExtraEventInfoParcel> extraEventInfo = parcel.ReadStrongParcelable<ExtraEventInfoParcel>();
    if (extraEventInfo == nullptr) {
        return false;
    }
    extraEventInfo_ = *extraEventInfo;
    return true;
}

bool AccessibilityEventInfoParcel::ReadFromParcel(Parcel &parcel)
{
    if (!ReadFromParcelFirstPart(parcel)) {
        return false;
    }
    if (!ReadFromParcelSecondPart(parcel)) {
        return false;
    }
    if (!ReadFromParcelThirdPart(parcel)) {
        return false;
    }
    return true;
}

bool AccessibilityEventInfoParcel::MarshallingFirstPart(Parcel &parcel) const
{
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, static_cast<uint32_t>(eventType_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, static_cast<uint32_t>(gestureType_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, bundleName_);
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast<int32_t>(triggerAction_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, timeStamp_);
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast<int32_t>(textMoveStep_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast<int32_t>(windowContentChangeTypes_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast<int32_t>(windowChangeTypes_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast<int32_t>(category_));
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, pageId_);

    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, GetViewId());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetWindowId());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetCurrentIndex());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetBeginIndex());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetEndIndex());
    auto contentList = GetContentList();
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, contentList.size());
    for (auto &content : contentList) {
        WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, content);
    }
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetComponentType());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetDescription());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetBeforeText());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetLatestContent());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, GetAccessibilityId());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetItemCounts());
    AccessibilityElementInfoParcel elementInfoParcel(elementInfo_);
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &elementInfoParcel);
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetTextAnnouncedForAccessibility());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetInspectorKey());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, GetRequestFocusElementId());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetResourceBundleName());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, GetResourceModuleName());
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, GetResourceId());
    auto resourceParams = GetResourceParams();
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, resourceParams.size());
    for (auto &params : resourceParams) {
        WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, std::get<0>(params));
        WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, std::get<1>(params));
    }
    return true;
}

bool AccessibilityEventInfoParcel::MarshallingSecondPart(Parcel &parcel) const
{
    ExtraEventInfoParcel extraEventInfoParcel(extraEventInfo_);
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &extraEventInfoParcel);
    return true;
}

bool AccessibilityEventInfoParcel::Marshalling(Parcel &parcel) const
{
    if (!MarshallingFirstPart(parcel)) {
        return false;
    }
    if (!MarshallingSecondPart(parcel)) {
        return false;
    }
    return true;
}

AccessibilityEventInfoParcel *AccessibilityEventInfoParcel::Unmarshalling(Parcel& parcel)
{
    AccessibilityEventInfoParcel *accessibilityEventInfo = new(std::nothrow) AccessibilityEventInfoParcel();
    if (accessibilityEventInfo == nullptr) {
        HILOG_ERROR("Failed to create accessibilityEventInfo.");
        return nullptr;
    }
    if (!accessibilityEventInfo->ReadFromParcel(parcel)) {
        HILOG_ERROR("read from parcel failed");
        delete accessibilityEventInfo;
        accessibilityEventInfo = nullptr;
        return nullptr;
    }
    return accessibilityEventInfo;
}

ExtraEventInfoParcel::ExtraEventInfoParcel(const ExtraEventInfo &extraEventInfo)
    : ExtraEventInfo(extraEventInfo)
{
}
 
bool ExtraEventInfoParcel::ReadFromParcel(Parcel &parcel)
{
    int32_t mapValueInt = 0;
    READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, mapValueInt);
    HILOG_DEBUG("ReadFromParcel: size is map, mapValueInt: %{public}d", mapValueInt);
 
    if (!ContainerSecurityVerify(parcel, mapValueInt, extraEventValueStr_.max_size())) {
        HILOG_WARN("extraEventValueStr : ExtraEventInfoParcel verify is false");
        return false;
    }
    for (int32_t i = 0; i < mapValueInt; i++) {
        std::string tempMapKey;
        std::string tempMapVal;
        READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, tempMapKey);
        READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, tempMapVal);
        HILOG_DEBUG("ReadFromParcel: extraEventValueStr's tempMapKey: %{public}s, tempMapVal: %{public}s",
            tempMapKey.c_str(), tempMapVal.c_str());
        extraEventValueStr_[tempMapKey] = tempMapVal;
    }
 
    return true;
}

bool ExtraEventInfoParcel::Marshalling(Parcel &parcel) const
{
    WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, extraEventValueStr_.size());
    for (const auto& [key, value] : extraEventValueStr_) {
        WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, key);
        WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String, parcel, value);

    }
    return true;
}

ExtraEventInfoParcel *ExtraEventInfoParcel::Unmarshalling(Parcel &parcel)
{
    ExtraEventInfoParcel *extraEventInfo = new(std::nothrow) ExtraEventInfoParcel();
    if (extraEventInfo == nullptr) {
        HILOG_ERROR("Failed to create extraEventInfo.");
        return nullptr;
    }
    if (!extraEventInfo->ReadFromParcel(parcel)) {
        HILOG_ERROR("read from parcel failed");
        delete extraEventInfo;
        extraEventInfo = nullptr;
        return nullptr;
    }
    return extraEventInfo;
}
} // namespace Accessibility
} // namespace OHOS