/*
 * 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.
 */

#ifndef PKG_INFO_UTILS_H
#define PKG_INFO_UTILS_H

#include <functional>
#include <string>
#include <vector>
#include "package/package.h"

namespace Hpackage {
struct FileInfo;
struct PkgInfo;
using FileInfoPtr = FileInfo *;
using PkgInfoPtr = PkgInfo *;

/**
 * Error code definition
 */
enum {
    PKG_SUCCESS = 0,
    PKG_ERROR_BASE = 100,
    PKG_INVALID_NAME,
    PKG_INVALID_PARAM,
    PKG_INVALID_FILE,
    PKG_INVALID_SIGNATURE,
    PKG_INVALID_PKG_FORMAT,
    PKG_INVALID_ALGORITHM,
    PKG_INVALID_DIGEST,
    PKG_INVALID_STREAM,
    PKG_INVALID_VERSION,
    PKG_INVALID_STATE,
    PKG_INVALID_LZ4,
    PKG_NONE_PERMISSION,
    PKG_NONE_MEMORY,
    PKG_VERIFY_FAIL,
};

enum {
    PKG_FULL_COMPONENT,
    PKG_DIFF_COMPONENT,
};

enum {
    POST_TYPE_UPLOAD_PKG = 0,
    POST_TYPE_DECODE_PKG,
    POST_TYPE_VERIFY_PKG,
    POST_TYPE_WRITE_PARTITION
};

enum {
    UPGRADE_FILE_COMP_OTHER_TPYE = 1,
    UPGRADE_FILE_COMP_IMG_TPYE
};

/**
 * Package information
 */
struct PkgInfo {
    uint32_t entryCount = 0;
    uint32_t updateFileHeadLen = 0;
    uint8_t signMethod;
    uint8_t digestMethod;
    uint8_t pkgType;
    uint8_t pkgFlags;
};

/**
 * File information
 */
struct FileInfo {
    uint8_t flags = 0;
    uint8_t resType = 0;
    uint8_t type = PKG_FULL_COMPONENT;
    uint8_t digestMethod = 0;
    uint16_t packMethod = 0;
    time_t modifiedTime = 0;
    size_t packedSize = 0;
    size_t unpackedSize = 0;
    size_t headerOffset = 0;
    size_t dataOffset = 0;
    std::string identity;
};

/**
 * Header information of the update package
 */
struct UpgradePkgInfo {
    PkgInfo pkgInfo;
    uint32_t updateFileVersion = 0;
    uint32_t updateFileType = 0;
    std::string productUpdateId;
    std::string softwareVersion;
    std::string date;
    std::string time;
    std::string descriptPackageId;
};

struct UpgradeChunkInfo {
    uint32_t chunkListCount;
    uint64_t chunkListSize;
    uint16_t partitionNum;
    std::unordered_map<std::string, uint64_t> imageSizeMap;
    std::unordered_map<std::string, std::string> imageHashMap;
};

/**
 * Component information of the update package
 */
struct ComponentInfo {
    FileInfo fileInfo;
    std::string version;
    uint8_t digest[DIGEST_MAX_LEN];
    uint16_t id;
    uint8_t resType;
    uint8_t type;
    uint8_t compFlags;
    size_t originalSize;
};

/**
 * Lz4 file configuration information
 */
struct Lz4FileInfo {
    FileInfo fileInfo;
    int8_t compressionLevel;
    int8_t blockIndependence;
    int8_t contentChecksumFlag;
    int8_t blockSizeID;
    int8_t autoFlush = 1;
};

/**
 * Zip file configuration information
 */
struct ZipFileInfo {
    FileInfo fileInfo;
    int32_t method = -1; // The system automatically uses the default value if the value is -1.
    int32_t level;
    int32_t windowBits;
    int32_t memLevel;
    int32_t strategy;
};

/**
 * buff definition used for parsing
 */
struct PkgBuffer {
    uint8_t *buffer;
    size_t length = 0; // buffer size

    std::vector<uint8_t> data;

    PkgBuffer()
    {
        this->buffer = nullptr;
        this->length = 0;
    }

    PkgBuffer(uint8_t *buffer, size_t bufferSize)
    {
        this->buffer = buffer;
        this->length = bufferSize;
    }

    PkgBuffer(std::vector<uint8_t> &buffer)
    {
        this->buffer = buffer.data();
        this->length = buffer.capacity();
    }
    PkgBuffer(size_t bufferSize)
    {
        Resize(bufferSize);
    }
    PkgBuffer(const PkgBuffer &buffer)
    {
        if (buffer.data.empty() && buffer.data.data() != buffer.buffer) {
            this->buffer = buffer.buffer;
            this->length = buffer.length;
            return;
        }
        data = buffer.data;
        this->buffer = data.data();
        this->length = data.capacity();
    }
    PkgBuffer(PkgBuffer &&buffer)
    {
        if (buffer.data.empty() && buffer.data.data() != buffer.buffer) {
            this->buffer = buffer.buffer;
            this->length = buffer.length;
            return;
        }
        data = std::move(buffer.data);
        this->buffer = data.data();
        this->length = data.capacity();
        buffer.Reset();
    }
    PkgBuffer &operator=(const PkgBuffer &buffer)
    {
        if (this == &buffer) {
            return *this;
        }
        if (buffer.data.empty() && buffer.data.data() != buffer.buffer) {
            this->buffer = buffer.buffer;
            this->length = buffer.length;
            return *this;
        }
        data = buffer.data;
        this->buffer = data.data();
        this->length = data.capacity();
        return *this;
    }

    PkgBuffer &operator=(PkgBuffer &&buffer) noexcept
    {
        if (this == &buffer) {
            return *this;
        }
        if (buffer.data.empty() && buffer.data.data() != buffer.buffer) {
            this->buffer = buffer.buffer;
            this->length = buffer.length;
            return *this;
        }
        data = std::move(buffer.data);
        this->buffer = data.data();
        this->length = data.capacity();
        return *this;
    }
    void Reset(void)
    {
        buffer = nullptr;
        length = 0;
        std::vector<uint8_t>().swap(data);
    }
    void Resize(size_t bufferSize)
    {
        data.resize(bufferSize, 0);
        this->buffer = data.data();
        this->length = bufferSize;
    }
    size_t Size(void) const
    {
        if (this->buffer != nullptr) {
            return this->length;
        }
        return data.size();
    }
};
} // namespace Hpackage
#endif // PKG_MANAGER_H