/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is MP4v2.
 *
 * The Initial Developer of the Original Code is Kona Blend.
 * Portions created by Kona Blend are Copyright (C) 2009.
 * All Rights Reserved.
 *
 * Contributor(s):
 *      Kona Blend, kona8lend@gmail.com
 *      David Byron, dbyron0@gmail.com
 */
#ifndef MP4V2_ITMF_TAGS_H
#define MP4V2_ITMF_TAGS_H

/**************************************************************************//**
 *
 *  @defgroup mp4_itmf_tags MP4v2 iTMF (iTunes Metadata Format) Tags
 *  @{
 *
 *  This is a high-level API used to manage iTMF metadata.
 *
 *  It provides more type-safety and simplified memory management as compared
 *  to iTMF Generic API.
 *
 *  At the heart of this API is a read-only structure that holds all known
 *  items and their current values. The value is always a pointer which if
 *  NULL indicates its corresponding atom does not exist. Thus, one must
 *  always check if the pointer is non-NULL before attempting to extract
 *  its value.
 *
 *  The structure may not be directly modified. Instead, <b>set</b> functions
 *  corresponding to each item are used to modify the backing-store of
 *  the read-only structure. Setting the value ptr to NULL will effectively
 *  remove it. Setting the value ptr to real data will immediately make a
 *  copy of the value in the backing-store and the read-only structure
 *  will correctly reflect the change.
 *
 *  The hidden data cache memory is automatically managed. Thus the user need
 *  only guarantee the data is available during the lifetime of the set-function
 *  call.
 *
 *  <b>iTMF Tags read workflow:</b>
 *
 *      @li MP4TagsAlloc()
 *      @li MP4TagsFetch()
 *      @li inspect each tag of interest...
 *      @li MP4TagsStore() (if modified)
 *      @li MP4TagsFree()
 *
 *  <b>iTMF Tags read/modify/add/remove workflow:</b>
 *
 *      @li MP4TagsAlloc()
 *      @li MP4TagsFetch()
 *      @li inspect each tag of interest...
 *      @li MP4TagsSetName(), MP4TagsSetArtist()...
 *      @li MP4TagsStore()
 *      @li MP4TagsFree()
 *
 *  @par Warning:
 *  Care must be taken when using multiple mechanisms to modify an open mp4
 *  file as it is not thread-safe, nor does it permit overlapping different
 *  API workflows which have a begin/end to their workflow. That is to say
 *  do not interleave an iTMF Generic workflow with an iTMF Tags workflow.
 *
 *****************************************************************************/

/** Enumeration of possible MP4TagArtwork::type values. */
typedef enum MP4TagArtworkType_e
{
    MP4_ART_UNDEFINED = 0,
    MP4_ART_BMP       = 1,
    MP4_ART_GIF       = 2,
    MP4_ART_JPEG      = 3,
    MP4_ART_PNG       = 4
} MP4TagArtworkType;

/** Data object representing a single piece of artwork. */
typedef struct MP4TagArtwork_s
{
    void*             data; /**< raw picture data */
    uint32_t          size; /**< data size in bytes */
    MP4TagArtworkType type; /**< data type */
} MP4TagArtwork;

typedef struct MP4TagTrack_s
{
    uint16_t index;
    uint16_t total;
} MP4TagTrack;

typedef struct MP4TagDisk_s
{
    uint16_t index;
    uint16_t total;
} MP4TagDisk;

/** Tags <b>convenience</b> structure.
 *
 *  This structure is used in the tags convenience API which allows for
 *  simplified retrieval and modification of the majority of known tags.
 *
 *  This is a read-only structure and each tag is present if and only if the
 *  pointer is a <b>non-NULL</b> value. The actual data is backed by a hidden
 *  data cache which is only updated when the appropriate metadata <b>set</b>
 *  function is used, or if MP4TagsFetch() is invoked. Thus, if other API
 *  is used to manipulate relevent atom structure of the MP4 file, the user
 *  is responsible for re-fetching the data in this structure.
 */
typedef struct MP4Tags_s
{
    void* __handle; /* internal use only */

    const char*          name;
    const char*          artist;
    const char*          albumArtist; 
    const char*          album;
    const char*          grouping;
    const char*          composer;
    const char*          comments;
    const char*          genre;
    const uint16_t*      genreType;
    const char*          releaseDate;
    const MP4TagTrack*   track;
    const MP4TagDisk*    disk;
    const uint16_t*      tempo;
    const uint8_t*       compilation;

    const char*          tvShow;
    const char*          tvNetwork;
    const char*          tvEpisodeID;
    const uint32_t*      tvSeason;
    const uint32_t*      tvEpisode;

    const char*          description;
    const char*          longDescription;
    const char*          lyrics;

    const char*          sortName;
    const char*          sortArtist;
    const char*          sortAlbumArtist;
    const char*          sortAlbum;
    const char*          sortComposer;
    const char*          sortTVShow;

    const MP4TagArtwork* artwork;
    uint32_t             artworkCount;

    const char*          copyright;
    const char*          encodingTool;
    const char*          encodedBy;
    const char*          purchaseDate;

    const uint8_t*       podcast;
    const char*          keywords;  /* TODO: Needs testing */
    const char*          category;    

    const uint8_t*       hdVideo;
    const uint8_t*       mediaType;
    const uint8_t*       contentRating;
    const uint8_t*       gapless;

    const char*          iTunesAccount;
    const uint8_t*       iTunesAccountType;
    const uint32_t*      iTunesCountry;
    const uint32_t*      contentID;
    const uint32_t*      artistID;
    const uint64_t*      playlistID;
    const uint32_t*      genreID;
    const uint32_t*      composerID;
    const char*          xid;
} MP4Tags;

