/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library 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 this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H
#define TAGLIB_TEXTIDENTIFICATIONFRAME_H

#include "tstringlist.h"
#include "tmap.h"
#include "taglib_export.h"
#include "id3v2frame.h"

namespace TagLib {

  namespace ID3v2 {

    class Tag;
    using KeyConversionMap = Map<String, String>;

    //! An ID3v2 text identification frame implementation

    /*!
     * This is an implementation of the most common type of ID3v2 frame -- text
     * identification frames.  There are a number of variations on this.  Those
     * enumerated in the ID3v2.4 standard are:
     *
     * %Frame | Description
     * :----: | :-----------------------------------------------
     *  TALB  | Album/Movie/Show title
     *  TBPM  | BPM (beats per minute)
     *  TCOM  | Composer
     *  TCON  | Content type
     *  TCOP  | Copyright message
     *  TDEN  | Encoding time
     *  TDLY  | Playlist delay
     *  TDOR  | Original release time
     *  TDRC  | Recording time
     *  TDRL  | Release time
     *  TDTG  | Tagging time
     *  TENC  | Encoded by
     *  TEXT  | Lyricist/Text writer
     *  TFLT  | %File type
     *  TIPL  | Involved people list
     *  TIT1  | Content group description
     *  TIT2  | Title/songname/content description
     *  TIT3  | Subtitle/Description refinement
     *  TKEY  | Initial key
     *  TLAN  | Language(s)
     *  TLEN  | Length
     *  TMCL  | Musician credits list
     *  TMED  | Media type
     *  TMOO  | Mood
     *  TOAL  | Original album/movie/show title
     *  TOFN  | Original filename
     *  TOLY  | Original lyricist(s)/text writer(s)
     *  TOPE  | Original artist(s)/performer(s)
     *  TOWN  | %File owner/licensee
     *  TPE1  | Lead performer(s)/Soloist(s)
     *  TPE2  | Band/orchestra/accompaniment
     *  TPE3  | Conductor/performer refinement
     *  TPE4  | Interpreted, remixed, or otherwise modified by
     *  TPOS  | Part of a set
     *  TPRO  | Produced notice
     *  TPUB  | Publisher
     *  TRCK  | Track number/Position in set
     *  TRSN  | Internet radio station name
     *  TRSO  | Internet radio station owner
     *  TSOA  | Album sort order
     *  TSOP  | Performer sort order
     *  TSOT  | Title sort order
     *  TSRC  | ISRC (international standard recording code)
     *  TSSE  | Software/Hardware and settings used for encoding
     *  TSST  | Set subtitle
     * </ul>
     *
     * The ID3v2 Frames document gives a description of each of these formats
     * and the expected order of strings in each.  ID3v2::Header::frameID() can
     * be used to determine the frame type.
     *
     * \note If non-Latin1 compatible strings are used with this class, even if
     * the text encoding is set to Latin1, the frame will be written using UTF8
     * (with the encoding flag appropriately set in the output).
     */

    class TAGLIB_EXPORT TextIdentificationFrame : public Frame
    {
      friend class FrameFactory;

    public:
      /*!
       * Construct an empty frame of type \a type.  Uses \a encoding as the
       * default text encoding.
       *
       * \note In this case you must specify the text encoding as it
       * resolves the ambiguity between constructors.
       *
       * \note Please see the note in the class description regarding Latin1.
       */
      TextIdentificationFrame(const ByteVector &type, String::Type encoding);

      /*!
       * This is a dual purpose constructor.  \a data can either be binary data
       * that should be parsed or (at a minimum) the frame ID.
       */
      explicit TextIdentificationFrame(const ByteVector &data);

      /*!
       * This is a special factory method to create a TIPL (involved people list)
       * frame from the given \a properties. Will parse key=[list of values] data
       * into the TIPL format as specified in the ID3 standard.
       */
      static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);

      /*!
       * This is a special factory method to create a TMCL (musician credits list)
       * frame from the given \a properties. Will parse key=[list of values] data
       * into the TMCL format as specified in the ID3 standard, where key should be
       * of the form instrumentPrefix:instrument.
       */
      static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
      /*!
       * Destroys this TextIdentificationFrame instance.
       */
      ~TextIdentificationFrame() override;

      TextIdentificationFrame(const TextIdentificationFrame &) = delete;
      TextIdentificationFrame &operator=(const TextIdentificationFrame &) = delete;

