using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.DotNetBar.SuperGrid.Primitives;
using DevComponents.DotNetBar.SuperGrid.Style;
using DevComponents.SuperGrid.TextMarkup;
namespace DevComponents.DotNetBar.SuperGrid
{
    ///
    /// GridGroup
    ///
    public class GridGroup : GridContainer
    {
        #region Static data
        private static bool _dragSelection;
        private static bool _dragStarted;
        #endregion
        #region Private variables
        private GridCell _Cell;
        private string _Text;
        private Size _TextSize;
        private Rectangle _ExpandButtonBounds;
        private int _AnchorIndex;
        private GroupArea _HitArea;
        private GridContainer _HitItem;
        private GroupArea _LastHitArea;
        private GroupArea _MouseDownHitArea;
        private Point _MouseDownPoint;
        private GridContainer _MouseDownHitRow;
        private GroupHeaderVisualStyles _GroupHeaderVisualStyles;
        private GroupHeaderVisualStyles _EffectiveVisualStyles;
        private int _StyleUpdateCount;
        private BodyElement _GroupTextMarkup;
        private object _GroupId;
        #endregion
        #region Public properties
        #region Bounds
        ///
        /// Bounds
        ///
        public override Rectangle Bounds
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    Rectangle r = BoundsRelative;
                    if (IsVFrozen == false)
                        r.Y -= VScrollOffset;
                    if (panel.IsSubPanel == true)
                        r.X -= HScrollOffset;
                    r.Height = FixedRowHeight;
                    Rectangle t = ViewRect;
                    if (r.Right > t.Right)
                        r.Width -= (r.Right - t.Right);
                    return (r);
                }
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region Cell
        ///
        /// Gets the Group's associated grid cell.
        ///
        public GridCell Cell
        {
            get { return (_Cell); }
            internal set { _Cell = value; }
        }
        #endregion
        #region Column
        ///
        /// Gets the Group's associated grid Column.
        ///
        public GridColumn Column
        {
            get { return (_Cell != null ? _Cell.GridColumn : null); }
        }
        #endregion
        #region GroupHeaderVisualStyles
        /// 
        /// Gets or sets the visual styles
        /// assigned to the element. Default value is null.
        /// 
        [DefaultValue(null), Category("Style")]
        [Description("Indicates visual style assigned to the element")]
        public GroupHeaderVisualStyles GroupHeaderVisualStyles
        {
            get
            {
                if (_GroupHeaderVisualStyles == null)
                {
                    _GroupHeaderVisualStyles = new GroupHeaderVisualStyles();
                    GroupHeaderStyleChangeHandler(null, _GroupHeaderVisualStyles);
                }
                return (_GroupHeaderVisualStyles);
            }
            set
            {
                if (_GroupHeaderVisualStyles != value)
                {
                    GroupHeaderVisualStyles oldValue = _GroupHeaderVisualStyles;
                    _GroupHeaderVisualStyles = value;
                    OnCellStyleChanged("GroupHeaderVisualStyle", oldValue, value);
                }
            }
        }
        private void OnCellStyleChanged(string property,
            GroupHeaderVisualStyles oldValue, GroupHeaderVisualStyles newValue)
        {
            GroupHeaderStyleChangeHandler(oldValue, newValue);
            OnPropertyChanged(property);
        }
        #endregion
        #region GroupValue
        ///
        /// GroupValue
        ///
        public object GroupValue
        {
            get { return (_Cell != null ? _Cell.Value : 0); }
        }
        #endregion
        #region PlainText
        ///
        /// Gets the "Plain" header Text (MiniMarkup stripped)
        ///
        public string PlainText
        {
            get
            {
                if (_GroupTextMarkup != null)
                    return (_GroupTextMarkup.PlainText);
                return (_Text);
            }
        }
        #endregion
        #region Text
        ///
        /// Text
        ///
        public string Text
        {
            get { return (_Text); }
            set
            {
                if (_Text != value)
                {
                    _Text = value;
                    MarkupGroupTextChanged();
                    OnPropertyChangedEx("Text", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region GroupId
        internal object GroupId
        {
            get { return (_GroupId); }
            set { _GroupId = value; }
        }
        #endregion
        #region GroupTextMarkup
        internal BodyElement GroupTextMarkup
        {
            get { return (_GroupTextMarkup); }
            set { _GroupTextMarkup = value; }
        }
        #endregion
        #endregion
        #region MeasureOverride
        #region MeasureOverride
        /// 
        /// MeasureOverride
        /// 
        /// 
        /// 
        /// 
        protected override void MeasureOverride(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize)
        {
            Size sizeNeeded = Size.Empty;
            GridPanel panel = stateInfo.GridPanel;
            Graphics g = layoutInfo.Graphics;
            if (CanShowRowHeader(panel) == true)
                sizeNeeded.Width += panel.RowHeaderWidthEx;
            GroupHeaderVisualStyle style = GetSizingStyle(panel);
            Size size = MeasureGroupText(g, style, constraintSize);
            if (size.Height > 0)
            {
                size.Height += Dpi.Height8;
                size.Width += Dpi.Width(style.Padding.Horizontal);
                size.Height += Dpi.Height(style.Padding.Vertical);
            }
            size.Height = Math.Max(size.Height, Dpi.Height(panel.GroupHeaderHeight));
            sizeNeeded.Width += size.Width;
            sizeNeeded.Height = Math.Max(size.Height, sizeNeeded.Height);
            if (panel.ShowGroupUnderline == true && size.Height > 0)
                sizeNeeded.Height += Dpi.Height4;
            FixedRowHeight = sizeNeeded.Height;
            if (Rows != null && Expanded == true)
            {
                if (panel.IndentGroups == true)
                {
                    GridLayoutStateInfo itemStateInfo = new
                        GridLayoutStateInfo(panel, stateInfo.IndentLevel + 1);
                    size = MeasureSubItems(layoutInfo, itemStateInfo, constraintSize);
                }
                else
                {
                    size = MeasureSubItems(layoutInfo, stateInfo, constraintSize);
                }
                sizeNeeded.Width = Math.Max(size.Width, sizeNeeded.Width);
                sizeNeeded.Height += size.Height;
            }
            Size = sizeNeeded;
        }
        #endregion
        #region MeasureGroupText
        private Size MeasureGroupText(Graphics g,
            GroupHeaderVisualStyle style, Size constraintSize)
        {
            _TextSize = Size.Empty;
            if (String.IsNullOrEmpty(Text) == false)
            {
                GridPanel panel = GridPanel;
                if (panel.IsSubPanel == false)
                {
                    if (panel.ShowGroupExpand == true)
                    {
                        constraintSize.Width = SViewRect.Width;
                        int n = panel.TreeButtonIndent +
                                Dpi.Width(panel.LevelIndentSize.Width * IndentLevel);
                        constraintSize.Width -= n;
                    }
                }
                _TextSize = MeasureHeaderText(g, style, constraintSize);
            }
            return (_TextSize);
        }
        #region MeasureHeaderText
        private Size MeasureHeaderText(Graphics g,
            GroupHeaderVisualStyle style, Size constraintSize)
        {
            Size size = Size.Empty;
            string s = Text;
            if (string.IsNullOrEmpty(s) == false)
            {
                if (_GroupTextMarkup != null)
                {
                    size = GetMarkupTextSize(g,
                        _GroupTextMarkup, style, constraintSize.Width);
                }
                else
                {
                    eTextFormat tf = style.GetTextFormatFlags();
                    size = (constraintSize.IsEmpty == true)
                               ? TextHelper.MeasureText(g, s, style.Font)
                               : TextHelper.MeasureText(g, s, style.Font, constraintSize, tf);
                }
            }
            return (size);
        }
        #region GetMarkupTextSize
        private Size GetMarkupTextSize(Graphics g,
            BodyElement textMarkup, GroupHeaderVisualStyle style, int width)
        {
            MarkupDrawContext d =
                new MarkupDrawContext(g, style.Font, style.TextColor, false);
            textMarkup.InvalidateElementsSize();
            textMarkup.Measure(new Size(width, 0), d);
            return (textMarkup.Bounds.Size);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region ArrangeOverride
        /// 
        /// ArrangeOverride
        /// 
        /// 
        /// 
        /// 
        protected override void ArrangeOverride(GridLayoutInfo layoutInfo,
            GridLayoutStateInfo stateInfo, Rectangle layoutBounds)
        {
            Rectangle bounds = layoutBounds;
            bounds.Height = FixedRowHeight;
            GridPanel panel = stateInfo.GridPanel;
            IndentLevel = stateInfo.IndentLevel;
            if (panel.ShowGroupExpand == true)
            {
                GroupHeaderVisualStyle style = GetSizingStyle(panel);
                Rectangle r = bounds;
                r.Width = Dpi.Width(panel.LevelIndentSize.Width);
                r.Height -= Dpi.Height(style.Padding.Vertical);
                int n = Dpi.Height(panel.GroupHeaderHeight);
                if (r.Height < n)
                    r.Height = n;
                if (CanShowRowHeader(panel) == true)
                    r.X += panel.RowHeaderWidthEx;
                n = panel.TreeButtonIndent +
                    Dpi.Width((panel.LevelIndentSize.Width * IndentLevel) - panel.LevelIndentSize.Width);
                r.X += n;
                if (r.Right > BoundsRelative.Right)
                    r.Width -= r.Right - BoundsRelative.Right;
                r.X += Dpi.Width(style.Padding.Left);
                r.Y += Dpi.Height(style.Padding.Top);
                Size size = panel.GetTreeButtonSize();
                r.X += (r.Width - size.Width) / 2;
                r.Y += (r.Height - size.Height) / 2 - 1;
                r.Size = size;
                _ExpandButtonBounds = r;
            }
            else
            {
                _ExpandButtonBounds = Rectangle.Empty;
            }
            if (Rows != null && Expanded == true)
            {
                bounds = layoutBounds;
                bounds.Y += FixedRowHeight;
                bounds.Height -= FixedRowHeight;
                if (panel.IndentGroups == true)
                {
                    GridLayoutStateInfo itemStateInfo =
                        new GridLayoutStateInfo(panel, stateInfo.IndentLevel + 1);
                    ArrangeSubItems(layoutInfo, itemStateInfo, bounds);
                }
                else
                {
                    ArrangeSubItems(layoutInfo, stateInfo, bounds);
                }
            }
        }
        #endregion
        #region RenderOverride
        /// 
        /// RenderOverride
        /// 
        /// 
        protected override void RenderOverride(GridRenderInfo renderInfo)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                Rectangle r = Bounds;
                if (r.IntersectsWith(renderInfo.ClipRectangle))
                {
                    Graphics g = renderInfo.Graphics;
                    GroupHeaderVisualStyle style = GetEffectiveStyle();
                    if (SuperGrid.DoPreRenderGroupHeaderEvent(g,
                        this, RenderParts.Background | RenderParts.RowHeader, r) == false)
                    {
                        RenderGroupBackground(g, style, r);
                        RenderRowHeader(g, panel, style, r);
                        SuperGrid.DoPostRenderGroupHeaderEvent(g,
                            this, RenderParts.Background | RenderParts.RowHeader, r);
                    }
                    if (CanShowRowHeader(panel) == true)
                    {
                        r.X += panel.RowHeaderWidthEx;
                        r.Width -= panel.RowHeaderWidthEx;
                    }
                    
                    RenderHeaderExpand(g, panel, ref r);
                    r = GetAdjustedBounds(style, r);
                    int n = Dpi.Width(panel.GroupHeaderHeight);
                    if (r.Height < n)
                        r.Height = n;
                    if (SuperGrid.DoPreRenderGroupHeaderEvent(g,
                        this, RenderParts.Content, r) == false)
                    {
                        RenderHeaderText(g, style, r);
                        RenderHeaderUnderline(g, panel, style, r);
                        SuperGrid.DoPostRenderGroupHeaderEvent(g,
                            this, RenderParts.Content, r);
                    }
                }
                if (Rows != null && Expanded == true)
                {
                    UpdateMergeFlags();
                    foreach (GridElement item in Rows)
                    {
                        if (item.Visible == true)
                            item.Render(renderInfo);
                    }
                }
            }
        }
        #region GetAdjustedBounds
        private Rectangle GetAdjustedBounds(GroupHeaderVisualStyle style, Rectangle r)
        {
            r.X += Dpi.Width(style.Padding.Left);
            r.Width -= Dpi.Width(style.Padding.Horizontal);
            r.Y += Dpi.Height(style.Padding.Top + 2);
            r.Height -= Dpi.Height(style.Padding.Vertical + 2);
            return (r);
        }
        #endregion
        #region RenderRowHeader
        private void RenderRowHeader(Graphics g,
            GridPanel panel, GroupHeaderVisualStyle style, Rectangle r)
        {
            if (CanShowRowHeader(panel) == true)
            {
                r.Width = panel.RowHeaderWidthEx;
                using (Brush br = style.RowHeaderStyle.Background.GetBrush(r))
                    g.FillRectangle(br, r);
                GridPanelVisualStyle pstyle = panel.GetEffectiveStyle();
                if (Dpi.Height1 == Dpi.Width1)
                {
                    using (Pen pen = new Pen(style.RowHeaderStyle.BorderHighlightColor, Dpi.Height1))
                    {
                        g.DrawLine(pen, r.X + 1, r.Top, r.Right - 2, r.Top);
                        g.DrawLine(pen, r.X + 1, r.Top, r.X + 1, r.Bottom - 1);
                    }
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Height1))
                    {
                        g.DrawLine(pen, r.X, r.Top - 1, r.Right - 1, r.Top - 1);
                        g.DrawLine(pen, r.X, r.Bottom - 1, r.Right - 2, r.Bottom - 1);
                        g.DrawLine(pen, r.Right - 1, r.Top, r.Right - 1, r.Bottom - 1);
                    }
                }
                else
                {
                    using (Pen pen = new Pen(style.RowHeaderStyle.BorderHighlightColor, Dpi.Height1))
                        g.DrawLine(pen, r.X + 1, r.Top, r.Right - 2, r.Top);
                    using (Pen pen = new Pen(style.RowHeaderStyle.BorderHighlightColor, Dpi.Width1))
                        g.DrawLine(pen, r.X + 1, r.Top, r.X + 1, r.Bottom - 1);
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Height1))
                    {
                        g.DrawLine(pen, r.X, r.Top - 1, r.Right - 1, r.Top - 1);
                        g.DrawLine(pen, r.X, r.Bottom - 1, r.Right - 2, r.Bottom - 1);
                    }
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Width1))
                        g.DrawLine(pen, r.Right - 1, r.Top, r.Right - 1, r.Bottom - 1);
                }
                r.X += Dpi.Width4;
                r.Width -= Dpi.Width4;
                int n = RenderIndicatorImage(g, panel, this, r);
                r.X += n;
                r.Width -= n;
                if (panel.ShowRowGridIndex == true)
                    RenderGridIndex(g, this, style.RowHeaderStyle, r);
            }
        }
        #region RenderIndicatorImage
        private int RenderIndicatorImage(Graphics g,
            GridPanel panel, GridContainer row, Rectangle r)
        {
            RowHeaderVisualStyle style = GetEffectiveRowStyle().RowHeaderStyle;
            Image image = style.GetActiveRowImage(panel);
            if (image != null)
            {
                if (panel.ActiveRow == row)
                {
                    if (panel.ActiveRowIndicatorStyle == ActiveRowIndicatorStyle.Image ||
                        panel.ActiveRowIndicatorStyle == ActiveRowIndicatorStyle.Both)
                    {
                        Rectangle u = r;
                        u.Size = image.Size;
                        if (r.Height > u.Height)
                            u.Y += (r.Height - u.Height) / 2;
                        u.Intersect(r);
                        g.DrawImageUnscaledAndClipped(image, u);
                    }
                }
                return (image.Width);
            }
            return (0);
        }
        #endregion
        #region RenderGridIndex
        private void RenderGridIndex(Graphics g,
            GridContainer row, RowHeaderVisualStyle style, Rectangle r)
        {
            string text = (row.GridIndex + row.GridPanel.RowHeaderIndexOffset).ToString();
            Font font = style.Font ?? SystemFonts.DefaultFont;
            r.Inflate(-2, 0);
            TextDrawing.DrawString(g, text,
                font, style.TextColor, r, style.GetTextFormatFlags());
            return;
        }
        #endregion
        #endregion
        #region CanShowRowHeader
        /// 
        /// CanShowRowHeader
        /// 
        /// 
        /// 
        protected virtual bool CanShowRowHeader(GridPanel panel)
        {
            switch (panel.GroupRowHeaderVisibility)
            {
                case RowHeaderVisibility.Always:
                    return (true);
                case RowHeaderVisibility.PanelControlled:
                    return (panel.ShowRowHeaders);
            }
            return (false);
        }
        #endregion
        #region RenderGroupBackground
        private void RenderGroupBackground(
            Graphics g, GroupHeaderVisualStyle style, Rectangle r)
        {
            if (style.Background != null && style.Background.IsEmpty == false)
            {
                using (Brush br = style.Background.GetBrush(r))
                    g.FillRectangle(br, r);
            }
        }
        #endregion
        #region RenderHeaderExpand
        private void RenderHeaderExpand(
            Graphics g, GridPanel panel, ref Rectangle r)
        {
            if (panel.ShowGroupExpand == true)
            {
                Rectangle bounds = _ExpandButtonBounds;
                if (IsVFrozen == false)
                    bounds.Y -= VScrollOffset;
                if (panel.IsSubPanel == true)
                    bounds.X -= HScrollOffset;
                bool hot = (_HitArea == GroupArea.ExpandButton);
                Image image = (Expanded == true)
                    ? panel.GetCollapseButton(g, hot) : panel.GetExpandButton(g, hot);
                ExpandDisplay.RenderButton(g, image, bounds, r);
                int n = panel.TreeButtonIndent +
                    Dpi.Width(panel.LevelIndentSize.Width * IndentLevel);
                r.X += n;
                r.Width -= n;
            }
            else
            {
                r.X += Dpi.Width3;
                r.Width -= Dpi.Width3;
            }
        }
        #endregion
        #region RenderHeaderText
        private void RenderHeaderText(Graphics g,
            GroupHeaderVisualStyle style, Rectangle r)
        {
            eTextFormat tf = style.GetTextFormatFlags();
            if (style.Alignment == Alignment.BottomLeft ||
                style.Alignment == Alignment.BottomCenter ||
                style.Alignment == Alignment.BottomRight)
            {
                r.Height -= Dpi.Height4;
            }
            if (r.Width > 0 && r.Height > 0)
            {
                if (_GroupTextMarkup != null)
                    RenderTextMarkup(g, _GroupTextMarkup, style, r);
                else
                    TextDrawing.DrawString(g, Text, style.Font, style.TextColor, r, tf);
            }
        }
        #region RenderTextMarkup
        private void RenderTextMarkup(Graphics g,
            BodyElement textMarkup, GroupHeaderVisualStyle style, Rectangle r)
        {
            MarkupDrawContext d =
                new MarkupDrawContext(g, style.Font, style.TextColor, false);
            textMarkup.Arrange(new Rectangle(r.Location, r.Size), d);
            Size size = textMarkup.Bounds.Size;
            switch (style.Alignment)
            {
                case Alignment.MiddleLeft:
                case Alignment.MiddleCenter:
                case Alignment.MiddleRight:
                    if (r.Height > size.Height)
                        r.Y += (r.Height - size.Height) / 2;
                    break;
                default:
                    if (r.Height > size.Height)
                        r.Y = r.Bottom - size.Height;
                    break;
            }
            textMarkup.Bounds = new Rectangle(r.Location, size);
            Region oldClip = g.Clip;
            try
            {
                g.SetClip(r, CombineMode.Intersect);
                textMarkup.Render(d);
            }
            finally
            {
                g.Clip = oldClip;
            }
        }
        #endregion
        #endregion
        #region RenderHeaderUnderline
        private void RenderHeaderUnderline(Graphics g,
            GridPanel panel, GroupHeaderVisualStyle style, Rectangle r)
        {
            if (panel.ShowGroupUnderline == true && style.UnderlineColor.IsEmpty == false)
            {
                switch (style.Alignment)
                {
                    case Alignment.MiddleLeft:
                    case Alignment.MiddleCenter:
                    case Alignment.MiddleRight:
                        r.Y += (r.Height + _TextSize.Height) / 2 + Dpi.Height4;
                        break;
                    case Alignment.TopLeft:
                    case Alignment.TopCenter:
                    case Alignment.TopRight:
                        r.Y += _TextSize.Height + Dpi.Height6;
                        break;
                    default:
                        r.Y = r.Bottom - _TextSize.Height / 2;
                        break;
                }
                if (r.Width > SViewRect.Width)
                    r.Width = SViewRect.Width;
                int n = r.Width;
                r.Height = Dpi.Height1;
                r.Width = (int)(r.Width * .75);
                Rectangle t = r;
                Color color1 = style.UnderlineColor;
                Color color2 = Color.Transparent;
                switch (style.Alignment)
                {
                    case Alignment.TopCenter:
                    case Alignment.MiddleCenter:
                    case Alignment.BottomCenter:
                        r.X += (n - r.Width) / 2;
                        r.Width /= 2;
                        color1 = Color.Transparent;
                        color2 = style.UnderlineColor;
                        break;
                    case Alignment.TopRight:
                    case Alignment.MiddleRight:
                    case Alignment.BottomRight:
                        r.X += n - r.Width;
                        color1 = Color.Transparent;
                        color2 = style.UnderlineColor;
                        break;
                }
                t.X = r.X;
                if ((r.Width > 0 && r.Height > 0) && (t.Width > 0 && t.Height > 0))
                {
                    using (LinearGradientBrush br = new
                        LinearGradientBrush(r, color1, color2, 0f))
                    {
                        br.WrapMode = WrapMode.TileFlipXY;
                        g.FillRectangle(br, t);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region Mouse support
        #region InternalMouseEnter
        internal override void InternalMouseEnter(EventArgs e)
        {
            base.InternalMouseEnter(e);
            InvalidateRender();
        }
        #endregion
        #region InternalMouseLeave
        internal override void InternalMouseLeave(EventArgs e)
        {
            base.InternalMouseLeave(e);
            InvalidateRender();
        }
        #endregion
        #region InternalMouseMove
        internal override void InternalMouseMove(MouseEventArgs e)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                if (IsMouseDown == true)
                    ProcessMouseDownMove(e, panel);
                ProcessMouseMove(e, panel);
            }
            if (Capture == false)
                base.InternalMouseMove(e);
        }
        #region ProcessMouseDownMove
        private void ProcessMouseDownMove(MouseEventArgs e, GridPanel panel)
        {
            Rectangle r = ViewRect;
            if (MouseDownPoint.Y < r.Y)
            {
                int n = SuperGrid.PrimaryGrid.FixedRowHeight -
                        SuperGrid.PrimaryGrid.FixedHeaderHeight;
                r.Y -= n;
                r.Height += n;
            }
            VScrollBarAdv vsb = SuperGrid.VScrollBar;
            if ((e.Y >= r.Y) && 
                (e.Y < r.Bottom || (vsb.Value >= vsb.Maximum - vsb.LargeChange)))
            {
                SuperGrid.DisableAutoScrolling();
                switch (_MouseDownHitArea)
                {
                    case GroupArea.Content:
                    case GroupArea.RowHeader:
                        _HitItem = GetRowAt(panel, e.Location);
                        if (_HitItem != null)
                        {
                            if (DragStarted(panel, e) == false)
                            {
                                if (panel.MultiSelect == true)
                                {
                                    if (_HitItem != panel.LastProcessedItem)
                                        ProcessExtendSelection(panel, true);
                                }
                            }
                        }
                        break;
                }
            }
            else
            {
                SuperGrid.EnableAutoScrolling(AutoScrollEnable.Vertical, r);
            }
        }
        #endregion
        #region ProcessMouseMove
        internal void ProcessMouseMove(MouseEventArgs e, GridPanel panel)
        {
            _HitArea = GetGroupAreaAt(e);
            switch (_HitArea)
            {
                case GroupArea.ExpandButton:
                    SuperGrid.GridCursor = Cursors.Hand;
                    break;
                default:
                    SuperGrid.GridCursor = Cursors.Default;
                    break;
            }
            if (_LastHitArea != _HitArea)
            {
                _LastHitArea = _HitArea;
                InvalidateRender();
            }
        }
        #endregion
        #region DragStarted
        private bool DragStarted(GridPanel panel, MouseEventArgs e)
        {
            if (_dragSelection == true && Capture == true)
            {
                if (_dragStarted == false)
                {
                    if (DragDrop.DragStarted(_MouseDownPoint, e.Location) == true)
                    {
                        _dragStarted = true;
                        if (SuperGrid.DoItemDragEvent(this, e) == true)
                        {
                            _dragSelection = false;
                            Capture = true;
                            InitExtendSelection(panel);
                        }
                    }
                }
                return (true);
            }
            return (false);
        }
        #endregion
        #endregion
        #region InternalMouseDown
        internal override void InternalMouseDown(MouseEventArgs e)
        {
            _MouseDownHitArea = _HitArea;
            _MouseDownHitRow = _HitItem;
            _MouseDownPoint = e.Location;
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                GridCell ecell = SuperGrid.EditorCell;
                if (ecell != null)
                {
                    if (ecell.EndEdit() == false)
                        return;
                }
                _dragSelection = false;
                _dragStarted = false;
                if (_MouseDownHitArea != GroupArea.NoWhere)
                {
                    if (_MouseDownHitArea == GroupArea.ExpandButton || 
                        panel.GroupHeaderClickBehavior == GroupHeaderClickBehavior.ExpandCollapse)
                    {
                            Expanded = !Expanded;
                    }
                    else
                    {
                        if (ShouldExtendSelection(panel) == true)
                        {
                            InitExtendSelection(panel);
                        }
                        else
                        {
                            if (IsMouseDown == true)
                            {
                                Capture = true;
                                _dragSelection = true;
                            }
                        }
                    }
                }
            }
        }
        #region ShouldExtendSelection
        private bool ShouldExtendSelection(GridPanel panel)
        {
            return (panel.SuperGrid.HasItemDragHandler == false || IsSelected == false ||
                ((Control.ModifierKeys & (Keys.Control | Keys.Shift)) != Keys.None));
        }
        #endregion
        #region InitExtendSelection
        private void InitExtendSelection(GridPanel panel)
        {
            if (IsMouseSelectable() == true)
            {
                Capture = true;
                ExtendSelectionEx(panel);
            }
        }
        #region IsMouseSelectable
        private bool IsMouseSelectable()
        {
            return (IsMouseSelectableEx(Control.MouseButtons));
        }
        private bool IsMouseSelectableEx(MouseButtons mb)
        {
            if ((mb & MouseButtons.Left) == MouseButtons.Left)
                return (true);
            return (IsSelected == false);
        }
        #endregion
        #region ExtendSelectionEx
        private void ExtendSelectionEx(GridPanel panel)
        {
            if (_MouseDownHitRow != null && _HitItem != null)
            {
                _AnchorIndex = _MouseDownHitRow.GridIndex;
                if (panel.LastProcessedItem != this && panel.LastProcessedItem != null)
                    panel.LastProcessedItem.InvalidateRender();
                bool ckey = panel.MultiSelect == true
                                ? ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                                : false;
                panel.LastProcessedItem = (ckey == true) ? _HitItem : this;
                ProcessExtendSelection(panel, false);
            }
        }
        #region ProcessExtendSelection
        internal void ProcessExtendSelection(GridPanel panel, bool extend)
        {
            bool ckey = panel.MultiSelect == true
                            ? ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                            : false;
            if (ckey == true)
                ProcessControlExtend(panel, extend);
            else
                ProcessNonControlExtend(panel, extend);
            panel.LastProcessedItem = _HitItem;
        }
        #region ProcessControlExtend
        private void ProcessControlExtend(GridPanel panel, bool extend)
        {
            if (panel.LastProcessedItem == null)
                panel.LastProcessedItem = _MouseDownHitRow;
            GridContainer lastRow = panel.LastProcessedItem as GridContainer;
            if (lastRow != null)
            {
                int startIndex = lastRow.GridIndex;
                int endIndex = _HitItem.GridIndex;
                panel.NormalizeIndices(extend,
                    _AnchorIndex, ref startIndex, ref endIndex);
                for (int i = startIndex; i <= endIndex; i++)
                {
                    if (extend == false || i != _AnchorIndex)
                        panel.SetSelectedRows(i, 1, !panel.IsRowSelected(i));
                }
                InvalidateRows(panel, startIndex, endIndex, true);
            }
        }
        #endregion
        #region ProcessNonControlExtend
        private void ProcessNonControlExtend(GridPanel panel, bool extend)
        {
            bool skey = (panel.MultiSelect == true) ?
                ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) : false;
            if (skey == false || panel.SelectionRowAnchor == null)
                panel.SelectionRowAnchor = _MouseDownHitRow;
            ExtendSelection(panel, _HitItem, extend);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #endregion
        #region InternalMouseUp
        /// 
        /// InternalMouseUp
        /// 
        /// 
        internal override void InternalMouseUp(MouseEventArgs e)
        {
            SuperGrid.DisableAutoScrolling();
            if (ExtendDragSelection(GridPanel, e) == false)
            {
                if (_MouseDownHitArea == _HitArea)
                {
                    if (_MouseDownHitArea == GroupArea.Content || _MouseDownHitArea == GroupArea.RowHeader)
                    {
                        GridPanel panel = GridPanel;
                        if (GridPanel.GroupHeaderClickBehavior == GroupHeaderClickBehavior.SelectAll)
                        {
                            bool ckey = panel.MultiSelect == true
                                ? ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                                : false;
                            ProcessSelectAll(panel, this, ckey);
                        }
                    }
                    SuperGrid.DoGroupHeaderClickEvent(this, _MouseDownHitArea, e);
                }
            }
        }
        #region ExtendDragSelection
        private bool ExtendDragSelection(GridPanel panel, MouseEventArgs e)
        {
            if (_dragSelection == true && Capture == true)
            {
                if (IsMouseSelectableEx(e.Button) == true)
                {
                    if (_MouseDownHitRow == _HitItem)
                    {
                        ExtendSelectionEx(panel);
                        return (true);
                    }
                }
            }
            return (false);
        }
        #endregion
        #region ProcessSelectAll
        private void ProcessSelectAll(GridPanel panel,
            GridContainer item, bool ckey)
        {
            if (item.Rows != null && item.Rows.Count > 0)
            {
                item.Expanded = true;
                foreach (GridContainer row in item.Rows)
                {
                    if (row is GridGroup)
                    {
                        ProcessSelectAll(panel, row, ckey);
                    }
                    else
                    {
                        int startIndex = ((GridContainer)item.Rows[0]).GridIndex;
                        int endIndex = ((GridContainer)item.Rows[item.Rows.Count - 1]).GridIndex;
                        if (ckey == true)
                        {
                            for (int i = startIndex; i <= endIndex; i++)
                                panel.SetSelectedRows(i, 1, !panel.IsRowSelected(i));
                        }
                        else
                        {
                            panel.SetSelectedRows(startIndex, endIndex - startIndex + 1, true);
                        }
                        break;
                    }
                }
            }
        }
        #endregion
        #endregion
        #region InternalMouseDoubleClick
        internal override void InternalMouseDoubleClick(MouseEventArgs e)
        {
            if (_HitArea == _MouseDownHitArea)
                SuperGrid.DoGroupHeaderDoubleClickEvent(this, _MouseDownHitArea, e);
        }
        #endregion
        #endregion
        #region GetGroupAreaAt
        /// 
        /// Returns element at specified mouse coordinates
        /// 
        /// Mouse event arguments
        /// Reference to child Group element or null
        /// if no element at specified coordinates
        protected virtual GroupArea GetGroupAreaAt(MouseEventArgs e)
        {
            return GetGroupAreaAt(e.X, e.Y);
        }
        /// 
        /// Returns element at specified mouse coordinates
        /// 
        /// Horizontal position
        /// Vertical position
        /// Reference to child element or null
        /// if no element at specified coordinates
        protected virtual GroupArea GetGroupAreaAt(int x, int y)
        {
            GridPanel panel = GridPanel;
            _HitItem = GetRowAt(panel, new Point(x, y));
            Rectangle r = BoundsRelative;
            r.Height = FixedRowHeight;
            if (IsVFrozen == false)
                r.Y -= VScrollOffset;
            if (panel.IsSubPanel == true)
                r.X -= HScrollOffset;
            if (r.Contains(x, y) == true)
            {
                if (panel.ShowRowHeaders == true)
                {
                    if (x >= r.X && x < r.X + panel.RowHeaderWidthEx)
                        return (GroupArea.RowHeader);
                }
                r = _ExpandButtonBounds;
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (GridPanel.IsSubPanel == true)
                    r.X -= HScrollOffset;
                if (r.Contains(x, y) == true)
                    return (GroupArea.ExpandButton);
                return (GroupArea.Content);
            }
            return (GroupArea.NoWhere);
        }
        #endregion
        #region GetRowAt
        private GridContainer GetRowAt(GridPanel panel, Point pt)
        {
            Rectangle r = panel.ContainerBounds;
            r.X -= HScrollOffset;
            if (pt.X < r.X)
                pt.X = r.X;
            GridContainer row = panel;
            GridElement item = row.InternalGetElementAt(pt.X, pt.Y);
            while (item != null)
            {
                row = item as GridContainer;
                if (row == null)
                    break;
                if (row is GridRow)
                    item = ((GridRow)row).GetRowElementAt(pt.X, pt.Y, false);
                else
                    item = row.GetElementAt(pt.X, pt.Y);
                if (item is GridContainer == false)
                    return (row);
            }
            return (null);
        }
        #endregion
        #region InvalidateRender
        /// 
        /// InvalidateRender
        /// 
        public override void InvalidateRender()
        {
            Rectangle bounds = BoundsRelative;
            if (IsVFrozen == false)
                bounds.Y -= VScrollOffset;
            SuperGridControl grid = SuperGrid;
            if (grid != null)
                grid.InvalidateRender(bounds);
            OnRenderInvalid(EventArgs.Empty);
        }
        #endregion
        #region Style support routines
        #region GroupHeaderStyleChangeHandler
        private void GroupHeaderStyleChangeHandler(
            GroupHeaderVisualStyles oldValue, GroupHeaderVisualStyles newValue)
        {
            if (oldValue != null)
                oldValue.PropertyChanged -= StyleChanged;
            if (newValue != null)
                newValue.PropertyChanged += StyleChanged;
        }
        #endregion
        #region GetEffectiveStyle
        ///
        /// GetEffectiveStyle
        ///
        ///
        public GroupHeaderVisualStyle GetEffectiveStyle()
        {
            StyleState state = GetState();
            return (GetEffectiveStyle(state));
        }
        internal GroupHeaderVisualStyle GetEffectiveStyle(StyleType styleType)
        {
            ValidateStyle();
            return (GetStyle(styleType));
        }
        internal GroupHeaderVisualStyle GetEffectiveStyle(StyleState state)
        {
            ValidateStyle();
            switch (state)
            {
                case StyleState.MouseOver:
                    return (GetStyle(StyleType.MouseOver));
                case StyleState.Selected:
                    return (GetStyle(StyleType.Selected));
                case StyleState.Selected | StyleState.MouseOver:
                    return (GetStyle(StyleType.SelectedMouseOver));
                case StyleState.ReadOnly:
                    return (GetStyle(StyleType.ReadOnly));
                case StyleState.ReadOnly | StyleState.MouseOver:
                    return (GetStyle(StyleType.ReadOnlyMouseOver));
                case StyleState.ReadOnly | StyleState.Selected:
                    return (GetStyle(StyleType.ReadOnlySelected));
                case StyleState.ReadOnly | StyleState.MouseOver | StyleState.Selected:
                    return (GetStyle(StyleType.ReadOnlySelectedMouseOver));
                default:
                    return (GetStyle(StyleType.Default));
            }
        }
        #endregion
        #region GetStyle
        private GroupHeaderVisualStyle GetStyle(StyleType e)
        {
            if (_EffectiveVisualStyles.IsValid(e) == false)
            {
                GroupHeaderVisualStyle style = new GroupHeaderVisualStyle();
                StyleType[] css = style.GetApplyStyleTypes(e);
                if (css != null)
                {
                    foreach (StyleType cs in css)
                    {
                        style.ApplyStyle(SuperGrid.BaseVisualStyles.GroupHeaderStyles[cs]);
                        style.ApplyStyle(SuperGrid.DefaultVisualStyles.GroupHeaderStyles[cs]);
                        style.ApplyStyle(GridPanel.DefaultVisualStyles.GroupHeaderStyles[cs]);
                        style.ApplyStyle(GroupHeaderVisualStyles[cs]);
                    }
                }
                SuperGrid.DoGetGroupHeaderStyleEvent(this, e, ref style);
                if (style.Background == null || style.Background.IsEmpty == true)
                    style.Background = new Background(Color.White);
                if (style.Font == null)
                    style.Font = SystemFonts.DefaultFont;
                if (style.TextColor.IsEmpty)
                    style.TextColor = Color.Black;
                _EffectiveVisualStyles[e] = style;
            }
            return (_EffectiveVisualStyles[e]);
        }
        #endregion
        #region ValidateStyle
        private void ValidateStyle()
        {
            if (_EffectiveVisualStyles == null ||
                (_StyleUpdateCount != SuperGrid.StyleUpdateCount))
            {
                _EffectiveVisualStyles = new GroupHeaderVisualStyles();
                _StyleUpdateCount = SuperGrid.StyleUpdateCount;
            }
        }
        #endregion
        #region GetState
        internal StyleState GetState()
        {
            StyleState rowState = StyleState.Default;
            if (IsMouseOver == true)
            {
                Point pt = SuperGrid.PointToClient(Control.MousePosition);
                if (Bounds.Contains(pt) == true)
                    rowState |= StyleState.MouseOver;
            }
            if (IsSelected == true)
                rowState |= StyleState.Selected;
            return (rowState);
        }
        #endregion
        #region GetSizingStyle
        private GroupHeaderVisualStyle GetSizingStyle(GridPanel panel)
        {
            StyleType styleType = panel.GetSizingStyle();
            if (styleType == StyleType.NotSet)
                styleType = StyleType.Default;
            return (GetEffectiveStyle(styleType));
        }
        #endregion
        #endregion
        #region CreateItemsCollection
        /// 
        /// Creates the GridItemsCollection that hosts the items.
        /// 
        /// New instance of GridItemsCollection.
        protected override GridItemsCollection CreateItemsCollection()
        {
            GridItemsCollection items = new GridItemsCollection();
            items.CollectionChanged += ItemsCollectionChanged;
            return (items);
        }
        #endregion
        #region DisposeItemsCollection
        /// 
        /// DisposeItemsCollection
        /// 
        /// 
        protected override void DisposeItemsCollection(GridItemsCollection items)
        {
            items.CollectionChanged -= ItemsCollectionChanged;
        }
        #endregion
        #region ItemsCollectionChanged
        void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Replace:
                    foreach (GridElement item in e.NewItems)
                        item.Parent = this;
                    break;
            }
            GridPanel panel = GridPanel;
            if (panel != null)
                panel.RowCollectionChanged(e);
        }
        #endregion
        #region Markup support
        private void MarkupGroupTextChanged()
        {
            _GroupTextMarkup = null;
            if (Column != null && Column.EnableGroupHeaderMarkup == true)
            {
                if (MarkupParser.IsMarkup(_Text) == true)
                    _GroupTextMarkup = MarkupParser.Parse(_Text);
            }
        }
        #endregion
        #region IDisposable
        /// 
        /// Dispose
        /// 
        public override void Dispose()
        {
            GroupHeaderVisualStyles = null;
            Rows = null;
            base.Dispose();
        }
        #endregion
    }
    #region enums
    #region GroupArea
    ///
    /// GroupArea
    ///
    public enum GroupArea
    {
        ///
        /// Content
        ///
        Content,
        ///
        /// ExpandButton
        ///
        ExpandButton,
        /// 
        /// Row Header
        /// 
        RowHeader,
        ///
        /// NoWhere
        ///
        NoWhere,
    }
    #endregion
    #endregion
}