/** Allocate tags convenience structure for reading and settings tags.
 *
 *  This function allocates a new structure which represents a snapshot
 *  of all the tags therein, tracking if the tag is missing,
 *  or present and with value. It is the caller's responsibility to free
 *  the structure with MP4TagsFree().
 *
 *  @return structure with all tags missing.
 */
MP4V2_EXPORT
const MP4Tags* MP4TagsAlloc( void );

/** Fetch data from mp4 file and populate structure.
 *
 *  The tags structure and its hidden data-cache is updated to
 *  reflect the actual tags values found in the <b>hFile</b>.
 *
 *  @param tags structure to fetch (write) into.
 *  @param hFile handle of file to fetch data from.
 *
 *  @return <b>true</b> on success, <b>false</b> on failure.
 */
MP4V2_EXPORT
bool MP4TagsFetch(
    const MP4Tags* tags,
    MP4FileHandle  hFile );

/** Store data to mp4 file from structure.
 *
 *  The tags structure is pushed out to the mp4 file,
 *  adding tags if needed, removing tags if needed, and updating
 *  the values to modified tags.
 *
 *  @param tags structure to store (read) from.
 *  @param hFile handle of file to store data to.
 *
 *  @return <b>true</b> on success, <b>false</b> on failure.
 */
MP4V2_EXPORT
bool MP4TagsStore(
    const MP4Tags* tags,
    MP4FileHandle  hFile );

/** Free tags convenience structure.
 *
 *  This function frees memory associated with the structure.
 *
 *  @param tags structure to destroy.
 */
MP4V2_EXPORT
void MP4TagsFree(
    const MP4Tags* tags );

/** Accessor that indicates whether a tags structure
 * contains any metadata
 *
 * @param tags the structure to inspect
 *
 * @param hasMetadata populated with false if @p tags
 * contains no metadata, true if @p tags contains metadata
 *
 * @retval false error determining if @p tags contains
 * metadata
 *
 * @retval true successfully determined if @p tags contains
 * metadata
 */
MP4V2_EXPORT
bool MP4TagsHasMetadata (
    const MP4Tags* tags,
    bool*          hasMetadata );

MP4V2_EXPORT bool MP4TagsSetName              ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetArtist            ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetAlbumArtist       ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetAlbum             ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetGrouping          ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetComposer          ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetComments          ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetGenre             ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetGenreType         ( const MP4Tags*, const uint16_t* );
MP4V2_EXPORT bool MP4TagsSetReleaseDate       ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetTrack             ( const MP4Tags*, const MP4TagTrack* );
MP4V2_EXPORT bool MP4TagsSetDisk              ( const MP4Tags*, const MP4TagDisk* );
MP4V2_EXPORT bool MP4TagsSetTempo             ( const MP4Tags*, const uint16_t* );
MP4V2_EXPORT bool MP4TagsSetCompilation       ( const MP4Tags*, const uint8_t* );

MP4V2_EXPORT bool MP4TagsSetTVShow            ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetTVNetwork         ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetTVEpisodeID       ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetTVSeason          ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetTVEpisode         ( const MP4Tags*, const uint32_t* );

MP4V2_EXPORT bool MP4TagsSetDescription       ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetLongDescription   ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetLyrics            ( const MP4Tags*, const char* );

MP4V2_EXPORT bool MP4TagsSetSortName          ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetSortArtist        ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetSortAlbumArtist   ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetSortAlbum         ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetSortComposer      ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetSortTVShow        ( const MP4Tags*, const char* );

MP4V2_EXPORT bool MP4TagsAddArtwork           ( const MP4Tags*, MP4TagArtwork* );
MP4V2_EXPORT bool MP4TagsSetArtwork           ( const MP4Tags*, uint32_t, MP4TagArtwork* );
MP4V2_EXPORT bool MP4TagsRemoveArtwork        ( const MP4Tags*, uint32_t );

MP4V2_EXPORT bool MP4TagsSetCopyright         ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetEncodingTool      ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetEncodedBy         ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetPurchaseDate      ( const MP4Tags*, const char* );

MP4V2_EXPORT bool MP4TagsSetPodcast           ( const MP4Tags*, const uint8_t* );
MP4V2_EXPORT bool MP4TagsSetKeywords          ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetCategory          ( const MP4Tags*, const char* );

MP4V2_EXPORT bool MP4TagsSetHDVideo           ( const MP4Tags*, const uint8_t* );
MP4V2_EXPORT bool MP4TagsSetMediaType         ( const MP4Tags*, const uint8_t* );
MP4V2_EXPORT bool MP4TagsSetContentRating     ( const MP4Tags*, const uint8_t* );
MP4V2_EXPORT bool MP4TagsSetGapless           ( const MP4Tags*, const uint8_t* );

MP4V2_EXPORT bool MP4TagsSetITunesAccount     ( const MP4Tags*, const char* );
MP4V2_EXPORT bool MP4TagsSetITunesAccountType ( const MP4Tags*, const uint8_t* );
MP4V2_EXPORT bool MP4TagsSetITunesCountry     ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetContentID         ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetArtistID          ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetPlaylistID        ( const MP4Tags*, const uint64_t* );
MP4V2_EXPORT bool MP4TagsSetGenreID           ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetComposerID        ( const MP4Tags*, const uint32_t* );
MP4V2_EXPORT bool MP4TagsSetXID               ( const MP4Tags*, const char* );

/** @} ***********************************************************************/

#endif /* MP4V2_ITMF_TAGS_H */
