#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
namespace DevComponents.Editors
{
    public class VisualGroup : VisualItem
    {
        #region Private Variables
        private VisualItem _MouseDownItem = null;
        private VisualItem _MouseOverItem = null;
        #endregion
        #region Events
        #endregion
        #region Constructor
        public VisualGroup()
            : base()
        {
            _Items = new VisualItemCollection(this);
        }
        #endregion
        #region Internal Implementation
        internal virtual void ProcessItemsCollectionChanged(CollectionChangedInfo collectionChangedInfo)
        {
            OnItemsCollectionChanged(collectionChangedInfo);
        }
        protected virtual void OnItemsCollectionChanged(CollectionChangedInfo collectionChangedInfo)
        {
            if (collectionChangedInfo.ChangeType == eCollectionChangeType.Adding || collectionChangedInfo.ChangeType == eCollectionChangeType.Removing ||
                collectionChangedInfo.ChangeType == eCollectionChangeType.Clearing)
            {
                if (collectionChangedInfo.Removed != null)
                {
                    foreach (VisualItem item in collectionChangedInfo.Removed)
                        item.Parent = null;
                }
                if (collectionChangedInfo.ChangeType == eCollectionChangeType.Clearing)
                {
                    foreach (VisualItem item in this.Items)
                        item.Parent = null;
                }
                if (collectionChangedInfo.Added != null)
                {
                    foreach (VisualItem item in collectionChangedInfo.Added)
                    {
                        if (item.Parent != null && item.Parent != this)
                        {
                            item.Parent.Items.Remove(item);
                        }
                        item.Parent = this;
                    }
                }
            }
            this.InvalidateArrange();
        }
        private VisualItemCollection _Items;
        public virtual VisualItemCollection Items
        {
            get { return _Items; }
        }
        internal void OnChildItemVisibleChanged(VisualItem visualItem)
        {
            InvalidateArrange();
        }
        private VisualItem _FocusedItem;
        public VisualItem FocusedItem
        {
            get { return _FocusedItem; }
            internal set
            {
                if (_FocusedItem == value) return;
                if (_FocusedItem != null)
                    _FocusedItem.ProcessLostFocus();
                VisualItem oldFocus = _FocusedItem;
                _FocusedItem = value;
                if (_FocusedItem != null)
                    _FocusedItem.ProcessGotFocus();
                OnFocusedItemChanged(oldFocus);
                this.InvalidateArrange();
            }
        }
        protected virtual void OnFocusedItemChanged(VisualItem previousFocus)
        {
        }
        protected override void OnPaint(PaintInfo p)
        {
            if (!IsLayoutValid)
                PerformLayout(p);
            Point renderOffset = p.RenderOffset;
            Point pr = p.RenderOffset;
            pr.Offset(this.RenderBounds.Location);
            p.RenderOffset = pr;
            Graphics g = p.Graphics;
            Region oldClip = null;
            bool clipSet = false;
            oldClip = g.Clip;
            Rectangle renderBounds = this.RenderBounds;
            renderBounds.Offset(renderOffset);
            g.SetClip(renderBounds, CombineMode.Intersect);
            clipSet = true;
            bool parentEnabled = p.ParentEnabled;
            p.ParentEnabled = p.ParentEnabled && this.Enabled;
            bool renderSystemItemsOnly = p.RenderSystemItemsOnly;
            foreach (VisualItem v in _Items)
            {
                if (renderSystemItemsOnly && v.ItemType != eSystemItemType.SystemButton) continue;
                if (_VerticalItemAlignment == eVerticalAlignment.Middle)
                {
                    if(_Orientation == DotNetBar.eOrientation.Horizontal)
                        v.RenderBounds = new Rectangle(p.RenderOffset.X + v.Location.X, p.RenderOffset.Y + v.Location.Y + (this.Size.Height - v.Size.Height) / 2, v.Size.Width, v.Size.Height);
                    else
                        v.RenderBounds = new Rectangle(p.RenderOffset.X + v.Location.X + (this.Size.Width - v.Size.Width) / 2, p.RenderOffset.Y + v.Location.Y, v.Size.Width, v.Size.Height);
                }
                else if (_VerticalItemAlignment == eVerticalAlignment.Bottom)
                {
                    if(_Orientation == DotNetBar.eOrientation.Horizontal)
                        v.RenderBounds = new Rectangle(p.RenderOffset.X + v.Location.X, p.RenderOffset.Y + v.Location.Y + (this.Size.Height - v.Size.Height), v.Size.Width, v.Size.Height);
                    else
                        v.RenderBounds = new Rectangle(p.RenderOffset.X + v.Location.X + (this.Size.Width - v.Size.Width), p.RenderOffset.Y + v.Location.Y, v.Size.Width, v.Size.Height);
                }
                else
                    v.RenderBounds = new Rectangle(p.RenderOffset.X + v.Location.X, p.RenderOffset.Y + v.Location.Y, v.Size.Width, v.Size.Height);
                if (v.RenderBounds.IntersectsWith(renderBounds))
                {
                    p.RenderOffset = Point.Empty;
                    v.ProcessPaint(p);
                    p.RenderOffset = pr;
                }
            }
            p.ParentEnabled = parentEnabled;
            if (clipSet)
            {
                if (oldClip != null)
                    g.Clip = oldClip;
                else
                    g.ResetClip();
            }
            if(oldClip!=null) oldClip.Dispose();
            p.RenderOffset = renderOffset;
            base.OnPaint(p);
        }
        protected override void OnIsRightToLeftChanged()
        {
            foreach (VisualItem vi in _Items)
                vi.IsRightToLeft = this.IsRightToLeft;
            base.OnIsRightToLeftChanged();
        }
        public override void PerformLayout(PaintInfo pi)
        {
            if (_Orientation == DotNetBar.eOrientation.Horizontal)
            {
                Point p = Point.Empty;
                Size size = Size.Empty;
                Size availableSize = pi.AvailableSize;
                Size containerSize = availableSize;
                bool usesFullWidth = false;
                Size calcSize = Size.Empty;
                foreach (VisualItem v in new VisualCollectionEnumerator(_Items, this.IsRightToLeft))
                {
                    if (v.Visible)
                    {
                        v.Location = p;
                        pi.AvailableSize = new Size(availableSize.Width - p.X, availableSize.Height);
                        v.PerformLayout(pi);
                        if (v.Alignment == eItemAlignment.Right)
                        {
                            v.Location = new Point(containerSize.Width - v.Size.Width, p.Y);
                            containerSize.Width -= v.Size.Width + _HorizontalItemSpacing;
                            calcSize.Width += v.Size.Width + _HorizontalItemSpacing;
                            usesFullWidth = true;
                        }
                        else
                        {
                            p.X += v.Size.Width + _HorizontalItemSpacing;
                            size.Width += v.Size.Width + _HorizontalItemSpacing;
                            calcSize.Width += v.Size.Width + _HorizontalItemSpacing;
                        }
                        if (v.Size.Height > size.Height)
                            size.Height = v.Size.Height;
                    }
                }
                if (size.Width > 0)
                    size.Width -= +_HorizontalItemSpacing;
                if (usesFullWidth && _HorizontalItemAlignment != eHorizontalAlignment.Left)
                {
                    if (_HorizontalItemAlignment == eHorizontalAlignment.Right)
                    {
                        if (containerSize.Width < availableSize.Width) containerSize.Width--;
                        foreach (VisualItem v in new VisualCollectionEnumerator(_Items, !this.IsRightToLeft))
                        {
                            if (!v.Visible || v.Alignment == eItemAlignment.Right || v is LockUpdateCheckBox) continue;
                            v.Location = new Point(containerSize.Width - v.Size.Width, p.Y);
                            containerSize.Width -= v.Size.Width + _HorizontalItemSpacing;
                        }
                    }
                    else
                    {
                        int offset = (containerSize.Width - size.Width) / 2;
                        foreach (VisualItem v in new VisualCollectionEnumerator(_Items, this.IsRightToLeft))
                        {
                            if (!v.Visible || v.Alignment == eItemAlignment.Right || v is LockUpdateCheckBox) continue;
                            v.Location = new Point(v.Location.X + offset, v.Location.Y);
                        }
                    }
                }
                this.CalculatedSize = calcSize;
                if (usesFullWidth)
                    size.Width = availableSize.Width;
                pi.AvailableSize = availableSize;
                this.Size = size;
                this.RenderBounds = new Rectangle(pi.RenderOffset, size);
            }
            else
                PerformVerticalLayout(pi);
            base.PerformLayout(pi);
        }
        private void PerformVerticalLayout(PaintInfo pi)
        {
            Point p = Point.Empty;
            Size size = Size.Empty;
            Size availableSize = pi.AvailableSize;
            Size containerSize = availableSize;
            bool usesFullWidth = false;
            Size calcSize = Size.Empty;
            foreach (VisualItem v in new VisualCollectionEnumerator(_Items, this.IsRightToLeft))
            {
                if (v.Visible)
                {
                    v.Location = p;
                    pi.AvailableSize = new Size(availableSize.Width, availableSize.Height - p.Y);
                    v.PerformLayout(pi);
                    if (v.Alignment == eItemAlignment.Right)
                    {
                        v.Location = new Point(p.X, containerSize.Height - v.Size.Height);
                        containerSize.Height -= v.Size.Height + _HorizontalItemSpacing;
                        calcSize.Height += v.Size.Height + _HorizontalItemSpacing;
                        usesFullWidth = true;
                    }
                    else
                    {
                        p.Y += v.Size.Height + _HorizontalItemSpacing;
                        size.Height += v.Size.Height + _HorizontalItemSpacing;
                        calcSize.Height += v.Size.Height + _HorizontalItemSpacing;
                    }
                    if (v.Size.Width > size.Width)
                        size.Width = v.Size.Width;
                }
            }
            if (size.Height > 0)
                size.Height -= +_HorizontalItemSpacing;
            if (usesFullWidth && _HorizontalItemAlignment != eHorizontalAlignment.Left)
            {
                if (_HorizontalItemAlignment == eHorizontalAlignment.Right)
                {
                    if (containerSize.Height < availableSize.Height) containerSize.Height--;
                    foreach (VisualItem v in new VisualCollectionEnumerator(_Items, !this.IsRightToLeft))
                    {
                        if (!v.Visible || v.Alignment == eItemAlignment.Right || v is LockUpdateCheckBox) continue;
                        v.Location = new Point(p.X, containerSize.Height - v.Size.Height);
                        containerSize.Height -= v.Size.Height + _HorizontalItemSpacing;
                    }
                }
                else
                {
                    int offset = (containerSize.Height - size.Height) / 2;
                    foreach (VisualItem v in new VisualCollectionEnumerator(_Items, this.IsRightToLeft))
                    {
                        if (!v.Visible || v.Alignment == eItemAlignment.Right || v is LockUpdateCheckBox) continue;
                        v.Location = new Point(v.Location.X, v.Location.Y + offset);
                    }
                }
            }
            this.CalculatedSize = calcSize;
            if (usesFullWidth)
                size.Height = availableSize.Height;
            pi.AvailableSize = availableSize;
            this.Size = size;
            this.RenderBounds = new Rectangle(pi.RenderOffset, size);
        }
        private DevComponents.DotNetBar.eOrientation _Orientation=DevComponents.DotNetBar.eOrientation.Horizontal;
        internal DevComponents.DotNetBar.eOrientation Orientation
        {
            get
            {
                return _Orientation;
            }
            set
            {
                _Orientation = value;
                this.InvalidateArrange();
                this.InvalidateRender();
            }
        }
        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            VisualItem item = GetItemAt(e.X, e.Y);
            if (item != null)
            {
                _MouseDownItem = item;
                _MouseOverItem = item;
                item.ProcessMouseDown(e);
                if (_MouseDownItem == item && CanFocus(item))
                    this.FocusedItem = item;
            }
            else if (item == null && this.IsFocused)
            {
                // Find first available input and focus it instead
                foreach (VisualItem visual in _Items)
                {
                    if (visual is VisualInputBase && CanFocus(visual))
                    {
                        this.FocusedItem = visual;
                        break;
                    }
                }
            }
            base.OnMouseDown(e);
        }
        protected override void OnMouseWheel(System.Windows.Forms.MouseEventArgs e)
        {
            if (this.FocusedItem != null)
                this.FocusedItem.ProcessMouseWheel(e);
            base.OnMouseWheel(e);
        }
        protected virtual bool CanFocus(VisualItem v)
        {
            return v != null && v.Visible && (v.Focusable || v is VisualInputGroup) && v.Enabled;
        }
        protected override void OnClick(EventArgs e)
        {
            if (_MouseDownItem != null)
            {
                _MouseDownItem.ProcessClick();
            }
            base.OnClick(EventArgs.Empty);
        }
        protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e)
        {
            if (_MouseDownItem != null)
            {
                _MouseDownItem.ProcessMouseClick(e);
            }
            base.OnMouseClick(e);
        }
        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            if (_MouseDownItem != null)
            {
                _MouseDownItem.ProcessMouseUp(e);
                _MouseDownItem = null;
            }
            base.OnMouseUp(e);
        }
        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            if (_MouseDownItem != null)
                _MouseDownItem.ProcessMouseMove(e);
            else
            {
                VisualItem item = GetItemAt(e.X, e.Y);
                if (item != _MouseOverItem && _MouseOverItem != null)
                {
                    _MouseOverItem.ProcessMouseLeave();
                    _MouseOverItem = null;
                }
                if (item != null && _MouseOverItem == null)
                {
                    _MouseOverItem = item;
                    _MouseOverItem.ProcessMouseEnter();
                }
                if (_MouseOverItem != null)
                    _MouseOverItem.ProcessMouseMove(e);
            }
            base.OnMouseMove(e);
        }
        protected override void OnMouseHover(EventArgs e)
        {
             if (_MouseOverItem != null)
                _MouseOverItem.ProcessMouseHover(e);
            base.OnMouseHover(e);
        }
        protected override void OnMouseLeave()
        {
            if (_MouseDownItem != null)
                _MouseDownItem.ProcessMouseLeave();
            else
            {
                if (_MouseOverItem != null)
                {
                    _MouseOverItem.ProcessMouseLeave();
                    _MouseOverItem = null;
                }
            }
            base.OnMouseLeave();
        }
        protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            if (_FocusedItem != null)
                _FocusedItem.ProcessKeyDown(e);
            base.OnKeyDown(e);
        }
        protected override void OnKeyUp(System.Windows.Forms.KeyEventArgs e)
        {
            if (_FocusedItem != null)
                _FocusedItem.ProcessKeyUp(e);
            base.OnKeyUp(e);
        }
        protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
        {
            if (_FocusedItem != null)
                _FocusedItem.ProcessKeyPress(e);
            base.OnKeyPress(e);
        }
        protected override bool OnCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
        {
            if (_FocusedItem != null)
                if (_FocusedItem.ProcessCmdKey(ref msg, keyData)) return true;
            foreach (VisualItem item in this.Items)
            {
                if (item is VisualButtonBase)
                {
                    if (item.ProcessCmdKey(ref msg, keyData)) return true;
                }
            }
            return base.OnCmdKey(ref msg, keyData);
        }
        public VisualItem GetItemAt(int x, int y)
        {
            for (int i = _Items.Count - 1; i >= 0 ; i--)
            {
                VisualItem item = _Items[i];
                if (!item.Visible) continue;
                if (item.RenderBounds.Contains(x, y))
                    return item;
            }
            return null;
        }
        private VisualItem GetFirstVisibleItem()
        {
            foreach (VisualItem item in new VisualCollectionEnumerator(_Items, this.IsRightToLeft))
            {
                if (item.Visible) return item;
            }
            return null;
        }
        protected override void OnGotFocus()
        {
            OnGroupFocused();
            base.OnGotFocus();
        }
        protected virtual void OnGroupFocused()
        {
            if (this.FocusedItem == null)
            {
                VisualItem item = GetFirstVisibleItem();
                if (item != null) this.FocusedItem = item;
            }
        }
        protected override void OnLostFocus()
        {
            this.FocusedItem = null;
            base.OnLostFocus();
        }
        internal virtual void ProcessInputComplete()
        {
            OnInputComplete();
        }
        /// 
        /// Occurs when child item input is complete. Method should be used to forward the input focus onto the different field if desired.
        /// 
        protected virtual void OnInputComplete()
        {
        }
        /// 
        /// Occurs when input stack on the child control has changed.
        /// 
        /// Control on which input has changed
        internal void ProcessInputChanged(VisualInputBase input)
        {
            OnInputChanged(input);
        }
        /// 
        /// Occurs when input stack on the child control has changed.
        /// 
        /// Control on which input has changed
        protected virtual void OnInputChanged(VisualInputBase input)
        {
        }
        private int _HorizontalItemSpacing = 0;
        /// 
        /// Gets or sets the horizontal spacing in pixels between the items.
        /// 
        [DefaultValue(0)]
        public int HorizontalItemSpacing
        {
            get { return _HorizontalItemSpacing; }
            set
            {
                if (_HorizontalItemSpacing != value)
                {
                    _HorizontalItemSpacing = value;
                    this.InvalidateArrange();
                }
            }
        }
        private bool _IsRootVisual = false;
        /// 
        /// Gets or sets whether visual is root visual directly parented to the control.
        /// 
        [DefaultValue(false)]
        public bool IsRootVisual
        {
            get { return _IsRootVisual; }
            set { _IsRootVisual = value; }
        }
        private eVerticalAlignment _VerticalItemAlignment = eVerticalAlignment.Middle;
        /// 
        /// Gets or sets group vertical alignment. Default value is middle.
        /// 
        [DefaultValue(eVerticalAlignment.Middle)]
        public eVerticalAlignment VerticalItemAlignment
        {
            get { return _VerticalItemAlignment; }
            set
            {
                if (_VerticalItemAlignment != value)
                {
                    _VerticalItemAlignment = value;
                    OnArrangeInvalid();
                }
            }
        }
        private eHorizontalAlignment _HorizontalItemAlignment = eHorizontalAlignment.Left;
        /// 
        /// Gets or sets input group horizontal alignment. Default value is left.
        /// 
        [DefaultValue(eHorizontalAlignment.Left)]
        public eHorizontalAlignment HorizontalItemAlignment
        {
            get { return _HorizontalItemAlignment; }
            set
            {
                if (_HorizontalItemAlignment != value)
                {
                    _HorizontalItemAlignment = value;
                    OnArrangeInvalid();
                }
            }
        }
        #endregion
    }
}
#endif