using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using IMLibrary.Controls.Toolbox.Design;

namespace IMLibrary.Controls.Toolbox
{
    partial class Toolbox
    {
        /// <summary>
        /// Represents an item in a <see cref="Toolbox"/> control.
        /// </summary>
        [Serializable]
        [ToolboxItem(false)]
        [DesignTimeVisible(false)]
        [TypeConverter(typeof(ItemConverter))]
        public class Item : IToolboxObject, ICloneable
        {
            #region Fields
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private string _text = string.Empty;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Image _image = null;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Color _foreColor = Color.White;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Color _backColor = Color.LightGray;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _enabled = true;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _visible = true;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _selected = false;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _highlighted = false;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private string _tooltip = string.Empty;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Point _location;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _renaming = false;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Color _transparentColor;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private ITab _owner;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private object _tag;
            #endregion

            #region Static members
            internal static readonly StringFormat _itemTextFormat;
            private static readonly Type DefaulValueAttributeType = typeof(DefaultValueAttribute);
            private static readonly Type StringType = typeof(string);
            private static readonly Type ColorType = typeof(Color);
            private static readonly Type ImageType = typeof(Image);
            private static Dictionary<Type, List<PropertyInfo>> _serializableProperties;

            static Item()
            {
                _itemTextFormat = new StringFormat();
                _itemTextFormat.LineAlignment = StringAlignment.Center;
                _itemTextFormat.Trimming = StringTrimming.EllipsisWord;
            }

            /// <summary>
            /// Gets the public browsable properties which could be serialized.
            /// </summary>
            private static List<PropertyInfo> GetSerializableProperties(Type type)
            {
                if (_serializableProperties == null)
                {
                    _serializableProperties = new Dictionary<Type, List<PropertyInfo>>();
                }

                List<PropertyInfo> properties;
                if (!_serializableProperties.TryGetValue(type, out properties))
                {
                    properties = new List<PropertyInfo>(type.GetProperties());
                    for (int i = properties.Count - 1; i >= 0; i--)
                    {
                        PropertyInfo pi = properties[i];
                        if (!pi.CanRead || !pi.CanWrite)
                        {
                            properties.RemoveAt(i);
                        }
                        else if (pi.IsDefined(typeof(XmlIgnoreAttribute), false))
                        {
                            properties.RemoveAt(i);
                        }
                        else if (pi.IsDefined(typeof(BrowsableAttribute), true))
                        {
                            BrowsableAttribute[] attributes = (BrowsableAttribute[])pi.GetCustomAttributes(typeof(BrowsableAttribute), true);
                            if (!attributes[0].Browsable)
                                properties.RemoveAt(i);
                        }
                    }
                    _serializableProperties.Add(type, properties);
                }
                return properties;
            }
            #endregion

