using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
using System.ComponentModel.Design;
using BSE.Windows.Forms.Properties;

namespace BSE.Windows.Forms
{
    #region Class XPanderPanel
	/// <summary>
	/// Used to group collections of controls. 
	/// </summary>
    /// <remarks>
    /// XPanderPanel controls represent the expandable and collapsable panels in XPanderPanelList.
    /// The XpanderPanel is a control that contains other controls.
    /// You can use a XPanderPanel to group collections of controls such as the XPanderPanelList.
    /// The order of xpanderpanels in the XPanderPanelList.XPanderPanels collection reflects the order
    /// of xpanderpanels controls. To change the order of tabs in the control, you must change
    /// their positions in the collection by removing them and inserting them at new indexes.
    /// You can change the xpanderpanel's appearance. For example, to make it appear flat,
    /// set the CaptionStyle property to CaptionStyle.Flat.
    /// On top of the XPanderPanel there is the captionbar.
    /// This captionbar may contain an image and text. According to it's properties the panel is closable.
    /// </remarks>
	/// <copyright>Copyright © 2006-2008 Uwe Eichkorn
    /// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
    /// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    /// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    /// PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
    /// REMAINS UNCHANGED.
    /// </copyright>
    [Designer(typeof(XPanderPanelDesigner))]
    [DesignTimeVisible(false)]
	public partial class XPanderPanel : BasePanel
	{
		#region EventsPublic
        /// <summary>
        /// The CaptionStyleChanged event occurs when CaptionStyle flags have been changed.
        /// </summary>
        [Description("The CaptionStyleChanged event occurs when CaptionStyle flags have been changed.")]
        public event EventHandler<EventArgs> CaptionStyleChanged;
        #endregion
		
		#region Constants
		#endregion

		#region FieldsPrivate
		
		private System.Drawing.Image m_imageChevron;
        private System.Drawing.Image m_imageChevronUp;
        private System.Drawing.Image m_imageChevronDown;
        private CustomXPanderPanelColors m_customColors;
        private System.Drawing.Image m_imageClosePanel;
        private bool m_bIsClosable = true;
        private CaptionStyle m_captionStyle;

		#endregion

