/*
 * HEIF codec.
 * Copyright (c) 2023 Dirk Farin <dirk.farin@gmail.com>
 *
 * This file is part of libheif.
 *
 * libheif is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * libheif is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBHEIF_HEIF_ITEMS_H
#define LIBHEIF_HEIF_ITEMS_H

#include "heif_library.h"
#include "heif_error.h"
#include "heif_metadata.h"

#ifdef __cplusplus
extern "C" {
#endif


/**
 * Gets the number of items.
 *
 * This is not the same as the number of images, since there can be other types of items,
 * such as metadata.
 *
 * @param ctx the file context
 * @return the number of items
 */
LIBHEIF_API
int heif_context_get_number_of_items(const heif_context* ctx);

/**
 * Get the item identifiers.
 *
 * Fills in the item IDs into the user-supplied array {@code ID_array}, preallocated with {@code count} entries.
 *
 * @param ctx the file context
 * @param ID_array the output array.
 * @param count the number of items allocated within {@code ID_array}.
 * @return the total number of IDs filled into the array, which may be less than {@code count}.
 */
LIBHEIF_API
int heif_context_get_list_of_item_IDs(const heif_context* ctx,
                                      heif_item_id* ID_array,
                                      int count);

/**
 * Gets the item type.
 *
 * Usually, this is a four character code (e.g. `mime` or `uri `), but it can theoretically be
 * any 4-byte number. Thus, the type is returned as an integer. You can use #heif_fourcc to map
 * between the two representations.
 *
 * @param ctx the file context
 * @param item_id the item identifier for the item
 * @return the item type
 */
LIBHEIF_API
uint32_t heif_item_get_item_type(const heif_context* ctx, heif_item_id item_id);

#define heif_item_type_mime   heif_fourcc('m','i','m','e')
#define heif_item_type_uri    heif_fourcc('u','r','i',' ')
#define heif_item_type_exif   heif_fourcc('E','x','i','f')
#define heif_item_type_grid   heif_fourcc('g','r','i','d')
#define heif_item_type_hvc1   heif_fourcc('h','v','c','1')
#define heif_item_type_unci   heif_fourcc('u','n','c','i')
#define heif_item_type_av01   heif_fourcc('a','v','0','1')
#define heif_item_type_avc1   heif_fourcc('a','v','c','1')

LIBHEIF_API
int heif_item_is_item_hidden(const heif_context* ctx, heif_item_id item_id);


/**
 * Gets the MIME content_type for an item.
 *
 * Only valid if the item type is `mime`.
 * If the item does not exist, or if it is not a `mime` item, NULL is returned.
 *
 * @param ctx the file context
 * @param item_id the item identifier for the item
 * @return the item content_type
 */
LIBHEIF_API
const char* heif_item_get_mime_item_content_type(const heif_context* ctx, heif_item_id item_id);

/**
 * Gets the content_encoding for a MIME item.
 *
 * Only valid if the item type is `mime`.
 * If the item does not exist, or if it is not a `mime` item, NULL is returned.
 *
 * If the item is not encoded, the returned value will be an empty string (not null).
 *
 * @param ctx the file context
 * @param item_id the item identifier for the item
 * @return the item content_type
 */
LIBHEIF_API
const char* heif_item_get_mime_item_content_encoding(const heif_context* ctx, heif_item_id item_id);

/**
 * Gets the item_uri_type for an item.
 *
 * Only valid if the item type is `uri `.
 * If the item does not exist, or if it is not a `uri ` item, NULL is returned.
 *
 * @param ctx the file context
 * @param item_id the item identifier for the item
 * @return the item item_uri_type
 */
LIBHEIF_API
const char* heif_item_get_uri_item_uri_type(const heif_context* ctx, heif_item_id item_id);

LIBHEIF_API
const char* heif_item_get_item_name(const heif_context* ctx, heif_item_id item_id);

LIBHEIF_API
heif_error heif_item_set_item_name(heif_context* ctx,
                                   heif_item_id item,
                                   const char* item_name);


/**
 * Gets the raw metadata, as stored in the HEIF file.
 *
 * Data in a "mime" item with "content_encoding" can be compressed.
 * When `out_compression_format` is NULL, the decompressed data will be returned.
 * Otherwise, the compressed data is returned and `out_compression_format` will be filled with the
 * compression format.
 * If the compression method is not supported, an error will be returned.
 *
 * It is valid to set `out_data` to NULL. In that case, only the `out_data_size` is filled.
 * Note that it is inefficient to use `out_data=NULL` just to get the size of compressed data.
 * In general, this should be avoided.
 *
 * If there is no data assigned to the item or there is an error, `out_data_size` is set to zero.
 *
 * @param ctx the file context
 * @param item_id the item identifier for the item
 * @param out_compression_format how the data is compressed. If the pointer is NULL, the decompressed data will be returned.
 * @param out_data the corresponding raw metadata
 * @param out_data_size the size of the metadata in bytes
 * @return whether the call succeeded, or there was an error
 */
LIBHEIF_API
heif_error heif_item_get_item_data(const heif_context* ctx,
                                   heif_item_id item_id,
                                   enum heif_metadata_compression* out_compression_format,
                                   uint8_t** out_data, size_t* out_data_size);

/**
 * Free the item data.
 *
 * This is used to free memory associated with the data returned by
 * {@link heif_item_get_item_data} in 'out_data' and set the pointer to NULL.
 *
 * @param ctx the file context
 * @param item_data the data to free
 */
LIBHEIF_API
void heif_release_item_data(const heif_context* ctx, uint8_t** item_data);


