using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace IMLibrary.Controls.Toolbox
{
    partial class Toolbox
    {
        /// <summary>
        /// Represents a category in a <see cref="Toolbox"/> control.
        /// </summary>
        [Serializable]
        [ToolboxItem(false)]
        [DesignTimeVisible(false)]
        [TypeConverter(typeof(TabConverter))]
        public class Tab : IToolboxObject, ITab
        {
            #region Fields
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private string _text;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _opened;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _visible = true;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _selected;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _allowDelete = true;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private ItemCollection _items;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private TabCollection _tabs;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private Point _location;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private int _height;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool _renaming = false;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private ITab _owner;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private object _tag;

            private static readonly Bitmap _collapsed;
            private static readonly Bitmap _expanded;
            private static readonly Bitmap _pointer;
            private static readonly StringFormat _tabCaptionFormat;
            private static readonly StringFormat _tabEmptyTextFormat;

            /// <summary>
            /// Represents the readonly Pointer <see cref="Item"/> of the <see cref="Tab"/>.
            /// </summary>
            public readonly Item PointerItem;

            /// <summary>
            /// Occurs when the <see cref="Tab"/> is opened or closed on the <see cref="Toolbox"/>.
            /// </summary>
            public event EventHandler<TabEventArgs> Toggle;

            /// <summary>
            /// Occurs when the <see cref="Tab"/> is selected/deselected on the <see cref="Toolbox"/>.
            /// </summary>
            public event EventHandler<TabEventArgs> SelectedChanged;
            #endregion

            #region Static constructor
            [DebuggerHidden]
            static Tab()
            {
                try
                {
                    _collapsed = new Bitmap(Properties.Resources.Collapsed);
                    _collapsed.MakeTransparent(_collapsed.GetPixel(0, 0));
                }
                catch { }

                try
                {
                    _expanded = new Bitmap(Properties.Resources.Expanded);
                    _expanded.MakeTransparent(_expanded.GetPixel(0, 0));
                }
                catch { }

                try
                {
                    _pointer = new Bitmap(Properties.Resources.PointerBlack);
                    _pointer.MakeTransparent(_pointer.GetPixel(0, 0));
                }
                catch { }

                _tabCaptionFormat = new StringFormat();
                _tabCaptionFormat.FormatFlags = StringFormatFlags.NoWrap;
                _tabCaptionFormat.Trimming = StringTrimming.EllipsisWord;

                _tabEmptyTextFormat = new StringFormat();
                _tabEmptyTextFormat.Alignment = StringAlignment.Center;
                _tabEmptyTextFormat.LineAlignment = StringAlignment.Center;
            }
            #endregion

            #region Constructors
            //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public  UInt32 OnlineCount = 0;
            //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public string FactText  = string.Empty;//{ get; set; }
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private string MyText = string.Empty;
            //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private bool Flicker = false;
            //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private System.Timers.Timer  timer1 = new  System.Timers.Timer(400);
            /// <summary>
            /// ΙΑΛΈΝΌ±κ
            /// </summary>
            public void FlickerIcons()
            {
                if (timer1.Enabled) return; 
                timer1.Elapsed  += (s, e) =>
                {
                    OnlineCount = 0;
                    bool HaveMessage = false;
                    foreach (var item in Items)
                    {
                        if (item.IsOnline)
                            OnlineCount++;

                        if (item.HaveMessage)
                        {
                            if (item.Flicker)
                                if (item.Selected)
                                    item.Image = item.SelectedImage;
                                else
                                    item.Image = item.NotSelectedImage;
                            else
                                if (item.Selected)
                                    item.Image = item.SelectedNullImage;
                                else
                                    item.Image = item.NotSelectedNullImage; 
                               
                            item.Flicker = !item.Flicker;

                            if (item.Owner != null)
                                item.Owner.Invalidate();

                            HaveMessage = true;
                        }
                    }
                     
                    if (HaveMessage && !this.Opened )
                    {
                        if (Flicker)
                            this.Text = string.Empty;
                        else
                            this.Text =string.Format("{0}  [{1}/{2}]",FactText,OnlineCount,Items.Count) ;

                        Flicker = !Flicker;
                        this.Invalidate();
                    }
                    else if (this.Text != string.Format("{0}  [{1}/{2}]", FactText, OnlineCount, Items.Count))
                    {
                        this.Text = string.Format("{0}  [{1}/{2}]", FactText, OnlineCount, Items.Count);
                        this.Invalidate(); 
                    }
                   
                };
                timer1.Enabled = true;
            }

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

            /// <summary>
            /// Initializes a new instance of the <see cref="Tab"/> class with the specified category text.
            /// </summary>
            /// <param name="text">The text to display for the tab.</param>
            public Tab(string text)
            {
                if (string.IsNullOrEmpty(text))
                    text = Properties.Resources.ToolboxTabDefaultName;

                _text = text;
                _items = new ItemCollection(this);
                _tabs = new TabCollection(this);

                PointerItem = CreatePointerItem(Properties.Resources.ToolboxPointerItem);
                PointerItem.Owner = this;
                PointerItem.Image = _pointer;
                PointerItem.Enabled = false;

                //IniTimer();
            }
            #endregion

            #region Public Properties
            public bool AllowDropItem = true;

            public bool AllowDrag = true;

            /// <summary>
            /// Gets the <see cref="Toolbox"/> object that contains the <see cref="Tab"/>.
            /// </summary>
            [Browsable(false)]
            public Toolbox Toolbox
            {
                [DebuggerStepThrough]
                get 
                {
                    ITab owner = this.Owner;
                    while (owner != null && !(owner is Toolbox))
                    {
                        owner = owner.Owner;
                    }
                    return (Toolbox)owner; 
                }
            }

            /// <summary>
            /// Gets or sets the text to display for the <see cref="Tab"/>.
            /// </summary>
            public virtual string Text
            {
                [DebuggerStepThrough]
                get { return _text; }
                set 
                { 
                    _text = value;
                    
                    Toolbox toolbox = this.Toolbox;
                    if (toolbox != null)
                    {
                        toolbox.Invalidate(GetCaptionRectangle(false));
                    }
                }
            }

            /// <summary>
            /// Gets or sets the value indicating whether the <see cref="Tab"/> is opened on the <see cref="Toolbox"/>.
            /// </summary>
            [DefaultValue(false)]
            public virtual bool Opened
            {
                [DebuggerStepThrough]
                get { return _opened; }
                set
                {
                    if (_opened != value)
                    {
                        _opened = value;
                        OnToggleTab();

                        if (Owner != null)
                            Owner.Invalidate();
                    }
                }
            }

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

            /// <summary>
            /// Indicates whether the <see cref="Tab"/> is currently selected on the <see cref="Toolbox"/>.
            /// </summary>
            [Browsable(false)]
            [DefaultValue(false)]
            public bool Selected
            {
                [DebuggerStepThrough]
                get { return _selected; }
                internal set
                {
                    if (_selected != value)
                    {
                        Toolbox toolbox = this.Toolbox;
                        if (toolbox != null)
                        {
                            _selected = value;
                            Rectangle invalidate = GetCaptionRectangle(true);
                            invalidate.Inflate(1, 1);
                            toolbox.Invalidate(invalidate);
                            OnSelectedChanged();
                        }
                    }
                }
            }

            /// <summary>
            /// Gets or sets a value indicating whether the <see cref="Tab"/> is allowed to remove from the <see cref="Toolbox"/>.
            /// </summary>
            [DefaultValue(true)]
            public bool AllowDelete
            {
                [DebuggerStepThrough]
                get { return _allowDelete; }
                [DebuggerStepThrough]
                set
                {
                    if (_allowDelete != value)
                    {
                        _allowDelete = value;
                    }
                }
            }

            /// <summary>
            /// Gets the location of the left top point where to draw the <see cref="Tab"/> on the <see cref="Toolbox"/>.
            /// </summary>
            [Browsable(false)]
            public Point Location
            {
                [DebuggerStepThrough]
                get { return _location; }
            }

            /// <summary>
            /// Gets the bounds of the <see cref="Tab"/> on the <see cref="Toolbox"/>.
            /// </summary>
            [Browsable(false)]
            public virtual Rectangle VisibleRectangle
            {
                get
                {
                    Toolbox toolbox = this.Toolbox;
                    if (toolbox == null)
                        return Rectangle.Empty;

                    return new Rectangle(this.Location, new Size(this.Width, this.Height));
                }
            }

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

            #region Other Properties
            /// <summary>
            /// Gets or sets the value indicating whether the <see cref="Tab"/> is currently renamed.
            /// </summary>
            protected internal bool Renaming
            {
                [DebuggerStepThrough]
                get { return _renaming; }
                set
                {
                    Toolbox toolbox = this.Toolbox;
                    if (toolbox != null)
                    {
                        _renaming = value;
                        toolbox.Invalidate(GetCaptionRectangle(true));
                    }
                }
            }

            #endregion

            #region Public Methods
            /// <summary>
            /// Ensures that the <see cref="Tab"/> is visible within the <see cref="Toolbox"/>, scrolling the contents of the <see cref="Toolbox"/> if necessary.
            /// </summary>
            public void EnsureVisible()
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox != null && Visible)
                {
                    toolbox.EnsureVisible(VisibleRectangle);
                }
            }

            /// <summary>
            /// Selects the <see cref="Tab"/> on the <see cref="Toolbox"/>.
            /// </summary>
            public void Select()
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox != null && Visible)
                {
                    EnsureVisible();
                    toolbox.SelectTool(this);
                }
            }

            /// <summary>
            /// Sorts items contained in the <see cref="Tab"/> using the specified order.
            /// </summary>
            /// <param name="order">One of the <see cref="SortOrder"/> values indicating how to sort items.</param>
            public void SortItems(SortOrder order)
            {
                if (order == SortOrder.None)
                    return;

                Comparison<Item> compare = delegate(Item first, Item second)
                {
                    if (first == second)
                        return 0;

                    if (order == SortOrder.Ascending)
                        return string.Compare(first.Text, second.Text);
                    else
                        return string.Compare(second.Text, first.Text);
                };
                Items.Sort(compare);
            }

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

            #region Protected Methods
            /// <summary>
            /// Creates a Pointer <see cref="Item"/> for the <see cref="Tab"/>.
            /// </summary>
            /// <param name="text">The default text of the Pointer Item.</param>
            /// <returns>An <see cref="Item"/> object representing the Pointer Item of the <see cref="Tab"/>.</returns>
            protected virtual Item CreatePointerItem(string text)
            {
                return new Item(text);
            }

            /// <summary>
            /// Notifies the <see cref="Toolbox"/> object that the state of the <see cref="Tab"/> is changed and invalidation is required.
            /// </summary>
            protected internal void NotifyInvalidate()
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox != null && this.Opened && this.Visible)
                    toolbox.Invalidate(this.VisibleRectangle);
            }

            /// <summary>
            /// Returns an object with information on which portion of a toolbox control is at a location specified by a <see cref="Point"/>.
            /// </summary>
            /// <param name="location">A <see cref="Point"/> containing the <see cref="Point.X"/> and <see cref="Point.Y"/> coordinates of the point to be hit tested.</param>
            /// <returns>A <see cref="HitTestInfo"/> that contains information about the specified point on the <see cref="Toolbox"/>.</returns>
            internal protected virtual HitTestInfo HitTest(Point location)
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox == null)
                    return null;

                Rectangle tabRect = this.VisibleRectangle;
                Rectangle captionRect = this.GetCaptionRectangle(true);

                HitTestInfo info = new HitTestInfo(location);

                if (tabRect.Contains(location))
                {
                    if (captionRect.Contains(location))
                    {
                        info.HitArea = HitArea.TabHeader;
                    }
                    else
                    {
                        if (toolbox.AllowNestedTabs)
                        {
                            foreach (Tab tab in Categories)
                            {
                                if ((toolbox.ShowAll || tab.Visible) && tab.VisibleRectangle.Contains(location))
                                {
                                    return tab.HitTest(location);
                                }
                            }
                        }

                        if (toolbox.ShowPointer && (PointerItem.Visible || toolbox.ShowAll) && PointerItem.Bounds.Contains(location))
                        {
                            info.HitArea = HitArea.Item;
                            info.Tool = PointerItem;
                        }
                        else
                        {
                            foreach (Item item in this.Items)
                            {
                                if ((item.Visible || toolbox.ShowAll) && item.Bounds.Contains(location))
                                {
                                    info.HitArea = HitArea.Item;
                                    info.Tool = item;
                                    break;
                                }
                            }
                        }
                    }

                    if (info.HitArea == HitArea.None)
                        info.HitArea = HitArea.TabBody;
                    if (info.Tool == null)
                        info.Tool = this;
                }

                return info;
            }

            /// <summary>
            /// Returns the <see cref="GraphicsPath"/> structure that represents the <see cref="Tab"/> drawing region.
            /// </summary>
            protected virtual GraphicsPath GetTabPath()
            {
                Rectangle rect = GetCaptionRectangle(true);
                GraphicsPath path = new GraphicsPath();
                path.AddRectangle(rect);
                return path;
            }

            /// <summary>
            /// Draws the <see cref="Tab"/> 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)
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox == null)
                    return;
                
                GraphicsPath tabPath = GetTabPath();
                RectangleF tabRectangle = tabPath.GetBounds();
                // Draw tab
                if (Selected)
                {
                    using (Brush selBrush = new SolidBrush(toolbox.TabSelectColor))
                    {
                        e.Graphics.FillPath(selBrush, tabPath);
                    }
                    using (Pen selPen = new Pen(toolbox.TabSelectBorderColor))
                    {
                        e.Graphics.DrawRectangle(selPen, tabRectangle.Left, tabRectangle.Top, tabRectangle.Width - 1, tabRectangle.Height - 1);
                    }
                }
                else if (toolbox.TabColorStyle != ColorStyle.None)
                {
                    Color backColorStart;
                    Color backColorEnd;
                    switch (toolbox.TabColorStyle)
                    {
                        case ColorStyle.Lighter:
                            backColorStart = ControlPaint.Light(toolbox.BackColorGradientStart, 0.001f);
                            backColorEnd = ControlPaint.Light(toolbox.BackColorGradientEnd, 0.001f);
                            break;
                        case ColorStyle.Darker:
                            backColorStart = ControlPaint.Dark(toolbox.BackColorGradientStart, 0.001f);
                            backColorEnd = ControlPaint.Dark(toolbox.BackColorGradientEnd, 0.001f);
                            break;
                        default:
                            backColorStart = Color.LightGray;
                            backColorEnd = Color.Gray;
                            break;
                    }
                    RectangleF gradientRectangle = tabRectangle;
                    gradientRectangle.Inflate(1, 1);
                    using (Brush unselectedBrush = new LinearGradientBrush(gradientRectangle, backColorStart, backColorEnd, LinearGradientMode.Horizontal))
                    {
                        e.Graphics.FillPath(unselectedBrush, tabPath);
                    }
                }

                // Draw collapsed/expanded icon
                Point stateIconPosition = Point.Round(tabRectangle.Location);
                stateIconPosition.Y += (int)(tabRectangle.Height - Tab._collapsed.Height) / 2;
                if (Opened)
                {
                    e.Graphics.DrawImageUnscaled(Tab._expanded, stateIconPosition);
                }
                else
                {
                    e.Graphics.DrawImageUnscaled(Tab._collapsed, stateIconPosition);
                }

                // Draw tab Text
                Brush textBrush = new SolidBrush(toolbox.ForeColor);
                SizeF textSize = e.Graphics.MeasureString(this.Text, toolbox.TabFont);
                RectangleF textRectangle = new RectangleF(tabRectangle.Left + Tab._expanded.Width + Toolbox.Gap_IconFromText, tabRectangle.Top + (tabRectangle.Height - textSize.Height) / 2, tabRectangle.Width - Tab._expanded.Width - Toolbox.Gap_IconFromText, textSize.Height);
                e.Graphics.DrawString(this.Text, toolbox.TabFont, textBrush, textRectangle, _tabCaptionFormat);

                _height = (int)tabRectangle.Height;
                // Draw items
                if (Opened)
                {
                    Point location = new Point((int)tabRectangle.Left + ((toolbox.DrawTabLevel) ? Toolbox.Gap_TabLevel : 0), (int)tabRectangle.Bottom);

                    if (Items.Count == 0 && (!toolbox.AllowNestedTabs || Categories.Count == 0) && (!toolbox.ShowAll || !toolbox.ShowPointer))
                    {
                        // Draw text ToolboxTabNoItemsText
                        // Before and after this text goes empty line with height = Toolbox.ItemHeight
                        string text = Properties.Resources.ToolboxTabNoItemsText;
                        textSize = e.Graphics.MeasureString(text, toolbox.Font, this.Width - ((toolbox.DrawTabLevel) ? Toolbox.Gap_TabLevel : 0));
                        textRectangle = new RectangleF(location.X, location.Y + Toolbox.Gap_ItemBetween + toolbox.ItemHeight, textSize.Width, textSize.Height);
                        e.Graphics.DrawString(text, toolbox.Font, textBrush, textRectangle, _tabEmptyTextFormat);

                        location.Offset(0, (int)(2 * toolbox.ItemHeight + 2 * Toolbox.Gap_ItemBetween + textSize.Height));
                    }
                    else
                    {
                        if (toolbox.AllowNestedTabs && this.Categories.Count > 0)
                        {
                            foreach (Tab tab in this.Categories)
                            {
                                if (tab.Visible || toolbox.ShowAll)
                                {
                                    location.Offset(0, Toolbox.Gap_TabBetween);
                                    tab.InternalPaint(e, ref location);
                                }
                            }

                            location.Offset(0, Toolbox.Gap_TabBetween);
                        }

                        if (toolbox.ShowPointer && (this.Items.Count > 0 || toolbox.ShowAll))
                        {
                            location.Offset(0, Toolbox.Gap_ItemBetween);
                            PointerItem.InternalPaint(e, location);
                            location.Offset(0, toolbox.ItemHeight);
                        }

                        foreach (Item item in Items)
                        {
                            if (item.Visible || toolbox.ShowAll)
                            {
                                location.Offset(0, Toolbox.Gap_ItemBetween);
                                item.InternalPaint(e, location);
                                //location.Offset(0, toolbox.ItemHeight);
                                location.Offset(0,item.Height );
                            }
                        }
                    }
                    _height += (int)(location.Y - tabRectangle.Bottom);

                    if (toolbox.DrawTabLevel)
                    {
                        using (Pen levelPen = new Pen(Color.Black, 1))
                        {
                            e.Graphics.DrawLine(levelPen,
                                tabRectangle.Left + Toolbox.Gap_TabLevel / 3f, 
                                tabRectangle.Bottom + Toolbox.Gap_TabBetween,
                                tabRectangle.Left + Toolbox.Gap_TabLevel / 3f, 
                                location.Y - Toolbox.Gap_TabBetween);
                            e.Graphics.DrawLine(levelPen,
                                tabRectangle.Left + Toolbox.Gap_TabLevel / 3f,
                                location.Y - Toolbox.Gap_TabBetween,
                                tabRectangle.Left + Toolbox.Gap_TabLevel * 2 / 3f,
                                location.Y - Toolbox.Gap_TabBetween);
                        }
                    }
                }
            }

            /// <summary>
            /// Invoked when the mouse button is pressed on the <see cref="Tab"/>.
            /// </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="Tab"/>. 
            /// </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.Left"/> and the mouse location is withing <see cref="Tab"/> caption, the <see cref="Tab"/> state is toggled.
            /// <para/>If the mouse button is <see cref="MouseButtons.Right"/> the <see cref="IMLibrary.Components.Toolbox.TabMenu"/> is shown if available.
            /// </remarks>
            protected virtual void OnMouseUp(MouseEventArgs e)
            {
                Toolbox toolbox = this.Toolbox;
                if (e.Button == MouseButtons.Left)
                {
                    if (this.GetCaptionRectangle(true).Contains(e.Location))
                    {
                        this.Opened = !this.Opened;
                        toolbox.Invalidate();
                    }
                }
                else if (e.Button == MouseButtons.Right)
                {
                    if (toolbox.TabMenu != null)
                    {
                        toolbox.TabMenu.Tag = this;
                        toolbox.TabMenu.Show(toolbox, e.Location);
                    }
                }
            }

            /// <summary>
            /// Invoked when the user clicks on the <see cref="Tab"/>.
            /// </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="Tab"/>.
            /// </summary>
            /// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
            protected virtual void OnDoubleClick(EventArgs e)
            {
            }

            #region Event Fires
            /// <summary>
            /// Raises the <see cref="Toggle"/> event.
            /// </summary>
            protected virtual void OnToggleTab()
            {
                if (Toggle != null)
                    Toggle(this, new TabEventArgs(this));
            }

            /// <summary>
            /// Raises the <see cref="SelectedChanged"/> event.
            /// </summary>
            protected virtual void OnSelectedChanged()
            {
                if (SelectedChanged != null)
                    SelectedChanged(this, new TabEventArgs(this));
            }
            #endregion

            #endregion

            #region Internal Methods
            internal void InternalPaint(PaintEventArgs e, ref Point position)
            {
                this._location = position;
                OnPaint(e);
                position.Offset(0, this.Height);
            }

            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>
            /// Calculates the height of the <see cref="Tab"/>.
            /// </summary>
            /// <param name="g">A drawing surface.</param>
            /// <param name="visibleRect">A <see cref="Rectangle"/> representing the visible region of the <see cref="Toolbox"/>.</param>
            internal protected virtual int CalculateTabHeight(Graphics g, Rectangle visibleRect)
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox == null)
                    return 0;

                int height = toolbox.TabHeight;
                if (this.Opened)
                {
                    if (toolbox.DrawTabLevel)
                    {
                        visibleRect.X += Toolbox.Gap_TabLevel;
                        visibleRect.Width -= Toolbox.Gap_TabLevel;
                    }

                    if (this.Items.Count == 0 && (!toolbox.AllowNestedTabs || this.Categories.Count == 0) && (!toolbox.ShowAll || !toolbox.ShowPointer))
                    {
                        height += 2 * toolbox.ItemHeight;
                        height += 2 * Toolbox.Gap_ItemBetween;
                        height += (int)g.MeasureString(Properties.Resources.ToolboxTabNoItemsText, toolbox.Font, visibleRect.Width).Height;
                    }
                    else
                    {
                        if (toolbox.AllowNestedTabs && this.Categories.Count > 0)
                        {
                            foreach (Tab tab in Categories)
                            {
                                height += tab.CalculateTabHeight(g, visibleRect);
                                height += Toolbox.Gap_TabBetween;
                            }

                            height += Toolbox.Gap_TabBetween;
                        }

                        if (toolbox.ShowPointer && (this.Items.Count > 0 || toolbox.ShowAll))
                        {
                            height += (toolbox.ItemHeight + Toolbox.Gap_ItemBetween);
                        }
                        foreach (Item item in Items)
                        {
                            if (item.Visible || toolbox.ShowAll)
                            {
                                //height += (toolbox.ItemHeight + Toolbox.Gap_ItemBetween);

                                height += (item.Height + Toolbox.Gap_ItemBetween);

                            }
                        }
                    }
                }
                return height;
            }

            /// <summary>
            /// Returns a <see cref="Rectangle"/> of the <see cref="Tab"/> caption.
            /// </summary>
            /// <param name="includeIcon">Indicates whether to include icon into returned rectangle.</param>
            internal protected Rectangle GetCaptionRectangle(bool includeIcon)
            {
                Toolbox toolbox = this.Toolbox;
                if (toolbox == null)
                    return Rectangle.Empty;

                Rectangle caption = new Rectangle(this.Location, new Size(this.Width, toolbox.TabHeight));
                if (!includeIcon)
                {
                    try
                    {
                        int offset = Tab._collapsed.Width + Toolbox.Gap_IconFromText;
                        caption.Width -= offset;
                        caption.X += offset;
                    }
                    catch { }
                }
                return caption;
            }
            #endregion

            #region Private Methods
            #endregion

            #region ITab Members

            /// <summary>
            /// Invalidates the <see cref="Tab.VisibleRectangle">bounds</see> of the <see cref="Tab"/>.
            /// </summary>
            public void Invalidate()
            {
                ITab parent = Owner;
                if (parent is Tab)
                    ((Tab)parent).NotifyInvalidate();
                else if (parent != null)
                    parent.Invalidate();
            }

            /// <summary>
            /// Gets the width of the <see cref="Tab"/> on the <see cref="Toolbox"/>.
            /// </summary>
            [Browsable(false)]
            public 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)
                    {
                        width -= Toolbox.Gap_TabLevel;
                    }
                    return width;
                }
            }

            /// <summary>
            /// Gets the height of the <see cref="Tab"/> on the <see cref="Toolbox"/> taking into account whether the <see cref="Tab"/> is opened and including heights of all the visible items.
            /// </summary>
            [Browsable(false)]
            public int Height
            {
                [DebuggerStepThrough]
                get { return _height; }
            }

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

            /// <summary>
            /// Gets the <see cref="ItemCollection">collection</see> of the items in the <see cref="Tab"/>.
            /// </summary>
            [MergableProperty(false)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            public virtual ItemCollection Items
            {
                [DebuggerStepThrough]
                get { return _items; }
            }

            /// <summary>
            /// Gets the <see cref="TabCollection">collection</see> of the tabs in the <see cref="Tab"/>.
            /// </summary>
            [MergableProperty(false)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            public virtual TabCollection Categories
            {
                [DebuggerStepThrough]
                get { return _tabs; }
            }

            #endregion
        }
    }
}