		#region Properties
		/// <summary>
        /// Gets or sets a value indicating whether the expand icon in a XPanderPanel is visible.
        /// </summary>
		[Description("Gets or sets a value indicating whether the expand icon in a XPanderPanel is visible.")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[DefaultValue(false)]
		[Browsable(false)]
		[Category("Appearance")]
		public override bool ShowExpandIcon
		{
			get
			{
				return base.ShowExpandIcon;
			}
			set
			{
				base.ShowExpandIcon = value;
			}
		}
        /// <summary>
        /// Gets or sets a value indicating whether the close icon in a XPanderPanel is visible.
        /// </summary>
        [Description("Gets or sets a value indicating whether the close icon in a XPanderPanel is visible.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(false)]
        [Browsable(false)]
        [Category("Appearance")]
        public override bool ShowCloseIcon
        {
            get
            {
                return base.ShowCloseIcon;
            }
            set
            {
                base.ShowCloseIcon = value;
            }
        }
        /// <summary>
        /// Gets the custom colors which are used for the XPanderPanel.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("The custom colors which are used for the XPanderPanel.")]
        [Category("Appearance")]
        public CustomXPanderPanelColors CustomColors
        {
            get { return this.m_customColors; }
        }
        /// <summary>
        /// Gets or sets the style of the caption (not for PanelStyle.Aqua).
        /// </summary>
        [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public CaptionStyle CaptionStyle
        {
            get { return this.m_captionStyle; }
            set
            {
                if (value.Equals(this.m_captionStyle) == false)
                {
                    this.m_captionStyle = value;
                    OnCaptionStyleChanged(this, EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether this XPanderPanel is closable.
        /// </summary>
        [Description("Gets or sets a value indicating whether this XPanderPanel is closable.")]
        [DefaultValue(true)]
        [Category("Appearance")]
        public bool IsClosable
        {
            get { return this.m_bIsClosable; }
            set
            {
                if (value.Equals(this.m_bIsClosable) == false)
                {
                    this.m_bIsClosable = value;
                    this.Invalidate(false);
                }
            }
        }
        /// <summary>
        /// Gets or sets the height and width of the XPanderPanel.
        /// </summary>
        [Browsable(false)]
        public new Size Size
        {
            get { return base.Size; }
            set { base.Size = value; }
        }
		#endregion

		#region MethodsPublic
		/// <summary>
		/// Initializes a new instance of the XPanderPanel class.
		/// </summary>
		public XPanderPanel()
		{
			InitializeComponent();

            this.BackColor = Color.Transparent;
            this.CaptionStyle = CaptionStyle.Normal;
            this.ForeColor = SystemColors.ControlText;
			this.Height = this.CaptionHeight;
			this.ShowBorder = true;
            this.m_customColors = new CustomXPanderPanelColors();
            this.m_customColors.CustomColorsChanged += OnCustomColorsChanged;

		}
        /// <summary>
        /// Gets the rectangle that represents the display area of the XPanderPanel.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Rectangle DisplayRectangle
        {
            get
            {
                Padding padding = this.Padding;

                Rectangle displayRectangle = new Rectangle(
                    padding.Left + Constants.BorderThickness,
                    padding.Top + this.CaptionHeight,
                    this.ClientRectangle.Width - padding.Left - padding.Right - (2 * Constants.BorderThickness),
                    this.ClientRectangle.Height - this.CaptionHeight - padding.Top - padding.Bottom);

                if (this.Controls.Count > 0)
                {
                    XPanderPanelList xpanderPanelList = this.Controls[0] as XPanderPanelList;
                    if ((xpanderPanelList != null) && (xpanderPanelList.Dock == DockStyle.Fill))
                    {
                        displayRectangle = new Rectangle(
                            padding.Left,
                            padding.Top + this.CaptionHeight,
                            this.ClientRectangle.Width - padding.Left - padding.Right,
                            this.ClientRectangle.Height - this.CaptionHeight - padding.Top - padding.Bottom - Constants.BorderThickness);
                    }
                }
                return displayRectangle;
            }
        }
		#endregion

		#region MethodsProtected
		/// <summary>
		/// Paints the background of the control.
		/// </summary>
		/// <param name="pevent">A PaintEventArgs that contains information about the control to paint.</param>
		protected override void OnPaintBackground(PaintEventArgs pevent)
		{
			base.OnPaintBackground(pevent);
            base.BackColor = Color.Transparent;
            Color backColor = this.PanelColors.XPanderPanelBackColor;
            if ((backColor != Color.Empty) && backColor != Color.Transparent)
            {
                Rectangle rectangle = new Rectangle(
                    0,
                    this.CaptionHeight,
                    this.ClientRectangle.Width,
                    this.ClientRectangle.Height - this.CaptionHeight);

                using (SolidBrush backgroundBrush = new SolidBrush(backColor))
                {
                    pevent.Graphics.FillRectangle(backgroundBrush, rectangle);
                }
            }
		}
		/// <summary>
		/// Raises the Paint event.
		/// </summary>
		/// <param name="e">A PaintEventArgs that contains the event data.</param>
		protected override void OnPaint(PaintEventArgs e)
		{
            if (IsZeroWidthOrHeight(this.CaptionRectangle) == true)
            {
                return;
            }
            
            using (UseAntiAlias antiAlias = new UseAntiAlias(e.Graphics))
            {
                Graphics graphics = e.Graphics;
                using (UseClearTypeGridFit clearTypeGridFit = new UseClearTypeGridFit(graphics))
                {
                    bool bExpand = this.Expand;
                    bool bShowBorder = this.ShowBorder;
                    Color borderColor = this.PanelColors.BorderColor;
                    Rectangle borderRectangle = this.ClientRectangle;
                    
                    switch (this.PanelStyle)
                    {
                        case PanelStyle.Default:
                        case PanelStyle.Office2007:
                            DrawCaptionbar(graphics, bExpand, bShowBorder, this.PanelStyle);
                            CalculatePanelHeights();
                            DrawBorders(graphics, this);
                            break;
                    }
                }
            }
		}
		/// <summary>
        /// Raises the PanelExpanding event.
		/// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">A XPanderStateChangeEventArgs that contains the event data.</param>
        protected override void OnPanelExpanding(object sender, XPanderStateChangeEventArgs e)
		{
			bool bExpand = e.Expand;
			if (bExpand == true)
			{
				this.Expand = bExpand;
                this.Invalidate(false);
			}
			base.OnPanelExpanding(sender, e);
		}
        /// <summary>
        /// Raises the CaptionStyleChanged event.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">An EventArgs that contains the event data.</param>
        protected virtual void OnCaptionStyleChanged(object sender, EventArgs e)
        {
            this.Invalidate(this.CaptionRectangle);
            if (this.CaptionStyleChanged != null)
            {
                this.CaptionStyleChanged(sender, e);
            }
        }
        /// <summary>
        /// Raises the MouseUp event.
        /// </summary>
        /// <param name="e">A MouseEventArgs that contains data about the OnMouseUp event.</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (this.CaptionRectangle.Contains(e.X, e.Y) == true)
            {
                if ((this.ShowCloseIcon == false) && (this.ShowExpandIcon == false))
                {
                    OnExpandClick(this, EventArgs.Empty);
                }
                else if ((this.ShowCloseIcon == true) && (this.ShowExpandIcon == false))
                {
                    if (this.RectangleCloseIcon.Contains(e.X, e.Y) == false)
                    {
                        OnExpandClick(this, EventArgs.Empty);
                    }
                }
                if (this.ShowExpandIcon == true)
                {
                    if (this.RectangleExpandIcon.Contains(e.X, e.Y) == true)
                    {
                        OnExpandClick(this, EventArgs.Empty);
                    }
                }
                if ((this.ShowCloseIcon == true) && (this.m_bIsClosable == true))
                {
                    if (this.RectangleCloseIcon.Contains(e.X, e.Y) == true)
                    {
                        OnCloseClick(this, EventArgs.Empty);
                    }
                }
            }
        }
		/// <summary>
		/// Raises the VisibleChanged event.
		/// </summary>
		/// <param name="e">An EventArgs that contains the event data.</param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (this.DesignMode == true)
            {
                return;
            }
            if (this.Visible == false)
            {
                if (this.Expand == true)
                {
                    this.Expand = false;
                    foreach (Control control in this.Parent.Controls)
                    {
                        BSE.Windows.Forms.XPanderPanel xpanderPanel =
                            control as BSE.Windows.Forms.XPanderPanel;

                        if (xpanderPanel != null)
                        {
                            if (xpanderPanel.Visible == true)
                            {
                                xpanderPanel.Expand = true;
                                return;
                            }
                        }
                    }
                }
            }
#if DEBUG
            //System.Diagnostics.Trace.WriteLine("Visibility: " + this.Name + this.Visible);
#endif
            CalculatePanelHeights();
        }

		#endregion

		#region MethodsPrivate
        
        private void DrawCaptionbar(Graphics graphics, bool bExpand, bool bShowBorder, PanelStyle panelStyle)
        {
            Rectangle captionRectangle = this.CaptionRectangle;
            Color colorGradientBegin = this.PanelColors.XPanderPanelCaptionGradientBegin;
            Color colorGradientEnd = this.PanelColors.XPanderPanelCaptionGradientEnd;
            Color colorGradientMiddle = this.PanelColors.XPanderPanelCaptionGradientMiddle;
            Color colorText = this.PanelColors.XPanderPanelCaptionText;
            Color foreColorCloseIcon = this.PanelColors.XPanderPanelCaptionCloseIcon;
            Color foreColorExpandIcon = this.PanelColors.XPanderPanelCaptionExpandIcon;
            bool bHover = this.HoverStateCaptionBar == HoverState.Hover ? true : false;

            if (this.m_imageClosePanel == null)
            {
                this.m_imageClosePanel = Resources.closePanel;
            }
            if (this.m_imageChevronUp == null)
            {
                this.m_imageChevronUp = Resources.ChevronUp;
            }
            if (this.m_imageChevronDown == null)
            {
                this.m_imageChevronDown = Resources.ChevronDown;
            }
            
            this.m_imageChevron = this.m_imageChevronDown;
            if (bExpand == true)
            {
                this.m_imageChevron = this.m_imageChevronUp;
            }

            if (this.m_captionStyle == CaptionStyle.Normal)
            {
                if (bHover == true)
                {
                    colorGradientBegin = this.PanelColors.XPanderPanelSelectedCaptionBegin;
                    colorGradientEnd = this.PanelColors.XPanderPanelSelectedCaptionEnd;
                    colorGradientMiddle = this.PanelColors.XPanderPanelSelectedCaptionMiddle;
                    if (bExpand == true)
                    {
                        colorGradientBegin = this.PanelColors.XPanderPanelPressedCaptionBegin;
                        colorGradientEnd = this.PanelColors.XPanderPanelPressedCaptionEnd;
                        colorGradientMiddle = this.PanelColors.XPanderPanelPressedCaptionMiddle;
                    }
                    colorText = this.PanelColors.XPanderPanelSelectedCaptionText;
                    foreColorCloseIcon = colorText;
                    foreColorExpandIcon = colorText;
                }
                else
                {
                    if (bExpand == true)
                    {
                        colorGradientBegin = this.PanelColors.XPanderPanelCheckedCaptionBegin;
                        colorGradientEnd = this.PanelColors.XPanderPanelCheckedCaptionEnd;
                        colorGradientMiddle = this.PanelColors.XPanderPanelCheckedCaptionMiddle;
                        colorText = this.PanelColors.XPanderPanelSelectedCaptionText;
                        foreColorCloseIcon = colorText;
                        foreColorExpandIcon = colorText;
                    }
                }
                if (panelStyle != PanelStyle.Office2007)
                {
                    RenderDoubleBackgroundGradient(
                    graphics,
                    captionRectangle,
                    colorGradientBegin,
                    colorGradientMiddle,
                    colorGradientEnd,
                    LinearGradientMode.Vertical,
                    false);
                }
                else
                {
                    RenderButtonBackground(
                        graphics,
                        captionRectangle,
                        colorGradientBegin,
                        colorGradientMiddle,
                        colorGradientEnd);
                }
            }
            else
            {
                Color colorFlatGradientBegin = this.PanelColors.XPanderPanelFlatCaptionGradientBegin;
                Color colorFlatGradientEnd = this.PanelColors.XPanderPanelFlatCaptionGradientEnd;
                Color colorInnerBorder = this.PanelColors.InnerBorderColor;
                colorText = this.PanelColors.XPanderPanelCaptionText;
                foreColorExpandIcon = colorText;

                RenderFlatButtonBackground(graphics, captionRectangle, colorFlatGradientBegin, colorFlatGradientEnd, bHover);
                DrawInnerBorders(graphics, this);
            }

            DrawImagesAndText(
                graphics,
                captionRectangle,
                CaptionSpacing,
                this.ImageRectangle,
                this.Image,
                this.RightToLeft,
                this.m_bIsClosable,
                this.ShowCloseIcon,
                this.m_imageClosePanel,
                foreColorCloseIcon,
                ref this.RectangleCloseIcon,
                this.ShowExpandIcon,
                this.m_imageChevron,
                foreColorExpandIcon,
                ref this.RectangleExpandIcon,
                this.CaptionFont,
                colorText,
                this.Text);
        }

        private static void DrawBorders(Graphics graphics, XPanderPanel xpanderPanel)
        {
            if (xpanderPanel.ShowBorder == true)
            {
                using (GraphicsPath graphicsPath = new GraphicsPath())
                {
                    using (Pen borderPen = new Pen(xpanderPanel.PanelColors.BorderColor, Constants.BorderThickness))
                    {
                        Rectangle captionRectangle = xpanderPanel.CaptionRectangle;
                        Rectangle borderRectangle = captionRectangle;

                        if (xpanderPanel.Expand == true)
                        {
                            borderRectangle = xpanderPanel.ClientRectangle;

                            graphics.DrawLine(
                                borderPen,
                                captionRectangle.Left,
                                captionRectangle.Top + captionRectangle.Height - Constants.BorderThickness,
                                captionRectangle.Left + captionRectangle.Width,
                                captionRectangle.Top + captionRectangle.Height - Constants.BorderThickness);
                        }

                        XPanderPanelList xpanderPanelList = xpanderPanel.Parent as XPanderPanelList;
                        if ((xpanderPanelList != null) && (xpanderPanelList.Dock == DockStyle.Fill))
                        {
                            BSE.Windows.Forms.Panel panel = xpanderPanelList.Parent as BSE.Windows.Forms.Panel;
                            XPanderPanel parentXPanderPanel = xpanderPanelList.Parent as XPanderPanel;
                            if (((panel != null) && (panel.Padding == new Padding(0))) ||
                                ((parentXPanderPanel != null) && (parentXPanderPanel.Padding == new Padding(0))))
                            {
                                if (xpanderPanel.Top != 0)
                                {
                                    graphicsPath.AddLine(
                                        borderRectangle.Left,
                                        borderRectangle.Top,
                                        borderRectangle.Left + captionRectangle.Width,
                                        borderRectangle.Top);
                                }

                                // Left vertical borderline
                                graphics.DrawLine(borderPen,
                                    borderRectangle.Left,
                                    borderRectangle.Top,
                                    borderRectangle.Left,
                                    borderRectangle.Top + borderRectangle.Height);

                                // Right vertical borderline
                                graphics.DrawLine(borderPen,
                                    borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                    borderRectangle.Top,
                                    borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                    borderRectangle.Top + borderRectangle.Height);
                            }
                            else
                            {
                                // Upper horizontal borderline only at the top xpanderPanel
                                if (xpanderPanel.Top == 0)
                                {
                                    graphicsPath.AddLine(
                                        borderRectangle.Left,
                                        borderRectangle.Top,
                                        borderRectangle.Left + borderRectangle.Width,
                                        borderRectangle.Top);
                                }

                                // Left vertical borderline
                                graphicsPath.AddLine(
                                    borderRectangle.Left,
                                    borderRectangle.Top,
                                    borderRectangle.Left,
                                    borderRectangle.Top + borderRectangle.Height);

                                //Lower horizontal borderline
                                graphicsPath.AddLine(
                                    borderRectangle.Left,
                                    borderRectangle.Top + borderRectangle.Height - Constants.BorderThickness,
                                    borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                    borderRectangle.Top + borderRectangle.Height - Constants.BorderThickness);

                                // Right vertical borderline
                                graphicsPath.AddLine(
                                    borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                    borderRectangle.Top,
                                    borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                    borderRectangle.Top + borderRectangle.Height);
                            }
                        }
                        else
                        {
                            // Upper horizontal borderline only at the top xpanderPanel
                            if (xpanderPanel.Top == 0)
                            {
                                graphicsPath.AddLine(
                                    borderRectangle.Left,
                                    borderRectangle.Top,
                                    borderRectangle.Left + borderRectangle.Width,
                                    borderRectangle.Top);
                            }

                            // Left vertical borderline
                            graphicsPath.AddLine(
                                borderRectangle.Left,
                                borderRectangle.Top,
                                borderRectangle.Left,
                                borderRectangle.Top + borderRectangle.Height);

                            //Lower horizontal borderline
                            graphicsPath.AddLine(
                                borderRectangle.Left,
                                borderRectangle.Top + borderRectangle.Height - Constants.BorderThickness,
                                borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                borderRectangle.Top + borderRectangle.Height - Constants.BorderThickness);

                            // Right vertical borderline
                            graphicsPath.AddLine(
                                borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                borderRectangle.Top,
                                borderRectangle.Left + borderRectangle.Width - Constants.BorderThickness,
                                borderRectangle.Top + borderRectangle.Height);
                        }
                    }
                    using (Pen borderPen = new Pen(xpanderPanel.PanelColors.BorderColor, Constants.BorderThickness))
                    {
                        graphics.DrawPath(borderPen, graphicsPath);
                    }
                }
            }
        }


        private static void DrawInnerBorders(Graphics graphics, XPanderPanel xpanderPanel)
        {
            if (xpanderPanel.ShowBorder == true)
            {
                using (GraphicsPath graphicsPath = new GraphicsPath())
                {
                    Rectangle captionRectangle = xpanderPanel.CaptionRectangle;
                    XPanderPanelList xpanderPanelList = xpanderPanel.Parent as XPanderPanelList;
                    if ((xpanderPanelList != null) && (xpanderPanelList.Dock == DockStyle.Fill))
                    {
                        BSE.Windows.Forms.Panel panel = xpanderPanelList.Parent as BSE.Windows.Forms.Panel;
                        XPanderPanel parentXPanderPanel = xpanderPanelList.Parent as XPanderPanel;
                        if (((panel != null) && (panel.Padding == new Padding(0))) ||
                            ((parentXPanderPanel != null) && (parentXPanderPanel.Padding == new Padding(0))))
                        {
                            //Left vertical borderline
                            graphicsPath.AddLine(captionRectangle.X, captionRectangle.Y + captionRectangle.Height, captionRectangle.X, captionRectangle.Y + Constants.BorderThickness);
                            if (xpanderPanel.Top == 0)
                            {
                                //Upper horizontal borderline
                                graphicsPath.AddLine(captionRectangle.X, captionRectangle.Y, captionRectangle.X + captionRectangle.Width, captionRectangle.Y);
                            }
                            else
                            {
                                //Upper horizontal borderline
                                graphicsPath.AddLine(captionRectangle.X, captionRectangle.Y + Constants.BorderThickness, captionRectangle.X + captionRectangle.Width, captionRectangle.Y + Constants.BorderThickness);
                            }
                        }
                    }
                    else
                    {
                        //Left vertical borderline
                        graphicsPath.AddLine(captionRectangle.X + Constants.BorderThickness, captionRectangle.Y + captionRectangle.Height, captionRectangle.X + Constants.BorderThickness, captionRectangle.Y);
                        if (xpanderPanel.Top == 0)
                        {
                            //Upper horizontal borderline
                            graphicsPath.AddLine(captionRectangle.X + Constants.BorderThickness, captionRectangle.Y + Constants.BorderThickness, captionRectangle.X + captionRectangle.Width - Constants.BorderThickness, captionRectangle.Y + Constants.BorderThickness);
                        }
                        else
                        {
                            //Upper horizontal borderline
                            graphicsPath.AddLine(captionRectangle.X + Constants.BorderThickness, captionRectangle.Y, captionRectangle.X + captionRectangle.Width - Constants.BorderThickness, captionRectangle.Y);
                        }
                    }

                    using (Pen borderPen = new Pen(xpanderPanel.PanelColors.InnerBorderColor))
                    {
                        graphics.DrawPath(borderPen, graphicsPath);
                    }
                }
            }
        }

		private void CalculatePanelHeights()
		{
			if (this.Parent == null)
			{
				return;
			}

            int iPanelHeight = this.Parent.Padding.Top;

            foreach (Control control in this.Parent.Controls)
            {
				BSE.Windows.Forms.XPanderPanel xpanderPanel =
					control as BSE.Windows.Forms.XPanderPanel;

                if ((xpanderPanel != null) && (xpanderPanel.Visible == true))
                {
                    iPanelHeight += xpanderPanel.CaptionHeight;
                }
            }

			iPanelHeight += this.Parent.Padding.Bottom;

            foreach (Control control in this.Parent.Controls)
			{
				BSE.Windows.Forms.XPanderPanel xpanderPanel =
					control as BSE.Windows.Forms.XPanderPanel;

                if (xpanderPanel != null)
                {
                    if (xpanderPanel.Expand == true)
                    {
                        xpanderPanel.Height = this.Parent.Height
                            + xpanderPanel.CaptionHeight
                            - iPanelHeight;
                    }
                    else
                    {
                        xpanderPanel.Height = xpanderPanel.CaptionHeight;
                    }
                }
			}

			int iTop = this.Parent.Padding.Top;
			foreach (Control control in this.Parent.Controls)
			{
				BSE.Windows.Forms.XPanderPanel xpanderPanel =
					control as BSE.Windows.Forms.XPanderPanel;

                if ((xpanderPanel != null) && (xpanderPanel.Visible == true))
                {
                    xpanderPanel.Top = iTop;
                    iTop += xpanderPanel.Height;
                }
			}
		}

		#endregion
    }

    #endregion

    #region Class XPanderPanelDesigner
    /// <summary>
    /// Designer class for extending the design mode behavior of a XPanderPanel control
    /// </summary>
	internal class XPanderPanelDesigner : System.Windows.Forms.Design.ScrollableControlDesigner
	{
		#region FieldsPrivate

		private Pen m_borderPen = new Pen(Color.FromKnownColor(KnownColor.ControlDarkDark));
        private System.Windows.Forms.Design.Behavior.Adorner m_adorner;

		#endregion

		#region MethodsPublic
		/// <summary>
        /// Initializes a new instance of the XPanderPanelDesigner class.
		/// </summary>
		public XPanderPanelDesigner()
		{
			this.m_borderPen.DashStyle = DashStyle.Dash;
		}
		/// <summary>
		/// Initializes the designer with the specified component.
		/// </summary>
		/// <param name="component">The IComponent to associate with the designer.</param>
		public override void Initialize(IComponent component)
		{
			base.Initialize(component);
            XPanderPanel xpanderPanel = Control as XPanderPanel;
            if (xpanderPanel != null)
            {
                this.m_adorner = new System.Windows.Forms.Design.Behavior.Adorner();
                BehaviorService.Adorners.Add(this.m_adorner);
                this.m_adorner.Glyphs.Add(new XPanderPanelCaptionGlyph(BehaviorService, xpanderPanel));
            }
		}
		#endregion

		#region MethodsProtected
        /// <summary>
        /// Releases the unmanaged resources used by the XPanderPanelDesigner,
        /// and optionally releases the managed resources. 
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources;
        /// false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
			try
			{
				if (disposing)
				{
					if (this.m_borderPen != null)
					{
						this.m_borderPen.Dispose();
					}
					if (this.m_adorner != null)
					{
						if (BehaviorService != null)
						{
							BehaviorService.Adorners.Remove(this.m_adorner);
						}
					}
				}
			}
			finally
			{
				base.Dispose(disposing);
			}
        }
		/// <summary>
		/// Receives a call when the control that the designer is managing has painted its surface so the designer can
		/// paint any additional adornments on top of the xpanderpanel.
		/// </summary>
		/// <param name="e">A PaintEventArgs the designer can use to draw on the xpanderpanel.</param>
		protected override void OnPaintAdornments(PaintEventArgs e)
		{
			base.OnPaintAdornments(e);
			e.Graphics.DrawRectangle(
				this.m_borderPen,
				0,
				0,
				this.Control.Width - 2,
				this.Control.Height - 2);
		}
		/// <summary>
		/// Allows a designer to change or remove items from the set of properties that it exposes through a <see cref="TypeDescriptor">TypeDescriptor</see>. 
		/// </summary>
		/// <param name="properties">The properties for the class of the component.</param>
		protected override void PostFilterProperties(IDictionary properties)
		{
			base.PostFilterProperties(properties);
			properties.Remove("AccessibilityObject");
			properties.Remove("AccessibleDefaultActionDescription");
			properties.Remove("AccessibleDescription");
			properties.Remove("AccessibleName");
			properties.Remove("AccessibleRole");
			properties.Remove("AllowDrop");
            properties.Remove("Anchor");
            properties.Remove("AntiAliasing");
			properties.Remove("AutoScroll");
			properties.Remove("AutoScrollMargin");
			properties.Remove("AutoScrollMinSize");
            properties.Remove("BackColor");
            properties.Remove("BackgroundImage");
			properties.Remove("BackgroundImageLayout");
			properties.Remove("CausesValidation");
			properties.Remove("ContextMenuStrip");
			properties.Remove("Dock");
			properties.Remove("GenerateMember");
			properties.Remove("ImeMode");
            properties.Remove("Location");
			properties.Remove("MaximumSize");
			properties.Remove("MinimumSize");
		}

		#endregion
    }
    #endregion

    #region Class XPanderPanelCaptionGlyph
    /// <summary>
    /// Represents a single user interface (UI) entity managed by an Adorner.
    /// </summary>
    internal class XPanderPanelCaptionGlyph : System.Windows.Forms.Design.Behavior.Glyph
    {
        #region FieldsPrivate

        private XPanderPanel m_xpanderPanel;
        private System.Windows.Forms.Design.Behavior.BehaviorService m_behaviorService;

        #endregion

        #region Properties
        /// <summary>
        /// Gets the bounds of the Glyph.
        /// </summary>
        public override Rectangle Bounds
        {
            get
            {
                Point edge = this.m_behaviorService.ControlToAdornerWindow(this.m_xpanderPanel);
                Rectangle bounds = new Rectangle(
                    edge.X,
                    edge.Y,
                    this.m_xpanderPanel.Width,
                    this.m_xpanderPanel.CaptionHeight);

                return bounds;
            }
        }
        #endregion

        #region MethodsPublic
        /// <summary>
        /// Initializes a new instance of the CaptionGlyph class.
        /// </summary>
        /// <param name="behaviorService"></param>
        /// <param name="xpanderPanel"></param>
        public XPanderPanelCaptionGlyph(System.Windows.Forms.Design.Behavior.BehaviorService behaviorService, XPanderPanel xpanderPanel)
            :
            base(new XPanderPanelCaptionClickBehavior(xpanderPanel))
        {
            this.m_behaviorService = behaviorService;
            this.m_xpanderPanel = xpanderPanel;
        }
        /// <summary>
        /// Provides hit test logic.
        /// </summary>
        /// <param name="p">A point to hit-test.</param>
        /// <returns>A Cursor if the Glyph is associated with p; otherwise, a null reference</returns>
        public override Cursor GetHitTest(Point p)
        {
            // GetHitTest is called to see if the point is
            // within this glyph.  This gives us a chance to decide
            // what cursor to show.  Returning null from here means
            // the mouse pointer is not currently inside of the glyph.
            // Returning a valid cursor here indicates the pointer is
            // inside the glyph, and also enables our Behavior property
            // as the active behavior.
            if ((this.m_xpanderPanel != null) && (this.m_xpanderPanel.Expand == false) && (Bounds.Contains(p)))
            {
                return Cursors.Hand;
            }

            return null;
        }
        /// <summary>
        /// Provides paint logic.
        /// </summary>
        /// <param name="pe">A PaintEventArgs that contains the event data.</param>
        public override void Paint(PaintEventArgs pe)
        {
        }

        #endregion
    }

    #endregion

    #region Class XPanderPanelCaptionClickBehavior
    /// <summary>
    /// Designer behaviour when the user clicks in the glyph on the XPanderPanel caption
    /// </summary>
    internal class XPanderPanelCaptionClickBehavior : System.Windows.Forms.Design.Behavior.Behavior
    {
        #region FieldsPrivate
        private XPanderPanel m_xpanderPanel;
        #endregion

        #region MethodsPublic
        /// <summary>
        /// Initializes a new instance of the Behavior class.
        /// </summary>
        /// <param name="xpanderPanel">XPanderPanel for this behaviour</param>
        public XPanderPanelCaptionClickBehavior(XPanderPanel xpanderPanel)
        {
            this.m_xpanderPanel = xpanderPanel;
        }
        /// <summary>
        /// Called when any mouse-down message enters the adorner window of the BehaviorService. 
        /// </summary>
        /// <param name="g">A Glyph.</param>
        /// <param name="button">A MouseButtons value indicating which button was clicked.</param>
        /// <param name="mouseLoc">The location at which the click occurred.</param>
        /// <returns>true if the message was handled; otherwise, false. </returns>
		public override bool OnMouseDown(System.Windows.Forms.Design.Behavior.Glyph g, MouseButtons button, Point mouseLoc)
		{
			if ((this.m_xpanderPanel != null) && (this.m_xpanderPanel.Expand == false))
			{
				XPanderPanelList xpanderPanelList = this.m_xpanderPanel.Parent as XPanderPanelList;
				if (xpanderPanelList != null)
				{
					xpanderPanelList.Expand(this.m_xpanderPanel);
					this.m_xpanderPanel.Invalidate(false);
				}
			}
			return true; // indicating we processed this event.
		}
        #endregion
    }

    #endregion
}
