/*
 * Copyright (c) 2022 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 "adapter/ios/osal/file_asset_provider.h"

#include <dirent.h>
#include <limits>
#include <sys/types.h>

#include "base/log/ace_trace.h"
#include "base/log/log.h"

namespace OHOS::Ace {
FileAssetProvider::~FileAssetProvider() {}

bool FileAssetProvider::Initialize(const std::string& packagePath, const std::vector<std::string>& assetBasePaths)
{
    ACE_SCOPED_TRACE("Initialize");
    if (assetBasePaths.empty()) {
        LOGE("the assetBasePath is empty");
        return false;
    }
    assetBasePaths_ = assetBasePaths;
    packagePath_ = packagePath;
    return true;
}

bool FileAssetProvider::IsValid() const
{
    return true;
}

class FileAssetMapping : public AssetMapping {
public:
    FileAssetMapping(std::unique_ptr<uint8_t[]> data, size_t size) : data_(std::move(data)), size_(size) {}

    ~FileAssetMapping() override {}

    size_t GetSize() const override
    {
        return size_;
    }

    const uint8_t* GetAsset() const override
    {
        return data_.get();
    }

private:
    std::unique_ptr<uint8_t[]> data_;
    size_t size_ = 0;
};

std::unique_ptr<AssetMapping> FileAssetProvider::GetAsMapping(const std::string& assetName) const
{
    ACE_SCOPED_TRACE("GetAsMapping");
    LOGD("assert name is: %{public}s", assetName.c_str());
    std::lock_guard<std::mutex> lock(mutex_);

    for (const auto& basePath : assetBasePaths_) {
        std::string fileName = packagePath_ + basePath + assetName;
        std::FILE* fp = std::fopen(fileName.c_str(), "r");
        if (fp == nullptr) {
            continue;
        }

        if (std::fseek(fp, 0, SEEK_END) != 0) {
            LOGE("seek file tail error");
            std::fclose(fp);
            continue;
        }

        long size = std::ftell(fp);
        uint8_t* dataArray = new (std::nothrow) uint8_t[size];
        if (dataArray == nullptr) {
            LOGE("new uint8_t array failed");
            std::fclose(fp);
            continue;
        }

        rewind(fp);
        std::unique_ptr<uint8_t[]> data(dataArray);
        size_t result = std::fread(data.get(), 1, size, fp);
        if (result != (size_t)size) {
            LOGE("read file failed");
            std::fclose(fp);
            continue;
        }

        fclose(fp);
        return std::make_unique<FileAssetMapping>(std::move(data), size);
    }
    return nullptr;
}

std::string FileAssetProvider::GetAssetPath(const std::string& assetName, bool)
{
    for (const auto& basePath : assetBasePaths_) {
        std::string assetBasePath = packagePath_ + basePath;
        std::string fileName = assetBasePath + assetName;
        std::FILE* fp = std::fopen(fileName.c_str(), "r");
        if (fp == nullptr) {
            continue;
        }
        std::fclose(fp);
        return assetBasePath;
    }
    LOGE("Cannot find base path of %{public}s", assetName.c_str());
    return "";
}

void FileAssetProvider::GetAssetList(const std::string& path, std::vector<std::string>& assetList)
{
    for (const auto& basePath : assetBasePaths_) {
        DIR* dp = nullptr;
        auto openDir = packagePath_ + basePath + path;
        if (nullptr == (dp = opendir(openDir.c_str()))) {
            continue;
        }
        struct dirent* dptr = nullptr;
        while ((dptr = readdir(dp)) != nullptr) {
            if (strcmp(dptr->d_name, ".") != 0 && strcmp(dptr->d_name, "..") != 0) {
                std::string file = "./";
                file += dptr->d_name;
                assetList.emplace_back(file);
            }
        }
        closedir(dp);
    }
}

} // namespace OHOS::Ace