Click here to Skip to main content
15,887,361 members
Articles / Desktop Programming / WPF

Wrap Panel Virtualization

Rate me:
Please Sign up or sign in to vote.
4.95/5 (18 votes)
2 Jan 2012CPOL2 min read 53.3K   5.6K   41  
WrapPanel doesn't support virtualization. But we can improve the performance by simulating virtualization.
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
using Tags.ID3.ID3v2Frames.OtherFrames;

/*
 * This namespace contain frames that their base information is text(string)
 */
namespace Tags.ID3.ID3v2Frames.TextFrames
{
    /// <summary>
    /// A class for frame that only include Text member
    /// </summary> 
    public abstract class TextOnlyFrame : Frame
    {
        private string _Text; // Contain text of current frame

        /// <summary>
        /// Create new TextOnlyFrame
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">Flags of current frame</param>
        protected TextOnlyFrame(string FrameID, FrameFlags Flags)
            : base(FrameID, Flags) { }

        /// <summary>
        /// Get or Set current TextOnlyFrame text
        /// </summary>
        public string Text
        {
            get
            { return _Text; }
            set
            { _Text = value; }
        }

        #region -> Override Methods and properties <-

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (Text == null || Text == "")
                return false;
            return true;
        }

        /// <summary>
        /// Call when frame need to write it's data to stream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            writer.WriteText(_Text, TextEncodings.Ascii, false);
        }

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            // in Ascii Encoding each character is one byte
            return Text.Length;
        }

        #endregion
    }

    /// <summary>
    /// A Class for frames that include Text with TextEncoding
    /// </summary>
    public class TextFrame : TextOnlyFrame
    {
        /*
         * Note: This class support both URL and Text frames
         * the diffrence between these two types is: URL frame don't contain
         * TextEncoding and always use Ascii as Encoding but TextFrames contain
         * URLs start with 'W' texts with 'T'
         */
        private TextEncodings _TextEncoding;

        /// <summary>
        /// Create new TextFrame Class
        /// </summary>
        /// <param name="FrameID">4 Characters frame identifier</param>
        /// <param name="Flags">Flag of frame</param>
        /// <param name="Data">FileStream to read frame data from</param>
        /// <param name="Length">Maximum length of frame</param>
        public TextFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            // If it was URL frame the TextEncoding is ascii and must not read
            if (IsUrl)
                TextEncoding = TextEncodings.Ascii;
            else
            {
                TextEncoding = (TextEncodings)Data.ReadByte();
                Length--;
                if (!IsValidEnumValue(TextEncoding, ExceptionLevels.Error, FrameID))
                    return;
            }

            Text = Data.ReadText(Length, _TextEncoding);
        }

        /// <summary>
        /// Create new TextFrame with specific information
        /// </summary>
        /// <param name="Text">Text of TextFrame</param>
        /// <param name="TextEncoding">TextEncoding of TextFrame</param>
        /// <param name="FrameID">FrameID of TextFrame</param>
        /// <param name="Flags">Flags of Frame</param>
        /// <param name="Ver">Minor version of ID3v2</param>
        public TextFrame(string FrameID, FrameFlags Flags, string Text, TextEncodings TextEncoding,
            int Ver)
            : base(FrameID, Flags)
        {
            if (FramesInfo.IsTextFrame(FrameID, Ver) != 1)
                throw (new ArgumentException(FrameID + " is not valid TextFrame FrameID"));

            this.Text = Text;
            this.TextEncoding = TextEncoding;
        }

        /// <summary>
        /// Create new TextFrame for inherited classes
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">Frame Falgs</param>
        protected TextFrame(string FrameID, FrameFlags Flags)
            : base(FrameID, Flags) { }

        /// <summary>
        /// Get or Set current frame TextEncoding
        /// </summary>
        public TextEncodings TextEncoding
        {
            get
            { return _TextEncoding; }
            set
            {
                if (IsValidEnumValue(value, ExceptionLevels.Error, FrameID))
                    _TextEncoding = value;
            }
        }

        #region -> Override method and properties <-

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            if (!IsUrl)
            {
                if (ID3v2.AutoTextEncoding)
                    SetEncoding();

                writer.WriteByte((byte)_TextEncoding); // Write Text Encoding
                writer.WriteText(Text, _TextEncoding, false); // Write Text
            }
            else
                writer.WriteText(Text, TextEncodings.Ascii, false);
        }

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            // 1: Encoding (Url Frames don't contain this
            // TextLength ( Ascii Or Unicode )
            // this frame don't contain text seprator
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            if (IsUrl)
                return GetTextLength(Text, TextEncodings.Ascii, false);
            else
                return (1 + GetTextLength(Text, _TextEncoding, false));

        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            // if TextEncoding and Text value is valid this frame is valid
            // otherwise not
            if (!IsValidEnumValue(_TextEncoding) ||
                Text == null || Text == "")
                return false;
            return true;
        }

        /// <summary>
        /// Set TextEncoding according to Data of current frame
        /// </summary>
        private void SetEncoding()
        {
            if (StaticMethods.IsAscii(Text))
                TextEncoding = TextEncodings.Ascii;
            else
                TextEncoding = ID3v2.DefaultUnicodeEncoding;

        }

        #endregion

        /// <summary>
        /// Determined if specific object is equal to current frame
        /// </summary>
        /// <param name="obj">Object to compare with current object</param>
        /// <returns>true if objects be equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            // if FrameID of two text frames were equal they are equal
            // ( the text is not important )
            return (this.FrameID == ((TextFrame)obj).FrameID);
        }

        /// <summary>
        /// Serves as hash function for particular type
        /// </summary>
        /// <returns>Hash for current frame</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Indicate if current frame contain URL information
        /// </summary>
        protected bool IsUrl
        {
            get
            {
                // first character of URL frames always is 'W'
                return (FrameID[0] == 'W');
            }
        }
    }

    /// <summary>
    /// A Class for frames that include Rating, Counter, Email
    /// </summary>
    public class PopularimeterFrame : TextOnlyFrame
    {
        private long _Counter;
        private byte _Rating;

        /// <summary>
        /// New PopularimeterFrame
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">4 Characters tag identifier</param>
        /// <param name="Data">TagStream contain frame data</param>
        /// <param name="Length">Maximum available length for current frame in TagStream</param>
        public PopularimeterFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            EMail = Data.ReadText(Length, TextEncodings.Ascii, ref Length, true); // Read Email Address

            _Rating = Data.ReadByte(); // Read Rating
            Length--;

            if (Length > 8)
            {
                ExceptionOccured(new ID3Exception("Counter value for Popularimeter frame is more than 8 byte." +
                    " this is not supported by this program", FrameID, ExceptionLevels.Error));
                return;
            }

            byte[] LBuf = new byte[8];
            byte[] Buf = new byte[Length];

            Data.Read(Buf, 0, Length);
            Buf.CopyTo(LBuf, 8 - Buf.Length);
            Array.Reverse(LBuf);

            _Counter = BitConverter.ToInt64(LBuf, 0);
        }

        /// <summary>
        /// New PopulariMeter frame from specific information
        /// </summary>
        /// <param name="Flags">Frame Flags</param>
        /// <param name="EMail">Email of user</param>
        /// <param name="Rating">User Rated value</param>
        /// <param name="Counter">How many times user listened to audio</param>
        public PopularimeterFrame(FrameFlags Flags, string EMail,
            byte Rating, long Counter)
            : base("POPM", Flags)
        {
            base.Text = EMail;
            _Rating = Rating;
            _Counter = Counter;
        }

        /// <summary>
        /// Get or Set Rating value for current Email Address
        /// </summary>
        public byte Rating
        {
            get
            { return _Rating; }
            set
            { _Rating = value; }
        }

        /// <summary>
        /// Get or Set Counter for current User (Mail Address)
        /// </summary>
        public long Counter
        {
            get
            { return _Counter; }
            set
            { _Counter = value; }
        }

        /// <summary>
        /// Gets or sets Email for current User
        /// </summary>
        public string EMail
        {
            get
            { return base.Text; }
            set
            { base.Text = value; }
        }

        #region -> Override method and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            return 10 + EMail.Length;
            // 1:   Rating Length
            // 1:   Seprator
            // 8:   Counter
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            writer.WriteText(EMail, TextEncodings.Ascii, true);

            writer.WriteByte(_Rating);

            byte[] Buf = BitConverter.GetBytes(_Counter);
            Array.Reverse(Buf);
            writer.Write(Buf, 0, 8);
        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (EMail != "")
                return true;

            return false;
        }

        #endregion

        /// <summary>
        /// Determines wheter the specified object is equal to current object
        /// </summary>
        /// <param name="obj">object to compare with current object</param>
        /// <returns>true if they were equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            if (((PopularimeterFrame)obj).EMail == this.EMail)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serves Hash function for particular types
        /// </summary>
        /// <returns>HashCode for current object</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// This property is not usable for this class
        /// </summary>
        public new string Text
        {
            get
            { throw (new Exception("This property is not useable for this class")); }
        }
    }

    /// <summary>
    /// A Class for frames that include Text, Encoding and Description
    /// </summary>
    public class UserTextFrame : TextFrame
    {
        private string _Description;

        /// <summary>
        /// Create new UserTextFrameClass
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">Frame Flagsr</param>
        /// <param name="Data">TagStream to read information from</param>
        /// <param name="Length">Maximum available length of data for current frame in TagStream</param>
        public UserTextFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            TextEncoding = (TextEncodings)Data.ReadByte();
            Length--;
            if (!IsValidEnumValue(TextEncoding, ExceptionLevels.Error, FrameID))
                return;

            _Description = Data.ReadText(Length, TextEncoding, ref Length, true);

            if (!IsUrl) // is text frame
                Text = Data.ReadText(Length, TextEncoding);
            else
                Text = Data.ReadText(Length, TextEncodings.Ascii);

            // User URL frames use this class and use Text property as URL
            // URL property must be in AScii format
            // all URL frames start with W and text frames with T
        }

        /// <summary>
        /// Create new UserTextFrame from specific information
        /// </summary>
        /// <param name="FrameID">FrameID of frame</param>
        /// <param name="Flags">Frame flags</param>
        /// <param name="Text">Frame text</param>
        /// <param name="Description">Frame description</param>
        /// <param name="TextEncoding">TextEncoding of texts</param>
        /// <param name="Ver">Minor version of ID3v2</param>
        public UserTextFrame(string FrameID, FrameFlags Flags, string Text,
            string Description, TextEncodings TextEncoding, int Ver)
            : base(FrameID, Flags)
        {
            if (FramesInfo.IsTextFrame(FrameID, Ver) != 2)
                throw (new ArgumentException(FrameID + " is not valid for UserTextFrame class"));

            this.Text = Text;
            this.TextEncoding = TextEncoding;
            this.Description = Description;
        }

        /// <summary>
        /// Create new UserTextFrame without set any default value
        /// </summary>
        /// <param name="FrameID">4 character frame identifier for current frame</param>
        /// <param name="Flags">Frame Flags</param>
        protected UserTextFrame(string FrameID, FrameFlags Flags)
            : base(FrameID, Flags) { }

        /// <summary>
        /// Get/Set current frame Description
        /// </summary>
        public string Description
        {
            set
            {
                if (value == null)
                    throw (new ArgumentException("Description can't be null"));

                _Description = value;
            }
            get
            { return _Description; }
        }

        #region -> Override Method and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            // TextLength
            // Description Length ( + seprator )
            // 1: Encoding
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            int TextLen;

            if (!IsUrl)
                TextLen = GetTextLength(Text, TextEncoding, false);
            else
                TextLen = GetTextLength(Text, TextEncodings.Ascii, false); ;

            return 1 + TextLen + GetTextLength(_Description, TextEncoding, true);
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            writer.WriteByte((byte)TextEncoding); // Write Encoding

            writer.WriteText(_Description, TextEncoding, true);

            if (!IsUrl)
                writer.WriteText(Text, TextEncoding, false);
            else // URL frames always use ascii encoding for text value
                writer.WriteText(Text, TextEncodings.Ascii, false);
        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if ((_Description != "" || Text != "") && IsValidEnumValue(TextEncoding))
                return true;

            return false;
        }

        private void SetEncoding()
        {
            if (StaticMethods.IsAscii(Text) && StaticMethods.IsAscii(Description))
                TextEncoding = TextEncodings.Ascii;
            else
                TextEncoding = ID3v2.DefaultUnicodeEncoding;
        }

        #endregion

        /// <summary>
        /// Determines wheter the specified object is equal to current object
        /// </summary>
        /// <param name="obj">object to compare with current object</param>
        /// <returns>true if they were equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            if (this.FrameID == ((UserTextFrame)obj).FrameID
                && this._Description == ((UserTextFrame)obj)._Description)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serves Hash function for particular types
        /// </summary>
        /// <returns>HashCode for current object</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    /// <summary>
    /// A Class for frames that include Text, Encoding and Language
    /// </summary>
    public class TermOfUseFrame : TextFrame
    {
        private Language _Language;

        /// <summary>
        /// Create new TermOfUseFrame class
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">2 Bytes flags identifier</param>
        /// <param name="Data">TagStream to read data from</param>
        /// <param name="Length">Maximum available length for current frame is TagStream</param>
        public TermOfUseFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            TextEncoding = (TextEncodings)Data.ReadByte();
            Length--;
            if (!IsValidEnumValue(TextEncoding, ExceptionLevels.Error, FrameID))
                return;

            _Language = new Language(Data);
            Length -= 3;

            Text = Data.ReadText(Length, TextEncoding);
        }

        /// <summary>
        /// Create new TermOfUseFrame with specific information
        /// </summary>
        /// <param name="Flags">Frame Flags</param>
        /// <param name="Text">Text of current frame</param>
        /// <param name="TextEncoding">Encoding of text</param>
        /// <param name="Lang">Language that text wrote in</param>
        public TermOfUseFrame(FrameFlags Flags, string Text,
            TextEncodings TextEncoding, string Lang)
            : base("USER", Flags)
        {
            this.Text = Text;
            this.TextEncoding = TextEncoding;
            Language = new Language(Lang);
        }

        /// <summary>
        /// Create new empty TermOfUseFrame
        /// </summary>
        /// <param name="FrameID">4 character frame identifier</param>
        /// <param name="Flags">Frame Flags</param>
        protected TermOfUseFrame(string FrameID, FrameFlags Flags)
            : base(FrameID, Flags) { }

        /// <summary>
        /// Gets or sets language of current frame
        /// </summary>
        public Language Language
        {
            get
            { return _Language; }
            set
            { _Language = value; }
        }

        #region -> Override method's and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            // 3: Language Length
            return (base.OnGetLength() + 3);
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            writer.WriteByte((byte)TextEncoding); // Write Text Encoding

            _Language.Write(writer);

            writer.WriteText(Text, TextEncoding, false);
        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (base.IsValid == false)
                return false;

            return _Language.IsValidLanguage;
        }

        private void SetEncoding()
        {
            if (StaticMethods.IsAscii(Text))
                TextEncoding = TextEncodings.Ascii;
            else
                TextEncoding = ID3v2.DefaultUnicodeEncoding;
        }

        #endregion

        /// <summary>
        /// Determines wheter the specified object is equal to current object
        /// </summary>
        /// <param name="obj">object to compare with current object</param>
        /// <returns>true if they were equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            if (((TermOfUseFrame)obj)._Language == this._Language &&
                ((TermOfUseFrame)obj).FrameID == this.FrameID)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serves Hash function for particular types
        /// </summary>
        /// <returns>HashCode for current object</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Convert current object to string
        /// </summary>
        /// <returns>String contain converted of current object</returns>
        public override string ToString()
        {
            return "Term of use [" + _Language + "]";
        }
    }

    /// <summary>
    /// A Class for frames that include PricePayed, DateOfPurch, TextEncoding, Text(Seller)
    /// </summary>
    public class OwnershipFrame : TextFrame
    {
        // Inherits:
        //      Text
        //      Encoding
        private Price _Price;
        private SDate _DateOfPurch;

        /// <summary>
        /// Create new OwnershipFrame
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">2 Bytes flags identifier</param>
        /// <param name="Data">TagStream to read data from</param>
        /// <param name="Length">Maximum available length for current frame is TagStream</param>
        public OwnershipFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            TextEncoding = (TextEncodings)Data.ReadByte();
            Length--;
            if (!IsValidEnumValue(TextEncoding, ExceptionLevels.Error, FrameID))
                return;

            _Price = new Price(Data, Length);
            Length -= _Price.Length;
            if (!_Price.IsValid)
            {
                ExceptionOccured(new ID3Exception("Price is not valid value. ownership frame will not read", FrameID, ExceptionLevels.Error));
                return;
            }

            if (Length >= 8)
            {
                _DateOfPurch = new SDate(Data);
                Length -= 8;
            }
            else
            {
                ExceptionOccured(new ID3Exception("Date is not valid for this frame", FrameID, ExceptionLevels.Error));
                return;
            }

            Seller = Data.ReadText(Length, TextEncoding);
        }

        /// <summary>
        /// Create new Ownership from specific information
        /// </summary>
        /// <param name="Flags">Frame Flags</param>
        /// <param name="PricePayed">Price payed for file</param>
        /// <param name="PurchDate">Purch date of file</param>
        /// <param name="Seller">Name of seller</param>
        /// <param name="TEncoding">Tex Encoding to use for text</param>
        public OwnershipFrame(FrameFlags Flags, Price PricePayed, SDate PurchDate,
            string Seller, TextEncodings TEncoding)
            : base("OWNE", Flags)
        {
            _Price = PricePayed;
            _DateOfPurch = PurchDate;
            this.Seller = Seller;
        }

        /// <summary>
        /// Get/Set DateOfPurch for current frame
        /// </summary>
        public SDate DateOfPurch
        {
            get
            { return _DateOfPurch; }
            set
            { _DateOfPurch = value; }
        }

        /// <summary>
        /// Get price of current frame
        /// </summary>
        public Price Price
        {
            get
            {
                return _Price;
            }
        }

        #region -> Override method and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            // base.OnGetLength(): 10(Header) + 1(Encoding) + Text.Length(According to encoding)
            // Price.Length + 8(Date) + 1(Seprator of Price)
            return (base.OnGetLength() + _Price.Length) + 9;
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            writer.WriteByte((byte)TextEncoding); // Write Text Encoding

            writer.WriteText(_Price.ToString(), TextEncodings.Ascii, true);

            writer.WriteText(_DateOfPurch.String, TextEncodings.Ascii, false);

            writer.WriteText(Seller, TextEncoding, false);
        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (_DateOfPurch == null && _Price == null)
                return false;

            return base.OnValidating();
        }

        private void SetEncoding()
        {
            if (StaticMethods.IsAscii(Seller))
                TextEncoding = TextEncodings.Ascii;
            else
                TextEncoding = ID3v2.DefaultUnicodeEncoding;
        }

        #endregion

        /// <summary>
        /// This property is not available for Ownership
        /// </summary>
        public new string Text
        {
            get
            {
                throw (new InvalidOperationException("This property not available for Ownership"));
            }
        }

        /// <summary>
        /// Get/Set Current frame seller
        /// </summary>
        public string Seller
        {
            get
            { return base.Text; }
            set
            {
                base.Text = value;
                // Base.Text control the value for null
            }
        }
    }

    /// <summary>
    /// A Class for frames that include FrameIdentifier, URL, AdditionalData
    /// </summary>
    public class LinkFrame : TextFrame
    {
        private string _FrameIdentifier;
        private string _AdditionalData;

        /// <summary>
        /// Create new LinkFrame
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">2 Bytes flags identifier</param>
        /// <param name="Data">Contain Data for this frame</param>
        /// <param name="Length"></param>
        public LinkFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            _FrameIdentifier = Data.ReadText(4, TextEncodings.Ascii);
            if (!ValidatingFrameID(_FrameIdentifier, ExceptionLevels.Warning))
                return;
            Length -= 4;
            // There is 3 byte in article that i think it's not true
            // because frame identifier is 4 character

            // use Text variable as URL
            URL = Data.ReadText(Length, TextEncodings.Ascii, ref Length, true);

            _AdditionalData = Data.ReadText(Length, TextEncodings.Ascii);
        }

        /// <summary>
        /// New LinkedFrame from specific information
        /// </summary>
        /// <param name="Flags">Frame Flags</param>
        /// <param name="FrameIdentifier">FrameIdentifier of frame that linked</param>
        /// <param name="URL">URL address of Linked Frame</param>
        /// <param name="AdditionalData">Additional data of Linked Frame</param>
        public LinkFrame(FrameFlags Flags, string FrameIdentifier,
            string URL, string AdditionalData)
            : base("LINK", Flags)
        {
            this.URL = URL;
            _AdditionalData = AdditionalData;

            // Check if FrameIdentifier is valid
            ValidatingFrameID(FrameIdentifier, ExceptionLevels.Warning);

            _FrameIdentifier = FrameIdentifier;
        }

        /// <summary>
        /// URL of current Link Frame
        /// </summary>
        public string URL
        {
            get
            { return base.Text; }
            set
            {
                // Check for null value (base.Text check it)
                base.Text = value;
            }
        }

        /// <summary>
        /// Get/Set Additional Data of Current Frame
        /// </summary>
        public string AdditionalData
        {
            get
            { return _AdditionalData; }
            set
            { _AdditionalData = value; }
        }

        /// <summary>
        /// Frame Identifier of Linked Frame
        /// </summary>
        public string FrameIdentifier
        {
            get
            { return _FrameIdentifier; }
            set
            {
                if (ValidatingFrameID(value, ExceptionLevels.Warning))
                    _FrameIdentifier = value;
            }
        }

        #region -> Override Method and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            // 4: FrameIdentifier
            // 1: Seprator
            return 5 + URL.Length + _AdditionalData.Length;
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            writer.WriteText(_FrameIdentifier, TextEncodings.Ascii, false);

            writer.WriteText(URL, TextEncodings.Ascii, true); // Write URL

            writer.WriteText(_AdditionalData, TextEncodings.Ascii, false);
        }

        /// <summary>
        /// Indicate if current frame data is valid
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (_FrameIdentifier == "")
                return false;

            return true;
        }

        /// <summary>
        /// Determines wheter the specified object is equal to current object
        /// </summary>
        /// <param name="obj">object to compare with current object</param>
        /// <returns>true if they were equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            if (((LinkFrame)obj)._FrameIdentifier == this._FrameIdentifier)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serves Hash function for particular types
        /// </summary>
        /// <returns>HashCode for current object</returns>
        public override int GetHashCode() { return base.GetHashCode(); }

        #endregion

        /// <summary>
        /// This property is not Available for current class
        /// </summary>
        public new TextEncodings TextEncoding
        {
            get
            { return TextEncodings.Ascii; }
        }

        /// <summary>
        /// This property is not Available for current class
        /// </summary>
        public new string Text
        {
            get
            { throw (new Exception("This property is not available for current class")); }
        }
    }

    /// <summary>
    /// A Class for frames that include Text, Description, Encoding and Language
    /// </summary>
    public class TextWithLanguageFrame : UserTextFrame
    {
        private Language _Language;

        /// <summary>
        /// Create new TextWithLanguageFrame
        /// </summary>
        /// <param name="FrameID">4 Characters tag identifier</param>
        /// <param name="Flags">2 Bytes flags identifier</param>
        /// <param name="Data">TagStream contains frame data</param>
        /// <param name="Length">Maximum available length for current frame is TagStream</param>
        public TextWithLanguageFrame(string FrameID, FrameFlags Flags, TagStream Data, int Length)
            : base(FrameID, Flags)
        {
            TextEncoding = (TextEncodings)Data.ReadByte();
            Length--;
            if (!IsValidEnumValue(TextEncoding, ExceptionLevels.Error, FrameID))
                return;

            _Language = new Language(Data);
            Length -= 3;

            Description = Data.ReadText(Length, TextEncoding, ref Length, true);

            Text = Data.ReadText(Length, TextEncoding);
        }

        /// <summary>
        /// Create new TextWithLanguageFrame from specific information
        /// </summary>
        /// <param name="FrameID">4 character frame identifer for current frame</param>
        /// <param name="Flags">Frame Flags</param>
        /// <param name="Text">Text of current frame</param>
        /// <param name="Description">Description of current frame</param>
        /// <param name="TextEncoding">Text Encoding used for current frame</param>
        /// <param name="Lang">Language used for text of current frame</param>
        public TextWithLanguageFrame(string FrameID, FrameFlags Flags, string Text,
            string Description, TextEncodings TextEncoding, string Lang)
            : base(FrameID, Flags)
        {
            if (FrameID != "USLT" && FrameID != "COMM")
                throw (new ArgumentException(FrameID + " is not valid Frame for TextWithLanguageFrame"));

            Language = new Language(Lang);
            this.Text = Text;
            this.Description = Description;
            this.TextEncoding = TextEncoding;
        }

        /// <summary>
        /// Get/Set current frame Language 
        /// </summary>
        public Language Language
        {
            get
            { return _Language; }
            set
            { _Language = value; }
        }

        #region -> Override method and properties <-

        /// <summary>
        /// Gets length of current frame in byte
        /// </summary>
        /// <returns>int contain length of current frame</returns>
        protected override int OnGetLength()
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            // 3: Language Length
            return (base.OnGetLength() + 3);
        }

        /// <summary>
        /// Writing Data to specific TagStream
        /// </summary>
        /// <param name="writer">TagStream to write data</param>
        /// <param name="MinorVersion">ID3 minor version</param>
        protected override void OnWritingData(TagStream writer, int MinorVersion)
        {
            if (ID3v2.AutoTextEncoding)
                SetEncoding();

            writer.WriteByte((byte)TextEncoding); // Write Text Encoding

            _Language.Write(writer);

            writer.WriteText(Description, TextEncoding, true);

            writer.WriteText(Text, TextEncoding, false);
        }

        /// <summary>
        /// Occur when want to validate frame information
        /// </summary>
        /// <returns>true if was valid frame otherwise false</returns>
        protected override bool OnValidating()
        {
            if (IsValidEnumValue(TextEncoding) &&
                    (Text != "" || Description != ""))
                return true;
            else
                return false;
        }

        private void SetEncoding()
        {
            if (StaticMethods.IsAscii(Text) && StaticMethods.IsAscii(Description))
                TextEncoding = TextEncodings.Ascii;
            else
                TextEncoding = ID3v2.DefaultUnicodeEncoding;
        }

        #endregion

        /// <summary>
        /// Determines wheter the specified object is equal to current object
        /// </summary>
        /// <param name="obj">object to compare with current object</param>
        /// <returns>true if they were equal otherwise false</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() != this.GetType())
                return false;

            if (((TextWithLanguageFrame)obj).FrameID == this.FrameID &&
                ((TextWithLanguageFrame)obj)._Language == this._Language &&
                ((TextWithLanguageFrame)obj).Description == this.Description)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serves Hash function for particular types
        /// </summary>
        /// <returns>HashCode for current object</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// convert current Frame to System.String
        /// </summary>
        /// <returns>Description [Language]</returns>
        public override string ToString()
        {
            return Description + " [" + _Language + "]";
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) KAZ Software Limited
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions