/* This file is part of Nokia HEIF library
 *
 * Copyright (c) 2015-2025 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
 *
 * Contact: heif@nokia.com
 *
 * This software, including documentation, is protected by copyright controlled by Nokia Corporation and/ or its
 * subsidiaries. All rights are reserved.
 *
 * Copying, including reproducing, storing, adapting or translating, any or all of this material requires the prior
 * written consent of Nokia.
 */

#ifndef ITEMINFOBOX_HPP
#define ITEMINFOBOX_HPP

#include <cstdint>

#include "customallocator.hpp"
#include "fullbox.hpp"

namespace ISOBMFF
{
    class BitStream;
}
class ItemInfoEntry;
class ItemInfoExtension;

/** @brief Item Information Box class. Extends from FullBox.
 *  @details 'iinf' box contains information about an item's type, encoding and protection scheme */

class ItemInfoBox : public FullBox
{
public:
    ItemInfoBox();
    ItemInfoBox(uint8_t version);
    ~ItemInfoBox() override = default;

    /** @brief Clear the contents of the Item Information List */
    void clear();

    /** @return All Item IDs in this ItemInfoBox */
    const Vector<std::uint32_t>& getItemIds() const;

    /** @brief Add a new Item Information Entry to the Item Information List
     * @param [in] infoEntry ItemInfoEntry to be added. */
    void addItemInfoEntry(const ItemInfoEntry& infoEntry);

    /** @brief Creates the bitstream that represents the box in the ISOBMFF file
     *  @param [out] bitstr Bitstream that contains the box data. */
    void writeBox(ISOBMFF::BitStream& bitstr) const override;

    /** @brief Parses a ItemInfoBox bitstream and fills in the necessary member variables
     *  @param [in]  bitstr Bitstream that contains the box data */
    void parseBox(ISOBMFF::BitStream& bitstr) override;

    /** @brief Get the ItemInfoEntry of particular item type
     * @param [in] itemType Type (4CC) of the item to find.
     * @param [in] index    0-based index of the ItemInformationEntry to be retrieved
     * @return ItemInfoEntry at the desired index */
    ItemInfoEntry* findItemWithType(FourCCInt itemType, unsigned int index = 0);

    /** @brief Return an ItemInfoEntry of an item with a desired itemId
     * @param [in] itemId ID of an Item
     * @return ItemInfoEntry with the desired itemId
     * @throws Runtime Exception if the requested ItemInfoEntry is not found. */
    ItemInfoEntry getItemById(uint32_t itemId) const;

    /** @brief Return an ItemInfoEntry of an item with a desired itemId
     * @param [in] itemId ID of an Item
     * @return ItemInfoEntry with the desired itemId
     * @throws Runtime Exception if the requested ItemInfoEntry is not found. */
    ItemInfoEntry& getItemById(uint32_t itemId);

private:
    Vector<ItemInfoEntry> mItemInfoList;  ///< Vector of the ItemInfoEntry Boxes
    Vector<std::uint32_t> mItemIds;
};

/** @brief Item Information Entry Box. Extends from FullBox.
 *  @details 'infe' box contains information about an item's properties as stored in the meta box. */
class ItemInfoEntry : public FullBox
{
public:
    ItemInfoEntry();
    ~ItemInfoEntry() override;

    ItemInfoEntry(const ItemInfoEntry&) = default;
    ItemInfoEntry& operator=(const ItemInfoEntry&) = default;

    /** @brief Set an item Id to the ItemInfoEntry
     * @param [in] id ID of an Item */
    void setItemID(std::uint32_t id);

    /** @brief Get the ID of an item
     * @return ID of an Item */
    std::uint32_t getItemID() const;

    /** @brief Set the item protection index of the ItemInfoEntry
     * @param [in] idx the index of the item protection scheme as listed in the item protection box */
    void setItemProtectionIndex(std::uint16_t idx);

    /** @brief Get the item protection index of the ItemInfoEntry
     * @return The index of the item protection scheme as listed in the item protection box */
    std::uint16_t getItemProtectionIndex() const;

    /** @brief Set the item name of the ItemInfoEntry
     * @param [in] name the name of the ItemInfoEntry */
    void setItemName(const String& name);

    /** @brief Get the item name of the ItemInfoEntry
     * @return The name of the ItemInfoEntry */
    const String& getItemName() const;

    /** @brief Set the content type of the ItemInfoEntry
     * @param [in] contentType the content type of the ItemInfoEntry */
    void setContentType(const String& contentType);

    /** @brief Get the content type of the ItemInfoEntry
     * @return The content type of the ItemInfoEntry */
    const String& getContentType() const;

    /** @brief Set the content encoding of the ItemInfoEntry
     * @param [in] contentEncoding The content encoding of the ItemInfoEntry */
    void setContentEncoding(const String& contentEncoding);

    /** @brief Get the content encoding of the ItemInfoEntry
     * @return The content encoding of the ItemInfoEntry */
    const String& getContentEncoding() const;

    /** @brief Set the extension Type of the ItemInfoEntry
     * @param [in] extensionType The extension type of the ItemInfoEntry */
    void setExtensionType(const String& extensionType);

    /** @brief Get the extension Type of the ItemInfoEntry
     * @return The extension type of the ItemInfoEntry */
    const String& getExtensionType() const;

    /** @brief Set the item type of the ItemInfoEntry
     * @param [in] itemType The item type of the ItemInfoEntry */
    void setItemType(FourCCInt itemType);