            /// <summary>
            /// Initializes a new instance of the <see cref="Item"/> class with default values.
            /// </summary>
            public Item() : this(string.Empty)
            {
                
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Item"/> class with the specified item text.
            /// </summary>
            /// <param name="text">The text to display for the item.</param>
            public Item(string text) : this(text, null)
            {

            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Item"/> class with the specified item text and image.
            /// </summary>
            /// <param name="text">The text to display for the item.</param>
            /// <param name="image">The image to display for the item.</param>
            public Item(string text, Image image) : this(text, image, Color.Transparent)
            {
                
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Item"/> class with the specified item text, image and image transparency color.
            /// </summary>
            /// <param name="text">The text to display for the item.</param>
            /// <param name="image">The image to display for the item.</param>
            /// <param name="transparentColor">The transparent color for the <paramref name="image"/>.</param>
            public Item(string text, Image image, Color transparentColor)
            {
                if (string.IsNullOrEmpty(text))
                    text = "Item";
                _text = text;
                _image = image;
                _transparentColor = transparentColor;
                //IniTimer();

            }

            #region Public Properties

            /// <summary>
            /// Gets or sets the text value of the <see cref="Item"/>.
            /// </summary>
            public virtual string Text
            {
                [DebuggerStepThrough]
                get { return _text; }
                [DebuggerStepThrough]
                set 
                {
                    if (_text != value && !string.IsNullOrEmpty(value))
                    {
                        _text = value;
                    }
                }
            }

            private int _notSelectedHeight = 24;
            /// <summary>
            /// Gets or sets the Not Selected Height of the <see cref="Item">items</see>.
            /// </summary>
            [DefaultValue(20)]
            public virtual int NotSelectedHeight
            {
                set
                {
                    if (value >= 20 && _notSelectedHeight != value)
                        _notSelectedHeight = value;
                }
                get { return _notSelectedHeight; }
            }

            private int _itemHeight=24;
            /// <summary>
            /// Gets or sets the height of the <see cref="Item">items</see>.
            /// </summary>
            [DefaultValue(20)]
            public virtual int Height
            {
                [DebuggerStepThrough]
                get { return _itemHeight; }
                [DebuggerStepThrough]
                set
                {
                    if (value >= 20 && _itemHeight != value)
                    { 
                        _itemHeight = value;
                        Owner.Invalidate();
                    }
                }
            }

            /// <summary>
            /// Gets or sets the text value of the <see cref="Item"/>.
            /// </summary>
            public virtual string Remark
            {
                get;
                set;
            }
            /// <summary>
            /// Gets or sets the Signature value of the <see cref="Item"/>.
            /// </summary>
            public string Signature
            { get; set; }
            
            /// <summary>
            /// Gets or sets the Online value of the <see cref="Item"/>.
            /// </summary>
            public virtual bool IsOnline
            {
                get;
                set;
            }

            bool _HaveMessage=false;
            public bool HaveMessage
            {
                set
                {
                    if (_HaveMessage != value)
                    {
                        _HaveMessage = value;
                        //this.Toolbox.Invalidate(this.Bounds);
                    }
                }
                get { return _HaveMessage; }
            }

            private Image _SelectedNullImage = null;
            public Image SelectedNullImage
            {
                get { return _SelectedNullImage; }
            }

            private Image _NotSelectedNullImage = null;
            public Image NotSelectedNullImage
            {
                get { return _NotSelectedNullImage; }
            }

            public bool Flicker
            {
                set;
                get;
            }

            private Image _SelectedImage = null;
            [DefaultValue(typeof(Image), "null")]
            public virtual Image SelectedImage
            {
                get { return _SelectedImage; }
                set { _SelectedImage = value;
                if (value != null)
                    _SelectedNullImage = new Bitmap(value.Width, value.Height);
                }
            }

            private Image _NotSelectedImage = null;
            [DefaultValue(typeof(Image), "null")]
            public virtual Image NotSelectedImage
            {
                get { return _NotSelectedImage; }
                set { _NotSelectedImage = value;
                if (value != null)
                    _NotSelectedNullImage = new Bitmap(value.Width, value.Height);
                }
            }
 
            /// <summary>
            /// Gets or sets the image displayed for the <see cref="Item"/>.
            /// </summary>
            [DefaultValue(typeof(Image), "null")]
            public virtual Image Image
            {
                [DebuggerStepThrough]
                get { return _image; }
                [DebuggerStepThrough]
                set
                {
                    _image = value;
                }
            }

            private Enum.Status  _status  =  Enum.Status.none;
            /// <summary>
            /// Gets or sets the image displayed for the <see cref="Item"/>.
            /// </summary>
            [DefaultValue(typeof(Image), "null")]
            public virtual Enum.Status  Status 
            { 
                get { return _status  ; } 
                set
                {
                    if (_status != value)
                    {
                        _status = value;
                        switch (value)
                        {
                            case Enum.Status.none:
                                _statusImage = null;
                                break;
                            case Enum.Status.away:
                                _statusImage = Properties.Resources.away;
                                break;
                            case Enum.Status.busy:
                                _statusImage = Properties.Resources.busy;
                                break;
                            case Enum.Status.mute:
                                _statusImage = Properties.Resources.mute;
                                break;
                            case Enum.Status.Mobil:
                                _statusImage = Properties.Resources.Mobil;
                                break;
                        }

                        this.Toolbox.Invalidate(this.Bounds);
                    }
                }
            }

            private  Image _statusImage = null ;
            /// <summary>
            /// Gets or sets the image displayed for the <see cref="Item"/>.
            /// </summary>
            [DefaultValue(typeof(Image), "null")]
            public virtual Image StatusImage
            { 
                get { return _statusImage; } 
            }

            /// <summary>
            /// Gets or sets the color to treat as transparent for the <see cref="Image"/>.
            /// </summary>
            /// <value>One of the <see cref="Color"/> values. The default is <b>null</b>.</value>
            /// <remarks>The transparent color is not rendered when the image is drawn.</remarks>
            [DefaultValue(typeof(Color), "Transparent")]
            public virtual Color TransparentColor
            {
                [DebuggerStepThrough]
                get { return _transparentColor; }
                [DebuggerStepThrough]
                set { _transparentColor = value; }
            }

            /// <summary>
            /// Gets or sets the color to display the text of the <see cref="Item"/>.
            /// </summary>
            [DefaultValue(typeof(Color), "White")]
            public virtual Color ForeColor
            {
                [DebuggerStepThrough]
                get { return _foreColor; }
                [DebuggerStepThrough]
                set { _foreColor = value; }
            }

            /// <summary>
            /// Gets or sets the color of the <see cref="Item"/> background.
            /// </summary>
            [DefaultValue(typeof(Color), "LightGray")]
            public virtual Color BackColor
            {
                [DebuggerStepThrough]
                get { return _backColor; }
                [DebuggerStepThrough]
                set { _backColor = value; }
            }

            /// <summary>
            /// Gets or sets whether the <see cref="Item"/> is selectable.
            /// </summary>
            [DefaultValue(true)]
            public virtual bool Enabled
            {
                [DebuggerStepThrough]
                get { return _enabled; }
                [DebuggerStepThrough]
                set { _enabled = value; }
            }

            /// <summary>
            /// Gets or sets whether the <see cref="Item"/> is visible on the <see cref="Toolbox"/>
            /// </summary>
            [DefaultValue(true)]
            public virtual bool Visible
            {
                [DebuggerStepThrough]
                get { return _visible; }
                [DebuggerStepThrough]
                set { _visible = value; }
            }

            /// <summary>
            /// Gets or sets the tooltip text of the <see cref="Item"/>.
            /// </summary>
            [DefaultValue("")]
            public virtual string Tooltip
            {
#if DEBUG
                get { return _text; }
#else
                [DebuggerStepThrough]
                get 
                {
                    if (string.IsNullOrEmpty(_tooltip))
                    {
                        _tooltip = _text;
                    }
                    return _tooltip; 
                }
#endif
                [DebuggerStepThrough]
                set 
                {
                    if (value != null)
                    {
                        _tooltip = value;
                    }
                }
            }

            /// <summary>
            /// Gets the value indicating whether the <see cref="Item"/> is currently selected.
            /// </summary>
            [Browsable(false)]
            [DefaultValue(false)]
            public virtual bool Selected
            {
                [DebuggerStepThrough]
                get { return _selected; }
                internal set 
                {
                    if (_selected != value && Toolbox != null)
                    {
                        _selected = value;
                        Toolbox.Invalidate(this.Bounds);
                    }
                }
            }

            /// <summary>
            /// Gets the value indicating whether the <see cref="Item"/> is currently highlighted.
            /// </summary>
            [Browsable(false)]
            [DefaultValue(false)]
            public virtual bool Highlighted
            {
                [DebuggerStepThrough]
                get { return _highlighted; }
                internal set 
                {
                    if (_highlighted != value && Toolbox != null)
                    {
                        _highlighted = value;
                        Toolbox.Invalidate(this.Bounds);
                    }
                }
            }

            /// <summary>
            /// Gets the <see cref="Tab">Category</see> that contains the <see cref="Item"/>.
            /// </summary>
            [Browsable(false)]            
            internal Tab Category
            {
                [DebuggerStepThrough]
                get 
                {
                    Toolbox toolbox = _owner as Toolbox;
                    if (toolbox != null)
                    {
                        if (toolbox.AllowToolboxItems)
                            return null;
                        else
                            return toolbox.GetToolboxItemsTab(true);
                    }
                    return _owner as Tab; 
                }
            }

            /// <summary>
            /// Gets the <see cref="Toolbox"/> that contains the <see cref="Item"/>.
            /// </summary>
            [Browsable(false)]
            public Toolbox Toolbox
            {
                get 
                {
                    Tab tab = _owner as Tab;
                    if (tab != null)
                        return tab.Toolbox;
                    return (Toolbox)_owner;
                }
            }

            /// <summary>
            /// Gets the <see cref="ITab">current</see> object that contains the <see cref="Item"/>.
            /// </summary>
            [Browsable(false)]
            public ITab Owner
            {
                [DebuggerStepThrough]
                get { return _owner; }
                [DebuggerStepThrough]
                internal set { _owner = value; }
            }

            /// <summary>
            /// Gets or sets an object that contains data to associate with the item.
            /// </summary>
            [XmlIgnore]
            public object Tag
            {
                [DebuggerStepThrough]
                get { return _tag; }
                [DebuggerStepThrough]
                set { _tag = value; }
            }
            #endregion

            #region Other Properties
            /// <summary>
            /// Gets the location of the left top point where to draw the <see cref="Item"/> on the <see cref="Toolbox"/>.
            /// </summary>
            protected internal Point Location
            {
                [DebuggerStepThrough]
                get { return _location; }
                [DebuggerStepThrough]
                private set { _location = value; }
            }

            /// <summary>
            /// Gets the width of the <see cref="Item"/> on the <see cref="Toolbox"/>.
            /// </summary>
            protected int Width
            {
                get
                {
                    if (this.Owner == null)
                        return 0;

                    Toolbox toolbox = this.Toolbox;
                    if (toolbox == null)
                        return 0;

                    int width = this.Owner.Width;
                    if (this.Owner is Toolbox)
                    {
                        width = this.Owner.VisibleRectangle.Width - 2 * Toolbox.Gap_TabBorder;
                    }
                    else if (toolbox.DrawTabLevel && (!(this.Owner is Toolbox) || !toolbox.AllowToolboxItems))
                    {
                        width -= Toolbox.Gap_TabLevel;
                    }
                    return width;
                }
            }

            /// <summary>
            /// Gets the bounds of the <see cref="Item"/> on the <see cref="Toolbox"/>.
            /// </summary>
            protected internal virtual Rectangle Bounds
            {
                get
                {
                    Toolbox toolbox = this.Toolbox;
                    if (toolbox == null)
                        return Rectangle.Empty;
                    //return new Rectangle(this.Location, new Size(this.Width, toolbox.ItemHeight));

                    return new Rectangle(this.Location, new Size(this.Width,this.Height));
                }
            }
            
            /// <summary>
            /// Gets or sets the value indicating whether the <see cref="Item"/> is currently renamed.
            /// </summary>
            protected internal bool Renaming
            {
                [DebuggerStepThrough]
                get { return _renaming; }
                set
                {
                    if (Toolbox != null)
                    {
                        _renaming = value;
                        Toolbox.Invalidate(Bounds);
                    }
                }
            }
            #endregion

            #region Public Methods
            /// <summary>
            /// Selects the <see cref="Item"/> on the <see cref="Toolbox"/>.
            /// </summary>
            public void Select()
            {
                if (Toolbox != null && Visible && Enabled)
                {
                    EnsureVisible();
                    Toolbox.SelectTool(this);
                }
            }

            /// <summary>
            /// Returns a string representation of the <see cref="Item"/>.
            /// </summary>
            /// <returns>A string that states an <see cref="Item"/> type and the its text.</returns>
            public override string ToString()
            {
                return string.Format("{0}: {1}", GetType().Name, Text);
            }

            /// <summary>
            /// Ensures that the <see cref="Item"/> is visible within the <see cref="Toolbox"/>, scrolling the contents of the <see cref="Toolbox"/> if necessary and opening the container <see cref="Tab">Category</see>.
            /// </summary>
            public void EnsureVisible()
            {
                if (Toolbox != null && Visible)
                {
                    if (Category != null)
                        Category.Opened = true;
                    Toolbox.EnsureVisible(Bounds);
                }
            }
            #endregion

            #region Protected Methods
            /// <summary>
            /// Invoked when the mouse button is pressed on the <see cref="Item"/>.
            /// </summary>
            /// <param name="e">A <see cref="System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
            protected virtual void OnMouseDown(MouseEventArgs e)
            {
            }

            /// <summary>
            /// Invoked when the mouse button is depressed on the <see cref="Item"/>. 
            /// </summary>
            /// <param name="e">A <see cref="System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
            /// <remarks>
            /// If the mouse button is <see cref="MouseButtons.Right"/> the <see cref="IMLibrary.Components.Toolbox.ItemMenu"/> is shown if available.
            /// </remarks>
            protected virtual void OnMouseUp(MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Right)
                {
                    if (Toolbox.ItemMenu != null)
                    {
                        Toolbox.ItemMenu.Tag = this;
                        Toolbox.ItemMenu.Show(Toolbox, e.Location);
                    }
                }
            }

            /// <summary>
            /// Invoked when the user clicks on the <see cref="Item"/>.
            /// </summary>
            /// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
            protected virtual void OnClick(EventArgs e)
            {
            }

            /// <summary>
            /// Invoked when the user double clicks on the <see cref="Item"/>.
            /// </summary>
            /// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
            protected virtual void OnDoubleClick(EventArgs e)
            {

            }

            /// <summary>
            /// Draws the <see cref="Item"/> on the <see cref="Toolbox"/>.
            /// </summary>
            /// <param name="e">A <see cref="PaintEventArgs"/> that contains the paint event data.</param>
            protected virtual void OnPaint(PaintEventArgs e)
            {
                bool setOwnClip = false;
                Region oldClip = e.Graphics.Clip;
                try
                {
                    if (e.ClipRectangle.Contains(this.Bounds))
                    {
                        setOwnClip = true;
                        e.Graphics.Clip = new Region(Bounds);
                    }

                    GraphicsPath itemPath = this.GetItemPath();
                    RectangleF itemRect = itemPath.GetBounds();
                    Rectangle itemCorrectRect = Rectangle.Round(itemRect);

                    if (this.Enabled)
                    {
                        // Fill item
                        if (this.Selected && this.Highlighted)
                        {
                            using (Brush selHighBrush = new SolidBrush(Toolbox.ItemSelectHoverColor))
                            {
                                e.Graphics.FillRectangle(selHighBrush, itemRect);
                            }
                        }
                        else if (this.Selected)
                        {
                            using (Brush selBrush = new SolidBrush(Toolbox.ItemSelectColor))
                            {
                                e.Graphics.FillRectangle(selBrush, itemRect);
                            }
                        }
                        else if (this.Highlighted)
                        {
                            using (Brush hoverBrush = new SolidBrush(Toolbox.ItemHoverColor))
                            {
                                e.Graphics.FillRectangle(hoverBrush, itemRect);
                            }
                        }

                        // Draw border
                        if (Selected || Highlighted)
                        {
                            using (Pen selPen = new Pen(Toolbox.ItemSelectBorderColor))
                            {
                                e.Graphics.DrawRectangle(selPen, itemRect.Left, itemRect.Top, itemRect.Width, itemRect.Height);
                            }
                        }
                    }

                    // Draw icon
                    Rectangle imageRectangle = Rectangle.Empty;
                    if (this.Image != null && Toolbox.ShowIcons)
                    {
                        Size size = new Size(Image.Width, this.Height);
                        //Size size = new Size(Image.Width, Toolbox.ItemHeight);

                        imageRectangle = new Rectangle(new Point(itemCorrectRect.Left + Toolbox.Gap_IconFromText, itemCorrectRect.Top), size);
                        if (imageRectangle.Height > Image.Height || imageRectangle.Width > Image.Width)
                            imageRectangle.Offset(5 + (int)(imageRectangle.Width - Image.Width) / 2, (int)(imageRectangle.Height - Image.Height) / 2);

                        using (Bitmap image = new Bitmap(this.Image))
                        {
                            if (this.TransparentColor != Color.Empty)
                                image.MakeTransparent(this.TransparentColor);

                            if (Enabled && IsOnline) 
                                e.Graphics.DrawImageUnscaled(image, imageRectangle);
                            else  
                                ControlPaint.DrawImageDisabled(e.Graphics, image, imageRectangle.Left, imageRectangle.Top, Toolbox.BackColorGradientStart);
                        }

                        if (this.StatusImage != null && !HaveMessage)
                            using (Bitmap statusImage = new Bitmap(this.StatusImage))
                            {
                                if (this.TransparentColor != Color.Empty)
                                    statusImage.MakeTransparent(this.TransparentColor);

                                int x = imageRectangle.Location.X + imageRectangle.Width - statusImage.Width;
                                int y = imageRectangle.Location.Y + imageRectangle.Width - statusImage.Height;
                                var size1 = new Size(statusImage.Width, statusImage.Height);
                                Rectangle StatusImageRectangle = new Rectangle(new Point(x, y), size1);
                                if (this.Enabled)
                                    e.Graphics.DrawImageUnscaled(statusImage, StatusImageRectangle);
                            }

                    }

                    // Write text
                    Rectangle itemTextRect = itemCorrectRect;
                    if (Toolbox.ShowIcons)
                    {
                        if (this.Image != null) 
                            itemTextRect.Offset(5 + imageRectangle.Width + 2 * Toolbox.Gap_IconFromText, 0); 

                        itemTextRect.Width -= (imageRectangle.Width + 2 * Toolbox.Gap_IconFromText);
                    }


                    if (Selected)
                        itemTextRect.Y = imageRectangle.Top - Toolbox.Font.Height - 5;


                    Brush textBrush = new SolidBrush(Color.Black);

                    if(!IsOnline)
                        textBrush = new SolidBrush(Toolbox.ForeColor);

                    if (Enabled)// && IsOnline
                        e.Graphics.DrawString(this.Text, Toolbox.Font, textBrush, itemTextRect, _itemTextFormat);
                    else 
                        ControlPaint.DrawStringDisabled(e.Graphics, this.Text, Toolbox.Font, Toolbox.BackColor, itemTextRect, _itemTextFormat);


                    //Write text Signature
                    if (Selected)
                        itemTextRect.Y = imageRectangle.Top;
                    else
                    {
                        itemTextRect.Y += 3;
                        SizeF size = e.Graphics.MeasureString(this.Text, Toolbox.Font);
                        itemTextRect.X = imageRectangle.Location.X +imageRectangle.Width + (int)size.Width + 5;
                    }

                    Brush SignaturetextBrush = new SolidBrush(Toolbox.ForeColor);

                    if (!string.IsNullOrEmpty(Signature))
                        if ( Enabled )//&& IsOnline
                            e.Graphics.DrawString(Signature, Toolbox.Font, SignaturetextBrush, itemTextRect, _itemTextFormat);
                        else 
                            ControlPaint.DrawStringDisabled(e.Graphics, Signature, Toolbox.Font, Toolbox.BackColor, itemTextRect, _itemTextFormat);
                }
                finally
                {
                    if (setOwnClip)
                        e.Graphics.Clip = oldClip;
                }
            }

            /// <summary>
            /// Returns the <see cref="GraphicsPath"/> structure that represents the <see cref="Item"/> drawing region.
            /// </summary>
            protected virtual GraphicsPath GetItemPath()
            {
                Rectangle rect = Bounds;
                rect.Width -= 1;
                rect.Height -= 1;
                GraphicsPath path = new GraphicsPath();
                path.AddRectangle(rect);
                return path;
            }

            /// <summary>
            /// Serializes an <see cref="Item"/> to the <see cref="XmlElement"/>.
            /// </summary>
            /// <param name="document">An <see cref="XmlDocument"/> that will own the resulting <see cref="XmlElement"/>.</param>
            /// <returns>An <see cref="XmlElement"/> that contains <see cref="Item"/> data.</returns>
            /// <exception cref="System.ArgumentNullException"><paramref name="document"/> is a null reference.</exception>
            protected internal virtual XmlElement SerializeToXml(XmlDocument document)
            {
                //return null;
                if (document == null)
                    throw new ArgumentNullException("document");

                XmlElement tabItem = document.CreateElement(Serializer_Item);

                Type thisType = this.GetType();
                foreach (PropertyInfo pi in Item.GetSerializableProperties(thisType))
                {
                    object value = pi.GetValue(this, null);
                    if (value != null)
                    {
                        if (pi.IsDefined(Item.DefaulValueAttributeType, true))
                        {
                            object[] attributes = pi.GetCustomAttributes(Item.DefaulValueAttributeType, true);
                            DefaultValueAttribute attr = (DefaultValueAttribute)attributes[0];
                            if (attr.Value == value || (attr.Value != null && attr.Value.Equals(value)))
                                continue;
                        }

                        if (pi.PropertyType.IsPrimitive || pi.PropertyType.IsEnum)
                            tabItem.SetAttribute(pi.Name, value.ToString());
                        else if (pi.PropertyType == Item.StringType)
                            tabItem.SetAttribute(pi.Name, (string)value);
                        else if (pi.PropertyType == Item.ColorType)
                            tabItem.SetAttribute(pi.Name, ((Color)value).ToArgb().ToString());
                        else if (pi.PropertyType == Item.ImageType)
                        {
                            Image image = (Image)value;
                            using (MemoryStream stream = new MemoryStream())
                            {
                                image.Save(stream, ImageFormat.Bmp);
                                stream.Flush();
                                tabItem.SetAttribute(pi.Name, Convert.ToBase64String(stream.ToArray()));
                            }
                        }
                    }
                }

                return tabItem;
            }

            /// <summary>
            /// Deserializes an <see cref="Item"/> data from the <see cref="XmlElement"/>.
            /// </summary>
            /// <param name="element">An <see cref="XmlElement"/> that contains <see cref="Item"/> data.</param>
            /// <exception cref="System.ArgumentNullException"><paramref name="element"/> is a null reference.</exception>
            protected internal virtual void DeserializeXml(XmlElement element)
            {
                if (element == null)
                    throw new ArgumentNullException("element");

                foreach (PropertyInfo pi in Item.GetSerializableProperties(this.GetType()))
                {
                    XmlAttribute attribute = element.Attributes[pi.Name];
                    if (attribute != null)
                    {
                        try
                        {
                            if (pi.PropertyType.IsPrimitive || pi.PropertyType.IsEnum)
                            {
                                pi.SetValue(this, Convert.ChangeType(attribute.Value, pi.PropertyType), null);
                            }
                            else if (pi.PropertyType == Item.StringType)
                            {
                                pi.SetValue(this, attribute.Value, null);
                            }
                            else if (pi.PropertyType == Item.ColorType)
                            {
                                int argb;
                                if (int.TryParse(attribute.Value, out argb))
                                    pi.SetValue(this, Color.FromArgb(argb), null);
                            }
                            else if (pi.PropertyType == Item.ImageType)
                            {
                                MemoryStream stream = new MemoryStream(Convert.FromBase64String(attribute.Value));
                                this.Image = System.Drawing.Image.FromStream(stream);
                            }
                        }
                        catch { }
                    }
                }
            }
            #endregion

            #region Internal Methods
            internal void InternalPaint(PaintEventArgs e, Point location)
            {
                this.Location = location;
                OnPaint(e);
            }

            internal void InternalMouseDown(MouseEventArgs e)
            {
                OnMouseDown(e);
            }

            internal void InternalMouseUp(MouseEventArgs e)
            {
                OnMouseUp(e);
            }

            internal void InternalClick(EventArgs e)
            {
                OnClick(e);
            }

            internal void InternalDoubleClick(EventArgs e)
            {
                OnDoubleClick(e);
            }

            /// <summary>
            /// Returns a bounds <see cref="Rectangle"/> of the <see cref="Item"/>.
            /// </summary>
            /// <param name="includeImage">Indicates whether to include image rectangle into returned bounds.</param>
            internal protected Rectangle GetBounds(bool includeImage)
            {
                Rectangle rect = Bounds;
                if (!includeImage && Image != null && Toolbox.ShowIcons)
                {
                    int offset = Image.Width + 2 * Toolbox.Gap_IconFromText;
                    rect.X += offset;
                    rect.Width -= offset;
                }
                return rect;
            }
            #endregion

            #region Private Methods
            private bool ShouldSerializeImage()
            {
                if (this.Image == null)
                    return false;
                return true;
            }

            private bool ShouldSerializeTransparentColor()
            {
                if (this.TransparentColor == Color.Empty)
                    return false;
                return true;
            }

            private bool ShouldSerializeTab()
            {
                return false;
            }

            private void ResetImage()
            {
                this.Image = null;
            }
            #endregion

            #region ICloneable Members

            /// <summary>
            /// Creates a new object that is a copy of the current instance.
            /// </summary>
            object ICloneable.Clone()
            {
                return Clone();
            }

            /// <summary>
            /// Creates an identical copy of the <see cref="Item"/>.
            /// </summary>
            /// <returns>An object that represents an <see cref="Item"/> that has the same text, image, forecolor and backcolor associated with it as the cloned item.</returns>
            public virtual Item Clone()
            {
                Item item = new Item();
                item._text = _text;
                item._image = _image;
                item._foreColor = _foreColor;
                item._backColor = _backColor;
                return item;
            }

            #endregion
        }
    }
}