// ------------------------- item language -------------------------

/**
 * Get the extended language associated with the item.
 * The item is usually a text item.
 *
 * @param context the heif file context containg the item.
 * @param itemId the identifier for the item
 * @param out_language output parameter with the item's language. Free with heif_string_release().
 * @return heif_error_ok on success, or an error value indicating the problem
 */
LIBHEIF_API
heif_error heif_item_get_property_extended_language(const heif_context* context,
                                                    heif_item_id itemId,
                                                    char** out_language);

LIBHEIF_API
heif_error heif_item_set_property_extended_language(heif_context* context,
                                                    heif_item_id item_id,
                                                    const char* language, heif_property_id* out_optional_propertyId);

// ------------------------- item references -------------------------

/**
 * Get the item ids that reference the given item.
 *
 * @param ctx the file context.
 * @param from_item_id the item identifier for the item.
 * @param index the index of the reference to get.
 * @param out_reference_type_4cc The 4cc of the reference. (e.g dimg, thmb, cdsc, or auxl)
 * @param out_references_to the item references. Use {@link heif_release_item_references} to free the memory.
 * @return the number of items that reference the given item. Returns 0 if the index exceeds the number of references.
 */
LIBHEIF_API
size_t heif_context_get_item_references(const heif_context* ctx,
                                        heif_item_id from_item_id,
                                        int index,
                                        uint32_t* out_reference_type_4cc,
                                        heif_item_id** out_references_to);

LIBHEIF_API
void heif_release_item_references(const heif_context* ctx, heif_item_id** references);

LIBHEIF_API
heif_error heif_context_add_item_reference(heif_context* ctx,
                                           uint32_t reference_type,
                                           heif_item_id from_item,
                                           heif_item_id to_item);

LIBHEIF_API
heif_error heif_context_add_item_references(heif_context* ctx,
                                            uint32_t reference_type,
                                            heif_item_id from_item,
                                            const heif_item_id* to_item,
                                            int num_to_items);

// ------------------------- adding new items -------------------------

/*
 * All functions in this section add a new item to the context and return its ID in
 * 'out_item_id'. The item ID is freshly allocated and does not collide with any item that
 * already exists in the context, including items read from an input file.
 *
 * 'data' is copied into the context, the caller may release it afterwards. 'size' is the
 * number of bytes in 'data'. A NULL 'data' is only allowed together with size 0.
 * 'out_item_id' may be NULL, in which case the item is added but its ID is not reported.
 *
 * The new item is marked as hidden. Use heif_context_add_item_reference() to link it to an
 * image (e.g. with a 'cdsc' reference for metadata that describes the image).
 *
 * Note that a file must contain at least one image or image sequence to be written;
 * a context holding only items added with these functions cannot be written.
 */

/**
 * Add an item with an arbitrary four-character item type (e.g. "Exif").
 *
 * @param ctx the file context
 * @param item_type four-character item type
 * @param data the item payload
 * @param size number of bytes in 'data'
 * @param out_item_id receives the ID of the new item (may be NULL)
 */
LIBHEIF_API
heif_error heif_context_add_item(heif_context* ctx,
                                 const char* item_type,
                                 const void* data, int size,
                                 heif_item_id* out_item_id);

/**
 * Add a 'mime' item, optionally compressing the payload.
 *
 * @param ctx the file context
 * @param content_type MIME content type of the payload (e.g. "application/rdf+xml")
 * @param content_encoding compression to apply to the payload before storing it.
 *        Use heif_metadata_compression_method_supported() to check which methods this
 *        build of libheif can compress. An unsupported method returns an error and no
 *        item is added.
 * @param data the (uncompressed) item payload
 * @param size number of bytes in 'data'
 * @param out_item_id receives the ID of the new item (may be NULL)
 */
LIBHEIF_API
heif_error heif_context_add_mime_item(heif_context* ctx,
                                      const char* content_type,
                                      enum heif_metadata_compression content_encoding,
                                      const void* data, int size,
                                      heif_item_id* out_item_id);

/**
 * Add a 'mime' item whose payload has already been compressed by the caller.
 *
 * @param ctx the file context
 * @param content_type MIME content type of the (uncompressed) payload
 * @param content_encoding the HTTP content-coding name that was applied to 'data', stored
 *        verbatim as the item's content_encoding. Use "" for uncompressed data.
 *        libheif itself can decode "deflate", "compress_zlib" and "br" (when built with
 *        zlib / Brotli support) and treats "identity" as uncompressed; items with any other
 *        content_encoding are kept, but their data can only be retrieved in compressed form
 *        with heif_item_get_item_data().
 * @param data the compressed item payload
 * @param size number of bytes in 'data'
 * @param out_item_id receives the ID of the new item (may be NULL)
 */
LIBHEIF_API
heif_error heif_context_add_precompressed_mime_item(heif_context* ctx,
                                                    const char* content_type,
                                                    const char* content_encoding,
                                                    const void* data, int size,
                                                    heif_item_id* out_item_id);

/**
 * Add a 'uri ' item.
 *
 * @param ctx the file context
 * @param item_uri_type the URI that identifies the type of the item payload
 * @param data the item payload
 * @param size number of bytes in 'data'
 * @param out_item_id receives the ID of the new item (may be NULL)
 */
LIBHEIF_API
heif_error heif_context_add_uri_item(heif_context* ctx,
                                     const char* item_uri_type,
                                     const void* data, int size,
                                     heif_item_id* out_item_id);

#ifdef __cplusplus
}
#endif

#endif
