/// <summary>
 /// Handle the <see cref="ZeroitPandaPanel.PropertyChange" /> event
 /// </summary>
 /// <param name="xpPanel">The <see cref="ZeroitPandaPanel" /> whose property changed</param>
 /// <param name="e">instance of <see cref="ZeroitPandaPanelPropertyChangeEventArgs" /> describing the property change</param>
 /// <remarks>Currently we handle the <see cref="ZeroitPandaPanelProperties.PanelHeightProperty" /> so that we can
 /// ensure that the entire panel is visible. The <see cref="ZeroitPandaPanelProperties.PanelHeightProperty" />
 /// is only changed when a <see cref="ZeroitPandaPanel" /> resizes due to a change in the size of child
 /// controls. Typically this indicates some interest/focus on the users part, but you may want to
 /// supress this event if these changes are 'randomesque' in your application</remarks>
 private void ZeroitPandaPanelGroup_PropertyChange(ZeroitPandaPanel xpPanel, ZeroitPandaPanelPropertyChangeEventArgs e)
 {
     if (e.ZeroitPandaPanelProperty == ZeroitPandaPanelProperties.PanelHeightProperty)
     {
         EnsureVisible(xpPanel);
     }
 }
        /// <summary>
        /// Update the location and width of all the <see cref="ZeroitPandaPanel" /> controls
        /// in the <see cref="ZeroitPandaPanelGroup" />
        /// </summary>
        private void UpdatePanels()
        {
            int lastBottom = 0;

            if (isInitializingComponent || updatingPanels)
            {
                return;
            }

            updatingPanels = true;

            for (int i = 0; i < panels.Count; i++)
            {
                ZeroitPandaPanel panel = (ZeroitPandaPanel)panels[i];

                if (!panel.Visible)
                {
                    continue;
                }

                UpdatePanel(panel, lastBottom);
                lastBottom = panel.Top + panel.Height;
            }

            updatingPanels = false;
        }
        /// <summary>
        /// Update an individual <see cref="ZeroitPandaPanel" />
        /// </summary>
        /// <param name="panel">The panel to be updated</param>
        /// <param name="lastBottom">Bottom position of last <see cref="ZeroitPandaPanel" /> or 0 if this is the 1st panel
        /// in the <c>ZeroitPandaPanelGroup</c></param>
        private void UpdatePanel(ZeroitPandaPanel panel, int lastBottom)
        {
            if (panel.Left != BorderMargin.Width)
            {
                panel.Left = BorderMargin.Width;
            }

            if (lastBottom != 0)
            {
                if (panel.Top != lastBottom + PanelSpacing)
                {
                    panel.Top = lastBottom + PanelSpacing;
                }
            }
            else
            {
                if (panel.Top != lastBottom + BorderMargin.Height)
                {
                    panel.Top = lastBottom + BorderMargin.Height;
                }
            }

            if (panel.Width != this.Width - (BorderMargin.Width << 1) - (VScroll ? SystemInformation.VerticalScrollBarWidth : 0))
            {
                panel.Width = this.Width - (BorderMargin.Width << 1) - (VScroll ? SystemInformation.VerticalScrollBarWidth : 0);
            }
        }
        /// <summary>
        /// Change the order/position of the specified <see cref="ZeroitPandaPanel" />
        /// </summary>
        /// <param name="newIndex">The new index/position</param>
        /// <param name="xpPanel">The <see cref="ZeroitPandaPanel" /> to move</param>
        public void MovePanel(int newIndex, ZeroitPandaPanel xpPanel)
        {
            int indexOf = panels.IndexOf(xpPanel);

            if ((indexOf != -1) && (indexOf != newIndex))
            {
                panels.RemoveAt(indexOf);
                panels.Insert(newIndex, xpPanel);
                UpdatePanels();
            }
        }
        /// <summary>
        /// <see cref="ZeroitPandaPanel.PanelStateChange" /> event handler
        /// </summary>
        /// <param name="sender">The <see cref="ZeroitPandaPanel" /> that changed</param>
        /// <param name="e"><see cref="System.EventArgs.Empty" /></param>
        private void ZeroitPandaPanelGroup_PanelStateChange(object sender, EventArgs e)
        {
            ZeroitPandaPanel panel = sender as ZeroitPandaPanel;

            // sometimes this needs to be forced
            if (panel.Width != this.Width - (BorderMargin.Width << 1) - (VScroll ? SystemInformation.VerticalScrollBarWidth : 0))
            {
                panel.Width = this.Width - (BorderMargin.Width << 1) - (VScroll ? SystemInformation.VerticalScrollBarWidth : 0);
            }

            UpdatePanelsAfter((ZeroitPandaPanel)sender);
        }
        /// <summary>
        /// Set the height of the <c>ItemLayoutPanel</c> and if applicable, the height
        /// of parent <see cref="ZeroitPandaPanel" />'s panel area to match our height (with
        /// a little margin)
        /// </summary>
        /// <param name="bestHeight">The best height as determined by the layout engine</param>
        public virtual void SetBestHeight(int bestHeight)
        {
            this.Height = bestHeight;

            if (!DesignMode)
            {
                ZeroitPandaPanel panel = Parent as ZeroitPandaPanel;
                if (panel != null)
                {
                    panel.PanelHeight = bestHeight + 12;
                }
            }
        }
        /// <summary>
        /// Ensure that the specified panel is fully visible (if possible) within
        /// the <c>ZeroitPandaPanelGroup</c>
        /// </summary>
        /// <param name="xpPanel">The <see cref="ZeroitPandaPanel" /> to make visible</param>
        /// <exception cref="System.ArgumentException">The specified ZeroitPandaPanel is not a member of this ZeroitPandaPanelGroup - ZeroitPandaPanel</exception>
        /// <exception cref="ArgumentException">If the specified <see cref="ZeroitPandaPanel" /> is not
        /// a member of the <c>ZeroitPandaPanelGroup</c></exception>
        /// <remarks>If the panel is not visible it is made visible. If the bottom of the panel
        /// not visible, the group is scrolled to make it visible, otherwise if the
        /// top of the panel is not visible the scroll is adjusted to make it visible</remarks>
        public void EnsureVisible(ZeroitPandaPanel xpPanel)
        {
            if (!panels.Contains(xpPanel))
            {
                throw new ArgumentException("The specified ZeroitPandaPanel is not a member of this ZeroitPandaPanelGroup", "ZeroitPandaPanel");
            }

            if (!xpPanel.Visible)
            {
                xpPanel.Visible = true;
            }

            if (xpPanel.Bottom > (Height + AutoScrollPosition.Y))
            {
                AutoScrollPosition = new Point(AutoScrollPosition.X, xpPanel.Bottom - Height);
            }
            else if (xpPanel.Top < 0)
            {
                AutoScrollPosition = new Point(AutoScrollPosition.X, Math.Max(0, xpPanel.Top - 1));
            }
        }
        /// <summary>
        /// Update the location of all the <see cref="ZeroitPandaPanel" /> controls
        /// in the <see cref="ZeroitPandaPanelGroup" /> after a particular index
        /// </summary>
        /// <param name="panel">The panel.</param>
        /// <remarks>Used when a panel is collapsed or expanded to change all the
        /// subsequent panels</remarks>
        private void UpdatePanelsAfter(ZeroitPandaPanel panel)
        {
            // @@BUGFIX: 1.1
            if (!panel.Visible)
            {
                UpdatePanels();
                return;
            }

            if (isInitializingComponent || updatingPanels)
            {
                return;
            }

            updatingPanels = true;

            // the bottom of the specified panel plus the BorderMargin.Height (which we always need
            // to take into account)
            int lastBottom = panel.Top + panel.Height;

            // map the panel to its index in our panels collection
            int panelIndex = panels.IndexOf(panel) + 1;

            // for each following panel, relocate it
            for (int i = panelIndex; i < panels.Count; i++)
            {
                ZeroitPandaPanel nextPanel = (ZeroitPandaPanel)panels[i];

                // @@BUGFIX: 1.1
                if (!nextPanel.Visible)
                {
                    continue;
                }

                UpdatePanel(nextPanel, lastBottom);
                lastBottom = nextPanel.Top + nextPanel.Height;
            }

            updatingPanels = false;
        }
        /// <summary>
        /// Convert to an <see cref="InstanceDescriptor" /> if requested
        /// </summary>
        /// <param name="context">designer context</param>
        /// <param name="culture">globalization</param>
        /// <param name="value">the instance to convert</param>
        /// <param name="destinationType">The target type</param>
        /// <returns>An <see cref="InstanceDescriptor" /> if requested, otherwise whatever
        /// the base class returns</returns>
        public override object ConvertTo(
            ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture,
            object value,
            Type destinationType
            )
        {
            // the designer wants an InstanceDescriptor
            if ((destinationType == typeof(InstanceDescriptor)) && (value is ZeroitPandaPanel))
            {
                ZeroitPandaPanel xpPanel = value as ZeroitPandaPanel;
                // Get our ZeroitPandaPanel(int) constructor
                ConstructorInfo ctorInfo = typeof(ZeroitPandaPanel).GetConstructor(new Type[] { typeof(int) });
                if (ctorInfo != null)
                {
                    // use this constructor and pass in the ExpandedHeight value. Use false to say that
                    // initialization is NOT complete
                    return(new InstanceDescriptor(ctorInfo, new object[] { xpPanel.ExpandedHeight }, false));
                }
            }

            return(base.ConvertTo(context, culture, value, destinationType));
        }