      /*!
       * Text identification frames are a list of string fields.
       *
       * This function will accept either a StringList or a String (using the
       * StringList constructor that accepts a single String).
       *
       * \note This will not change the text encoding of the frame even if the
       * strings passed in are not of the same encoding.  Please use
       * setEncoding(s.type()) if you wish to change the encoding of the frame.
       */
      void setText(const StringList &l);

      // Reimplementations.

      void setText(const String &s) override;
      String toString() const override;
      StringList toStringList() const override;

      /*!
       * Returns the text encoding that will be used in rendering this frame.
       * This defaults to the type that was either specified in the constructor
       * or read from the frame when parsed.
       *
       * \note Please see the note in the class description regarding Latin1.
       *
       * \see setTextEncoding()
       * \see render()
       */
      String::Type textEncoding() const;

      /*!
       * Sets the text encoding to be used when rendering this frame to
       * \a encoding.
       *
       * \note Please see the note in the class description regarding Latin1.
       *
       * \see textEncoding()
       * \see render()
       */
      void setTextEncoding(String::Type encoding);

      /*!
       * Returns a list of the strings in this frame.
       */
      StringList fieldList() const;

      /*!
       * Returns a KeyConversionMap mapping a role as it would be  used in a PropertyMap
       * to the corresponding key used in a TIPL ID3 frame to describe that role.
       */
      static const KeyConversionMap &involvedPeopleMap();

      PropertyMap asProperties() const override;

    protected:
      // Reimplementations.

      void parseFields(const ByteVector &data) override;
      ByteVector renderFields() const override;

      /*!
       * The constructor used by the FrameFactory.
       */
      TextIdentificationFrame(const ByteVector &data, Header *h);

    private:
      /*!
       * Parses the special structure of a TIPL frame
       * Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
       * "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
       */
      PropertyMap makeTIPLProperties() const;
      /*!
       * Parses the special structure of a TMCL frame.
       */
      PropertyMap makeTMCLProperties() const;
      class TextIdentificationFramePrivate;
      TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
      std::unique_ptr<TextIdentificationFramePrivate> d;
    };

    /*!
     * This is a specialization of text identification frames that allows for
     * user defined entries.  Each entry has a description in addition to the
     * normal list of fields that a text identification frame has.
     *
     * This description identifies the frame and must be unique.
     */

    //! An ID3v2 custom text identification frame implementation

    class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
    {
      friend class FrameFactory;

    public:
      /*!
       * Constructs an empty user defined text identification frame.  For this to be
       * a useful frame both a description and text must be set.
       */
      explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1);

      /*!
       * Creates a frame based on \a data.
       */
      explicit UserTextIdentificationFrame(const ByteVector &data);

      /*!
       * Creates a user defined text identification frame with the given \a description
       * and \a values.
       */
      UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);

      ~UserTextIdentificationFrame() override;

      UserTextIdentificationFrame(const UserTextIdentificationFrame &) = delete;
      UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &) = delete;

      String toString() const override;

      /*!
       * Returns the description for this frame.
       */
      String description() const;

      /*!
       * Sets the description of the frame to \a s.  \a s must be unique.  You can
       * check for the presence of another user defined text frame of the same type
       * using find() and testing for null.
       */
      void setDescription(const String &s);

      void setText(const String &text) override;
      void setText(const StringList &fields);

      /*!
       * A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
       * - the key is the frame's description, uppercased
       * - if the description contains '::', only the substring after that
       *   separator is considered as key (compatibility with exfalso)
       * - if the above rules don't yield a valid key (e.g. containing non-ASCII
       *   characters), the returned map will contain an entry "TXXX/<description>"
       *   in its unsupportedData() list.
       * - The values will be copies of the fieldList().
       * - If the description() appears as value in fieldList(), it will be omitted
       *   in the value list, in order to be compatible with TagLib which copies
       *   the description() into the fieldList().
       */
      PropertyMap asProperties() const override;

      /*!
       * Searches for the user defined text frame with the description \a description
       * in \a tag.  This returns null if no matching frames were found.
       */
      static UserTextIdentificationFrame *find(const Tag *tag, const String &description);

      /*!
       * Returns an appropriate TXXX frame description for the given free-form tag key.
       */
      static String keyToTXXX(const String &);

      /*!
       * Returns a free-form tag name for the given ID3 frame description.
       */
      static String txxxToKey(const String &);

    private:
      UserTextIdentificationFrame(const ByteVector &data, Header *h);

      void checkFields();

      class UserTextIdentificationFramePrivate;
      TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
      std::unique_ptr<UserTextIdentificationFramePrivate> d;
    };

  }  // namespace ID3v2
}  // namespace TagLib
#endif