    /** @brief Get the item type of the ItemInfoEntry
     * @return The item type of the ItemInfoEntry */
    FourCCInt getItemType() const;

    /** @brief Set the item URI type of the ItemInfoEntry
     * @param [in] itemUriType The item URI type of the ItemInfoEntry */
    void setItemUriType(const String& itemUriType);

    /** @brief Get the item URI type of the ItemInfoEntry
     * @return The item URI type of the ItemInfoEntry */
    const String& getItemUriType() const;

    /** @brief Creates the bitstream that represents the box in the ISOBMFF file
     *  @param [out] bitstr Bitstream that contains the box data. */
    void writeBox(ISOBMFF::BitStream& bitstr) const override;

    /** @brief Parses an ItemInfoEntry bitstream and fills in the necessary member variables
     *  @param [in]  bitstr Bitstream that contains the box data */
    void parseBox(ISOBMFF::BitStream& bitstr) override;

private:
    // Version 0, 1, 2, 3
    std::uint32_t mItemID;               ///< ID of the item
    std::uint16_t mItemProtectionIndex;  ///< Item protection index
    String mItemName;                    ///< Item name
    String mContentType;                 ///< Content type
    String mContentEncoding;             ///< Content encoding

    // Version 1
    String mExtensionType;  ///< The extension type

    /** @todo Verify if default shallow copy is wanted/needed for ItemInfoExtension */
    std::shared_ptr<ItemInfoExtension> mItemInfoExtension;  ///< Item info extension

    // Version 2
    FourCCInt mItemType;  ///< Item type.
    String mItemUriType;  ///< Item URI type.
};

/** @brief Item Information Extension abstract class.
 *  @details Item Information Extension class can be used to extend the item information data structure. */
class ItemInfoExtension
{
public:
    ItemInfoExtension()          = default;
    virtual ~ItemInfoExtension() = default;

    /** @brief Creates the bitstream that represents the box in the ISOBMFF file
     *  @param [out] bitstr Bitstream that contains the box data. */
    virtual void write(ISOBMFF::BitStream& bitstr) = 0;

    /** @brief Parses an ItemInfoExtension bitstream and fills in the necessary member variables
     *  @param [in]  bitstr Bitstream that contains the box data */
    virtual void parse(ISOBMFF::BitStream& bitstr) = 0;
};

/** @brief FD Item Information Extension class.
 *  @details Implements Item Information Extension class of type 'fdel' as defined in the ISOBMFF standard. */
class FDItemInfoExtension : public ItemInfoExtension
{
public:
    FDItemInfoExtension();
    ~FDItemInfoExtension() override = default;

    /** @brief Set the content location field
     * @param [in] location Content Location field as defined in the ISOBMFF standard. */
    void setContentLocation(const String& location);

    /** @brief Get the content location field
     * @return Content Location field as defined in the ISOBMFF standard. */
    const String& getContentLocation();

    /** @brief Set the content MD5 value.
     * @param [in] md5 MD5 value as defined in the ISOBMFF standard. */
    void setContentMD5(const String& md5);

    /** @brief Get the content MD5 value.
     * @return MD5 value as defined in the ISOBMFF standard. */
    const String& getContentMD5();

    /** @brief Set the content length.
     * @param [in] length content length value as defined in the ISOBMFF standard. */
    void setContentLength(uint64_t length);

    /** @brief Get the content length.
     * @return Content Length value as defined in the ISOBMFF standard. */
    uint64_t getContentLength();

    /** @brief Set the transfer length.
     * @param [in] length transfer length value as defined in the ISOBMFF standard. */
    void setTranferLength(uint64_t length);

    /** @brief Get the content length.
     * @return Content Length value as defined in the ISOBMFF standard. */
    uint64_t getTranferLength();

    /** @brief Set the number of entries in the Group ID list.
     * @param [in] numID Number of entries in the Group ID list. */
    void setNumGroupID(uint8_t numID);

    /** @brief Get the number of entries in the Group ID list.
     * @return Number of entries in the Group ID list. */
    uint8_t getNumGroupID();

    /** @brief Set the Group ID of an index in the list.
     * @param [in] idx Group ID to insert to the Group ID List.
     * @param [in] id Group Id value to be inserted to the Group ID List. */
    void setGroupID(const std::uint32_t idx, const uint32_t id);

    /** @brief Set the Group ID of an index in the list.
     * @param [in] idx Group ID to insert to the Group ID List.
     * @return Group Id value. */
    uint32_t getGroupID(const std::uint32_t idx);

    /** @brief Creates the bitstream that represents the class in the ISOBMFF file
     *  @param [out] bitstr Bitstream that contains the class data. */
    void write(ISOBMFF::BitStream& bitstr) override;

    /** @brief Parses an FDItemInfoExtension bitstream and fills in the necessary member variables
     *  @param [in]  bitstr Bitstream that contains the class data */
    void parse(ISOBMFF::BitStream& bitstr) override;

private:
    String mContentLocation;    ///< Content location
    String mContentMD5;         ///< MD5 value
    uint64_t mContentLength;    ///< Content length
    uint64_t mTransferLength;   ///< Transfer length
    uint8_t mEntryCount;        ///< Entry count
    Vector<uint32_t> mGroupID;  ///< Vector of Group ID values
};

#endif /* end of include guard: ITEMINFOBOX_HPP */
