/// <summary>
        ///    Gets a specified lyrics frame from the specified tag,
        ///    trying to to match the description and language but
        ///    accepting an incomplete match.
        /// </summary>
        /// <param name="tag">
        ///    A <see cref="Tag" /> object to search in.
        /// </param>
        /// <param name="description">
        ///    A <see cref="string" /> object specifying the description
        ///    to match.
        /// </param>
        /// <param name="language">
        ///    A <see cref="string" /> object specifying the ISO-639-2
        ///    language code to match.
        /// </param>
        /// <param name="type">
        ///    A <see cref="SynchedTextType" /> value specifying the
        ///    text type to match.
        /// </param>
        /// <returns>
        ///    A <see cref="SynchronisedLyricsFrame" /> object
        ///    containing the matching frame, or <see langword="null" />
        ///    if a match wasn't found.
        /// </returns>
        /// <remarks>
        ///    <para>The method tries matching with the following order
        ///    of precidence:</para>
        ///    <list type="number">
        ///       <item><term>The first frame with a matching
        ///       description, language, and type.</term></item>
        ///       <item><term>The first frame with a matching
        ///       description and language.</term></item>
        ///       <item><term>The first frame with a matching
        ///       language.</term></item>
        ///       <item><term>The first frame with a matching
        ///       description.</term></item>
        ///       <item><term>The first frame with a matching
        ///       type.</term></item>
        ///       <item><term>The first frame.</term></item>
        ///    </list>
        /// </remarks>
        public static SynchronisedLyricsFrame GetPreferred(Tag tag,
                                                           string description,
                                                           string language,
                                                           SynchedTextType type)
        {
            // This is weird, so bear with me. The best thing we can
            // have is something straightforward and in our own
            // language. If it has a description, then it is
            // probably used for something other than an actual
            // comment. If that doesn't work, we'd still rather have
            // something in our language than something in another.
            // After that all we have left are things in other
            // languages, so we'd rather have one with actual
            // content, so we try to get one with no description
            // first.

            int best_value = -1;
            SynchronisedLyricsFrame best_frame = null;

            foreach (Frame f in tag)
            {
                SynchronisedLyricsFrame cf =
                    f as SynchronisedLyricsFrame;

                if (cf == null)
                {
                    continue;
                }

                int value = 0;
                if (cf.Language == language)
                {
                    value += 4;
                }
                if (cf.Description == description)
                {
                    value += 2;
                }
                if (cf.Type == type)
                {
                    value += 1;
                }

                if (value == 7)
                {
                    return(cf);
                }

                if (value <= best_value)
                {
                    continue;
                }

                best_value = value;
                best_frame = cf;
            }

            return(best_frame);
        }
        /// <summary>
        ///    Creates a deep copy of the current instance.
        /// </summary>
        /// <returns>
        ///    A new <see cref="Frame" /> object identical to the
        ///    current instance.
        /// </returns>
        public override Frame Clone()
        {
            SynchronisedLyricsFrame frame =
                new SynchronisedLyricsFrame(description,
                                            language, lyrics_type, encoding);

            frame.timestamp_format = timestamp_format;
            frame.text             = (SynchedText[])text.Clone();
            return(frame);
        }
        /// <summary>
        ///    Gets a specified lyrics frame from the specified tag,
        ///    optionally creating it if it does not exist.
        /// </summary>
        /// <param name="tag">
        ///    A <see cref="Tag" /> object to search in.
        /// </param>
        /// <param name="description">
        ///    A <see cref="string" /> object specifying the description
        ///    to match.
        /// </param>
        /// <param name="language">
        ///    A <see cref="string" /> object specifying the ISO-639-2
        ///    language code to match.
        /// </param>
        /// <param name="type">
        ///    A <see cref="SynchedTextType" /> value specifying the
        ///    text type to match.
        /// </param>
        /// <param name="create">
        ///    A <see cref="bool" /> specifying whether or not to create
        ///    and add a new frame to the tag if a match is not found.
        /// </param>
        /// <returns>
        ///    A <see cref="SynchronisedLyricsFrame" /> object
        ///    containing the matching frame, or <see langword="null" />
        ///    if a match wasn't found and <paramref name="create" /> is
        ///    <see langword="false" />.
        /// </returns>
        public static SynchronisedLyricsFrame Get(Tag tag,
                                                  string description,
                                                  string language,
                                                  SynchedTextType type,
                                                  bool create)
        {
            foreach (Frame f in tag)
            {
                SynchronisedLyricsFrame lyr =
                    f as SynchronisedLyricsFrame;

                if (lyr == null)
                {
                    continue;
                }

                if (lyr.Description == description &&
                    (language == null ||
                     language == lyr.Language) &&
                    type == lyr.Type)
                {
                    return(lyr);
                }
            }

            if (!create)
            {
                return(null);
            }

            SynchronisedLyricsFrame frame =
                new SynchronisedLyricsFrame(description,
                                            language, type);

            tag.AddFrame(frame);
            return(frame);
        }