/*
 * Copyright (c) 2023 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 "session/host/include/scene_persistence.h"

#include <sys/stat.h>

#include <hitrace_meter.h>
#include <image_packer.h>
#include <parameters.h>

#include "window_manager_hilog.h"

namespace OHOS::Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "ScenePersistence" };
constexpr const char* UNDERLINE_SEPARATOR = "_";
constexpr const char* SCALED_SNAPSHOT_FLAG = "s";
constexpr const char* ASTC_IMAGE_FORMAT_LOW = "image/astc/8*8";
constexpr const char* ASTC_IMAGE_FORMAT_HIGH = "image/astc/4*4";
constexpr const char* ASTC_IMAGE_SUFFIX = ".astc";
constexpr uint8_t ASTC_IMAGE_QUALITY = 20;

constexpr const char* IMAGE_FORMAT = "image/png";
constexpr const char* IMAGE_SUFFIX = ".png";
constexpr uint8_t IMAGE_QUALITY = 100;
constexpr int32_t ICON_IMAGE_WIDTH_HEIGHT_SIZE = 1024;
constexpr double ICON_IMAGE_MAX_SCALE = 1;

constexpr uint8_t SUCCESS = 0;
} // namespace

std::string ScenePersistence::snapshotDirectory_;
std::string ScenePersistence::updatedIconDirectory_;
std::string ScenePersistence::abilityIconDirectory_;
std::string ScenePersistence::startWindowDirectory_;
std::shared_ptr<WSFFRTHelper> ScenePersistence::snapshotFfrtHelper_;
bool ScenePersistence::isAstcEnabled_ = false;

bool ScenePersistence::CreateSnapshotDir(const std::string& directory)
{
    snapshotDirectory_ = directory + "/SceneSnapShot/";
    if (mkdir(snapshotDirectory_.c_str(), S_IRWXU)) {
        TLOGD(WmsLogTag::WMS_PATTERN, "mkdir failed or the directory already exists");
        return false;
    }
    return true;
}

bool ScenePersistence::CreateUpdatedIconDir(const std::string& directory)
{
    updatedIconDirectory_ = directory + "/UpdatedIcon/";
    if (mkdir(updatedIconDirectory_.c_str(), S_IRWXU)) {
        TLOGD(WmsLogTag::DEFAULT, "mkdir failed or the directory already exists");
        return false;
    }
    return true;
}

bool ScenePersistence::CreateAbilityIconDir(const std::string& directory)
{
    abilityIconDirectory_ = directory + "/AbilityIcon/";
    if (mkdir(abilityIconDirectory_.c_str(), S_IRWXU)) {
        TLOGD(WmsLogTag::DEFAULT, "mkdir failed or the directory already exists");
        return false;
    }
    return true;
}

bool ScenePersistence::CreateStartWindowDir(const std::string& directory)
{
    startWindowDirectory_ = directory + "/StartWindow/";
    if (mkdir(startWindowDirectory_.c_str(), S_IRWXU)) {
        TLOGD(WmsLogTag::DEFAULT, "mkdir failed or the start window directory already exists");
        return false;
    }
    return true;
}

void ScenePersistence::SaveStartWindow(const std::shared_ptr<Media::PixelMap>& pixelMap,
                                       const std::string& saveStartWindowKey,
                                       const std::function<void(std::string, std::string)>& saveStartWindowCallback)
{
    std::string startWindowPath = startWindowDirectory_ + saveStartWindowKey + IMAGE_SUFFIX;
    auto task = [weakThis = wptr(this), pixelMap, startWindowPath, saveStartWindowKey, saveStartWindowCallback]() {
        auto scenePersistence = weakThis.promote();
        if (scenePersistence == nullptr || pixelMap == nullptr || startWindowPath.find('/') == std::string::npos) {
            TLOGNE(WmsLogTag::WMS_PATTERN,
                "SaveStartWindow scenePersistence %{public}s nullptr or pixelMap %{public}s null",
                scenePersistence == nullptr ? "" : "not", pixelMap == nullptr ? "" : "not");
            return;
        }
        OHOS::Media::ImagePacker imagePacker;
        OHOS::Media::PackOption option;
        option.format = IMAGE_FORMAT;
        option.quality = IMAGE_QUALITY;
        if (remove(startWindowPath.c_str())) {
            TLOGND(WmsLogTag::WMS_PATTERN, "SaveStartWindow remove old file failed");
        }
        TLOGNI(WmsLogTag::WMS_PATTERN, "SaveStartWindow begin");
        HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "ScenePersistence::SaveStartWindow %s", startWindowPath.c_str());
        std::lock_guard lock(scenePersistence->savingStartWindowMutex_);
        if (imagePacker.StartPacking(startWindowPath, option)) {
            TLOGNE(WmsLogTag::WMS_PATTERN, "SaveStartWindow failed, start packing error");
            return;
        }
        if (imagePacker.AddImage(*pixelMap)) {
            TLOGNE(WmsLogTag::WMS_PATTERN, "SaveStartWindow failed, add image error");
            return;
        }
        int64_t packedSize = 0;
        if (imagePacker.FinalizePacking(packedSize)) {
            TLOGNE(WmsLogTag::WMS_PATTERN, "SaveStartWindow failed, finish packing error, size: %{public}" PRIu64,
                packedSize);
            return;
        }
        saveStartWindowCallback(startWindowPath, saveStartWindowKey);
        TLOGNI(WmsLogTag::WMS_PATTERN, "SaveStartWindow success, size: %{public}" PRIu64,
            packedSize);
    };
    snapshotFfrtHelper_->SubmitTask(std::move(task), startWindowPath);
}

void ScenePersistence::SetSnapshotCapacity(SnapshotStatus capacity)
{
    capacity_ = capacity;
}

ScenePersistence::ScenePersistence(const std::string& bundleName, int32_t persistentId, SnapshotStatus capacity)
    : bundleName_(bundleName), persistentId_(persistentId), capacity_(capacity)
{
    InitAstcEnabled();
    auto suffix = isAstcEnabled_ ? ASTC_IMAGE_SUFFIX : IMAGE_SUFFIX;
    for (int32_t screenStatus = SCREEN_UNKNOWN; screenStatus < SCREEN_COUNT; screenStatus++) {
        snapshotPath_[screenStatus] = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR +
            std::to_string(persistentId) + UNDERLINE_SEPARATOR + std::to_string(screenStatus) + suffix;
    }
    snapshotScaledPath_ = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR +
        std::to_string(persistentId) + UNDERLINE_SEPARATOR + SCALED_SNAPSHOT_FLAG + suffix;
    snapshotFreeMultiWindowPath_ = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR +
        std::to_string(persistentId) + suffix;
    updatedIconPath_ = updatedIconDirectory_ + bundleName + IMAGE_SUFFIX;
    abilityIconPath_ = abilityIconDirectory_ + bundleName + UNDERLINE_SEPARATOR +
        std::to_string(persistentId) + IMAGE_SUFFIX;
    if (snapshotFfrtHelper_ == nullptr) {
        snapshotFfrtHelper_ = std::make_shared<WSFFRTHelper>();
    }
    const std::string multiWindowUIType = system::GetParameter("const.window.multiWindowUIType", "HandsetSmartWindow");
    isPcWindow_ = (multiWindowUIType == "FreeFormMultiWindow");
}

ScenePersistence::~ScenePersistence()
{
    ClearSnapshotPath();
    ClearAbilityIconPath();
}

void ScenePersistence::ClearSnapshotPath()
{
    auto task = [snapshotPaths = std::vector<std::string>(snapshotPath_, snapshotPath_ + SCREEN_COUNT),
        snapshotFreeMultiWindowPath = snapshotFreeMultiWindowPath_, snapshotScaledPath = snapshotScaledPath_,
        persistentId = persistentId_, where = __func__]() {
        TLOGI(WmsLogTag::WMS_PATTERN, "%{public}s persistentId: %{public}d", where, persistentId);
        for (const auto& snapshotPath: snapshotPaths) {
            remove(snapshotPath.c_str());
        }
        remove(snapshotScaledPath.c_str());
        remove(snapshotFreeMultiWindowPath.c_str());
    };
    snapshotFfrtHelper_->SubmitTask(std::move(task), "ClearSnapshotPath" + std::to_string(persistentId_));
}

void ScenePersistence::ClearAbilityIconPath()
{
    TLOGI(WmsLogTag::WMS_PATTERN, "clear icon, persistentId: %{public}d", persistentId_);
    remove(abilityIconPath_.c_str());
}

std::shared_ptr<WSFFRTHelper> ScenePersistence::GetSnapshotFfrtHelper() const
{
    return snapshotFfrtHelper_;
}

void ScenePersistence::InitAstcEnabled()
{
    static bool isAstcEnabled = system::GetBoolParameter("persist.multimedia.image.astc.enabled", true);
    isAstcEnabled_ = isAstcEnabled;
}

bool ScenePersistence::IsAstcEnabled()
{
    return isAstcEnabled_;
}

void ScenePersistence::SaveSnapshot(const std::shared_ptr<Media::PixelMap>& pixelMap,
    const std::function<void()> resetSnapshotCallback, SnapshotStatus key, DisplayOrientation rotate,
    bool freeMultiWindow)
{
    savingSnapshotSum_.fetch_add(1);
    SetIsSavingSnapshot(true);
    TLOGI(WmsLogTag::WMS_PATTERN, "isSavingSnapshot:%{public}d", isSavingSnapshot_.load());
    std::string path = freeMultiWindow ? snapshotFreeMultiWindowPath_ : snapshotPath_[key];
    float scaleValue = snapshotScaleLow_ / snapshotScale_;
    auto task = [weakThis = wptr(this), pixelMap, resetSnapshotCallback, savingSnapshotSum = savingSnapshotSum_.load(),
        key, rotate, path, freeMultiWindow, scaledPath = snapshotScaledPath_, scaleValue,
        enablePersistentScaledSnapshot = enablePersistentScaledSnapshot_]() {
        auto scenePersistence = weakThis.promote();
        if (scenePersistence == nullptr || pixelMap == nullptr ||
            path.find('/') == std::string::npos) {
            TLOGNE(WmsLogTag::WMS_PATTERN, "scenePersistence %{public}s nullptr, pixelMap %{public}s nullptr",
                scenePersistence == nullptr ? "" : "not", pixelMap == nullptr ? "" : "not");
            resetSnapshotCallback();
            return;
        }

        if (!scenePersistence->PersistSnapshot(path, pixelMap)) {
            resetSnapshotCallback();
            return;
        }
        scenePersistence->SetSnapshotSize(key, freeMultiWindow, false,
            { pixelMap->GetWidth(), pixelMap->GetHeight() });
        scenePersistence->rotate_[key] = rotate;
        if (enablePersistentScaledSnapshot) {
            if (scaledPath.find('/') == std::string::npos) {
                TLOGNE(WmsLogTag::WMS_PATTERN, "scaledPath invalid");
                resetSnapshotCallback();
                return;
            }
            pixelMap->scale(scaleValue, scaleValue);
            if (!scenePersistence->PersistSnapshot(scaledPath, pixelMap)) {
                TLOGNE(WmsLogTag::WMS_PATTERN, "Save scaledSnapshot failed");
                resetSnapshotCallback();
                return;
            }
            scenePersistence->SetSnapshotSize(key, false, true, { pixelMap->GetWidth(), pixelMap->GetHeight() });
        }
        // If the current num is equals to the latest num, it is the last saveSnapshot task
        if (savingSnapshotSum == scenePersistence->savingSnapshotSum_.load()) {
            resetSnapshotCallback();
        }
    };
    snapshotFfrtHelper_->SubmitTask(std::move(task), "SaveSnapshot" + path);
}

bool ScenePersistence::PersistSnapshot(std::string path, const std::shared_ptr<Media::PixelMap>& pixelMap)
{
    TLOGI(WmsLogTag::WMS_PATTERN, "Save snapshot begin");
    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "SaveSnapshot %s", path.c_str());
    OHOS::Media::ImagePacker imagePacker;
    OHOS::Media::PackOption option;
    const char *astcImageFormat = isPcWindow_ ? ASTC_IMAGE_FORMAT_LOW : ASTC_IMAGE_FORMAT_HIGH;
    option.format = IsAstcEnabled() ? astcImageFormat : IMAGE_FORMAT;
    option.quality = IsAstcEnabled() ? ASTC_IMAGE_QUALITY : IMAGE_QUALITY;
    option.numberHint = 1;

    std::lock_guard lock(savingSnapshotMutex_);
    if (auto ret = remove(path.c_str())) {
        TLOGD(WmsLogTag::WMS_PATTERN, "Remove %{public}s failed ret:%{public}d", path.c_str(), ret);
    }
    if (imagePacker.StartPacking(path, option)) {
        TLOGE(WmsLogTag::WMS_PATTERN, "Save snapshot failed, starting packing error");
        return false;
    }
    if (imagePacker.AddImage(*pixelMap)) {
        TLOGE(WmsLogTag::WMS_PATTERN, "Save snapshot failed, adding image error");
        return false;
    }
    int64_t packedSize = 0;
    if (imagePacker.FinalizePacking(packedSize)) {
        TLOGE(WmsLogTag::WMS_PATTERN, "Save snapshot failed, finalizing packing error");
        return false;
    }
    TLOGI(WmsLogTag::WMS_PATTERN, "Save snapshot end, packed size %{public}" PRId64, packedSize);
    return true;
}

bool ScenePersistence::IsSavingSnapshot()
{
    return isSavingSnapshot_.load();
}

void ScenePersistence::SetIsSavingSnapshot(bool isSavingSnapshot)
{
    isSavingSnapshot_.store(isSavingSnapshot);
}

void ScenePersistence::ResetSnapshotCache()
{
    isSavingSnapshot_.store(false);
}

void ScenePersistence::RenameSnapshotFromOldPersistentId(const int32_t& oldPersistentId)
{
    auto task = [weakThis = wptr(this), oldPersistentId]() {
        auto scenePersistence = weakThis.promote();
        if (scenePersistence == nullptr) {
            TLOGNE(WmsLogTag::WMS_PATTERN, "scenePersistence is nullptr");
            return;
        }
        for (int32_t screenStatus = SCREEN_UNKNOWN; screenStatus < SCREEN_COUNT; screenStatus++) {
            scenePersistence->RenameSnapshotFromOldPersistentId(oldPersistentId, screenStatus);
        }
        auto suffix = scenePersistence->isAstcEnabled_ ? ASTC_IMAGE_SUFFIX : IMAGE_SUFFIX;
        std::string oldSnapshotFreeMultiWindowPath = snapshotDirectory_ + scenePersistence->bundleName_ +
            UNDERLINE_SEPARATOR + std::to_string(oldPersistentId) + suffix;
        auto& snapshotPath = scenePersistence->snapshotFreeMultiWindowPath_;
        std::lock_guard lock(scenePersistence->savingSnapshotMutex_);
        int ret = std::rename(oldSnapshotFreeMultiWindowPath.c_str(), snapshotPath.c_str());
        if (ret == 0) {
            TLOGNI(WmsLogTag::WMS_PATTERN, "Rename snapshot from %{public}s to %{public}s.",
                oldSnapshotFreeMultiWindowPath.c_str(), snapshotPath.c_str());
        } else {
            TLOGNW(WmsLogTag::WMS_PATTERN, "Failed to rename snapshot from %{public}s to %{public}s.",
                oldSnapshotFreeMultiWindowPath.c_str(), snapshotPath.c_str());
        }
        std::string oldSnapshotScaledPath = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
            std::to_string(oldPersistentId) + UNDERLINE_SEPARATOR + SCALED_SNAPSHOT_FLAG + suffix;
        auto& snapshotScaledPath = scenePersistence->snapshotScaledPath_;
        ret = std::rename(oldSnapshotScaledPath.c_str(), snapshotScaledPath.c_str());
        if (ret == 0) {
            TLOGNI(WmsLogTag::WMS_PATTERN, "Rename snapshot from %{public}s to %{public}s.",
                oldSnapshotScaledPath.c_str(), snapshotScaledPath.c_str());
        } else {
            TLOGNW(WmsLogTag::WMS_PATTERN, "Failed to rename snapshot from %{public}s to %{public}s.",
                oldSnapshotScaledPath.c_str(), snapshotScaledPath.c_str());
        }
    };
    snapshotFfrtHelper_->SubmitTask(std::move(task), "RenameSnapshotFromOldPersistentId"
        + std::to_string(oldPersistentId));
}

void ScenePersistence::RenameSnapshotFromOldPersistentId(const int32_t& oldPersistentId, SnapshotStatus key)
{
    auto& snapshotPath = snapshotPath_[key];
    auto suffix = isAstcEnabled_ ? ASTC_IMAGE_SUFFIX : IMAGE_SUFFIX;
    std::string oldSnapshotPath = snapshotDirectory_ + bundleName_ + UNDERLINE_SEPARATOR +
        std::to_string(oldPersistentId) + UNDERLINE_SEPARATOR + std::to_string(key) + suffix;
    std::lock_guard lock(savingSnapshotMutex_);
    int ret = std::rename(oldSnapshotPath.c_str(), snapshotPath.c_str());
    if (ret == 0) {
        TLOGI(WmsLogTag::WMS_PATTERN, "Rename snapshot from %{public}s to %{public}s.",
            oldSnapshotPath.c_str(), snapshotPath.c_str());
    } else {
        TLOGW(WmsLogTag::WMS_PATTERN, "Failed to rename snapshot from %{public}s to %{public}s.",
            oldSnapshotPath.c_str(), snapshotPath.c_str());
    }
}

std::string ScenePersistence::GetSnapshotFilePath(SnapshotStatus& key, bool useKey, bool freeMultiWindow)
{
    if (freeMultiWindow) {
        return snapshotFreeMultiWindowPath_;
    }
    if (useKey || HasSnapshot(key, false)) {
        return snapshotPath_[key];
    }
    if (FindClosestFormSnapshot(key)) {
        TLOGW(WmsLogTag::WMS_PATTERN, "FindClosestFormSnapshot:%{public}d", key);
        return snapshotPath_[key];
    }
    TLOGW(WmsLogTag::WMS_PATTERN, "Failed");
    return snapshotPath_[SCREEN_UNKNOWN];
}

bool ScenePersistence::FindClosestFormSnapshot(SnapshotStatus& key)
{
    std::lock_guard lock(hasSnapshotMutex_);
    if (hasSnapshot_[key]) {
        return true;
    }
    bool isFolded = (key == SCREEN_FOLDED);
    if (isFolded) {
        for (int32_t screenStatus = SCREEN_EXPAND; screenStatus >= SCREEN_UNKNOWN; screenStatus--) {
            if (hasSnapshot_[screenStatus]) {
                key = screenStatus;
                return true;
            }
        }
        return false;
    }
    for (int32_t screenStatus = SCREEN_UNKNOWN; screenStatus < SCREEN_COUNT; screenStatus++) {
        if (hasSnapshot_[screenStatus]) {
            key = screenStatus;
            return true;
        }
    }
    return false;
}

void ScenePersistence::SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap>& pixelMap)
{
    if (pixelMap == nullptr || updatedIconPath_.find('/') == std::string::npos) {
        return;
    }
    SaveIcon(pixelMap, updatedIconPath_);
}

std::string ScenePersistence::GetUpdatedIconPath() const
{
    return updatedIconPath_;
}

void ScenePersistence::SaveAbilityIcon(const std::shared_ptr<Media::PixelMap>& pixelMap)
{
    if (pixelMap == nullptr || abilityIconPath_.find('/') == std::string::npos) {
        return;
    }
    SaveIcon(pixelMap, abilityIconPath_);
}

std::string ScenePersistence::GetAbilityIconPath() const
{
    return abilityIconPath_;
}

void ScenePersistence::SaveIcon(const std::shared_ptr<Media::PixelMap>& pixelMap, std::string iconPath)
{
    OHOS::Media::ImagePacker imagePacker;
    OHOS::Media::PackOption option;
    option.format = IMAGE_FORMAT;
    option.quality = IMAGE_QUALITY;
    option.numberHint = 1;
    if (pixelMap->GetWidth() > ICON_IMAGE_WIDTH_HEIGHT_SIZE || pixelMap->GetHeight() > ICON_IMAGE_WIDTH_HEIGHT_SIZE) {
        // large image need scale
        double xScale = pixelMap->GetWidth() > ICON_IMAGE_WIDTH_HEIGHT_SIZE ?
            ICON_IMAGE_WIDTH_HEIGHT_SIZE / ((double) pixelMap->GetWidth()) : ICON_IMAGE_MAX_SCALE;
        double yScale = pixelMap->GetHeight() > ICON_IMAGE_WIDTH_HEIGHT_SIZE ?
            ICON_IMAGE_WIDTH_HEIGHT_SIZE / ((double) pixelMap->GetHeight()) : ICON_IMAGE_MAX_SCALE;
        pixelMap->scale(xScale, yScale, Media::AntiAliasingOption::MEDIUM);
    }
    if (remove(iconPath.c_str())) {
        TLOGD(WmsLogTag::DEFAULT, "Failed to delete old file");
    }
    if (imagePacker.StartPacking(iconPath, option)) {
        TLOGE(WmsLogTag::DEFAULT, "Save icon failed, starting packing error");
        return;
    }
    if (imagePacker.AddImage(*pixelMap)) {
        TLOGE(WmsLogTag::DEFAULT, "Save icon failed, adding image error");
        return;
    }
    int64_t packedSize = 0;
    if (imagePacker.FinalizePacking(packedSize)) {
        TLOGE(WmsLogTag::DEFAULT, "Save icon failed, finalizing packing error");
        return;
    }
    TLOGD(WmsLogTag::DEFAULT, "SaveIcon finished");
}

void ScenePersistence::SetSnapshotSize(SnapshotStatus key, bool freeMultiWindow, bool isScaledSnapshot,
    std::pair<uint32_t, uint32_t> size)
{
    std::lock_guard lock(snapshotSizeMutex_);
    if (isScaledSnapshot) {
        snapshotScaledSize_ = size;
        return;
    }
    if (freeMultiWindow) {
        snapshotFreeMultiWindowSize_ = size;
        return;
    }
    snapshotSize_[key] = size;
}

std::pair<uint32_t, uint32_t> ScenePersistence::GetSnapshotSize(SnapshotStatus key, bool freeMultiWindow,
    bool isScaledSnapshot) const
{
    std::lock_guard lock(snapshotSizeMutex_);
    if (isScaledSnapshot) {
        return snapshotScaledSize_;
    }
    if (freeMultiWindow) {
        return snapshotFreeMultiWindowSize_;
    }
    return snapshotSize_[key];
}

void ScenePersistence::SetHasSnapshot(bool hasSnapshot, SnapshotStatus key)
{
    std::lock_guard lock(hasSnapshotMutex_);
    hasSnapshot_[key] = hasSnapshot;
}

void ScenePersistence::SetHasSnapshotFreeMultiWindow(bool hasSnapshot)
{
    std::lock_guard lock(hasSnapshotMutex_);
    hasSnapshotFreeMultiWindow_ = hasSnapshot;
}

bool ScenePersistence::HasSnapshot() const
{
    std::lock_guard lock(hasSnapshotMutex_);
    for (const auto& hasSnapshot : hasSnapshot_) {
        if (hasSnapshot) {
            return true;
        }
    }
    return hasSnapshotFreeMultiWindow_;
}

bool ScenePersistence::HasSnapshot(SnapshotStatus key, bool freeMultiWindow) const
{
    std::lock_guard lock(hasSnapshotMutex_);
    if (freeMultiWindow) {
        return hasSnapshotFreeMultiWindow_;
    }
    return hasSnapshot_[key];
}

void ScenePersistence::ClearSnapshot()
{
    std::lock_guard lock(hasSnapshotMutex_);
    for (auto& hasSnapshot : hasSnapshot_) {
        hasSnapshot = false;
    }
    hasSnapshotFreeMultiWindow_ = false;
}

bool ScenePersistence::IsSnapshotExisted(SnapshotStatus key, bool freeMultiWindow)
{
    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IsSnapshotExisted");
    struct stat buf;
    auto snapshotPath = GetSnapshotFilePath(key, true, freeMultiWindow);
    if (stat(snapshotPath.c_str(), &buf)) {
        TLOGD(WmsLogTag::WMS_PATTERN, "Snapshot file %{public}s does not exist",
            snapshotPath.c_str());
        return false;
    }
    if (!S_ISREG(buf.st_mode)) {
        return false;
    }
    SetHasSnapshot(true, key);
    return true;
}

std::shared_ptr<Media::PixelMap> ScenePersistence::GetLocalSnapshotPixelMap(const float oriScale,
    const float newScale, SnapshotStatus key, bool freeMultiWindow)
{
    if (!IsSnapshotExisted(key, freeMultiWindow)) {
        TLOGE(WmsLogTag::WMS_PATTERN, "local snapshot pic is not existed");
        return nullptr;
    }

    uint32_t errorCode = 0;
    Media::SourceOptions sourceOpts;
    const char *astcImageFormat = this->isPcWindow_ ? ASTC_IMAGE_FORMAT_LOW : ASTC_IMAGE_FORMAT_HIGH;
    sourceOpts.formatHint = IsAstcEnabled() ? astcImageFormat : IMAGE_FORMAT;
    std::string path = GetSnapshotFilePath(key, true, freeMultiWindow);
    std::lock_guard lock(savingSnapshotMutex_);
    auto imageSource = Media::ImageSource::CreateImageSource(path, sourceOpts, errorCode);
    if (!imageSource) {
        TLOGE(WmsLogTag::WMS_PATTERN, "create image source fail, errCode: %{public}u", errorCode);
        return nullptr;
    }

    Media::ImageInfo info;
    int32_t decoderWidth = 0;
    int32_t decoderHeight = 0;
    errorCode = imageSource->GetImageInfo(info);
    if (errorCode == Rosen::SUCCESS) {
        decoderWidth = info.size.width;
        decoderHeight = info.size.height;
    }
    Media::DecodeOptions decodeOpts;
    decodeOpts.desiredPixelFormat = Media::PixelFormat::RGBA_8888;
    if (oriScale != 0 && decoderWidth > 0 && decoderHeight > 0) {
        auto isNeedToScale = newScale < oriScale;
        decodeOpts.desiredSize.width = isNeedToScale ?
            static_cast<int>(decoderWidth * newScale / oriScale) : decoderWidth;
        decodeOpts.desiredSize.height = isNeedToScale ?
            static_cast<int>(decoderHeight * newScale / oriScale) : decoderHeight;
    }
    return imageSource->CreatePixelMap(decodeOpts, errorCode);
}
} // namespace OHOS::Rosen