using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
namespace DevComponents.DotNetBar.Layout
{
    /// 
    /// Represents layout item which hosts a Windows Forms Control.
    /// 
    [Designer("DevComponents.DotNetBar.Layout.Design.LayoutControlItemDesigner, DevComponents.DotNetBar.Layout.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=7eb7c3a35b91de04")]
    public class LayoutControlItem : LayoutItemBase
    {
        #region Constructor
        protected override void OnDispose()
        {
            UnhookControlEventHandlers(_Control);
            base.OnDispose();
        }
        #endregion
        #region Implementation
        protected override void OnUpdateLayout()
        {
            base.OnUpdateLayout();
            if (_Control != null)
            {
                Rectangle bounds = Helpers.Deflate(this.Bounds, this.Padding);
                Rectangle r = bounds;
                if (this.TextVisible && !string.IsNullOrEmpty(this.Text))
                {
                    Rectangle actualTextBounds = this.ActualTextBounds;
                    if (IsImageVisible)
                        actualTextBounds = Rectangle.Union(actualTextBounds, this.ActualImageBounds);
                    if (this.TextPosition == eLayoutPosition.Default || this.TextPosition == eLayoutPosition.Left)
                    {
                        r.X = actualTextBounds.Right + _TextControlSpacing;
                        r.Width = bounds.Right - r.X;
                    }
                    else if (this.TextPosition == eLayoutPosition.Top)
                    {
                        r.Y = actualTextBounds.Bottom + _TextControlSpacing;
                        r.Height = bounds.Bottom - r.Y;
                    }
                    else if (this.TextPosition == eLayoutPosition.Bottom)
                    {
                        r.Height = actualTextBounds.Y - bounds.Y - _TextControlSpacing;
                    }
                    else if (this.TextPosition == eLayoutPosition.Right)
                    {
                        r.Width = actualTextBounds.X - r.X - _TextControlSpacing;
                    }
                }
                if (_Control.Margin.Horizontal > 0 || _Control.Margin.Vertical > 0)
                {
                    r.X += _Control.Margin.Left;
                    r.Width -= _Control.Margin.Horizontal;
                    r.Y += _Control.Margin.Top;
                    r.Height -= _Control.Margin.Vertical;
                }
                if (!_ControlSize.IsEmpty && _Control.Dock != DockStyle.Fill && (_ControlSize.Width > 0 && r.Width > _ControlSize.Width) || (_ControlSize.Height > 0 && r.Height > _ControlSize.Height))
                {
                    Size controlSize = new Size(_ControlSize.Width > 0 ? Math.Min(r.Width, _ControlSize.Width) : r.Width,
                            _ControlSize.Height > 0 ? Math.Min(r.Height, _ControlSize.Height) : r.Height);
                    if (_Control.Dock != DockStyle.None)
                    {
                        if (_Control.Dock == DockStyle.Left)
                            r = new Rectangle(r.X, r.Y, controlSize.Width, r.Height);
                        else if (_Control.Dock == DockStyle.Right)
                            r = new Rectangle(r.Right - controlSize.Width, r.Y, controlSize.Width, r.Height);
                        else if (_Control.Dock == DockStyle.Top)
                            r = new Rectangle(r.X, r.Y, r.Width, controlSize.Height);
                        else if (_Control.Dock == DockStyle.Bottom)
                            r = new Rectangle(r.X, r.Bottom - controlSize.Height, r.Width, controlSize.Height);
                    }
                    else
                    {
                        if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom))
                        {
                            // Center into the bounding box
                            r.X += (r.Width - controlSize.Width) / 2;
                            r.Y += (r.Height - controlSize.Height) / 2;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top))
                        {
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right))
                        {
                            r.X += (r.Width - controlSize.Width) / 2;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Bottom))
                        {
                            r.Y += (r.Height - controlSize.Height) / 2;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Bottom))
                        {
                            r.Y = r.Bottom - controlSize.Height;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right))
                        {
                            r.Y = r.Bottom - controlSize.Height;
                            r.X += (r.Width - controlSize.Width) / 2;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Top))
                        {
                            r.X = r.Right - controlSize.Width;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Bottom))
                        {
                            r.X = r.Right - controlSize.Width;
                            r.Y = r.Bottom - controlSize.Height;
                            r.Size = controlSize;
                        }
                        else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Top))
                        {
                            r.X = r.Right - controlSize.Width;
                            r.Y += (r.Height - controlSize.Height) / 2;
                            r.Size = controlSize;
                        }
                        else
                            r.Size = controlSize;
                    }
                }
                _Control.Bounds = r;
            }
        }
        protected override void OnPaintBackground(PaintContext context)
        {
            base.OnPaintBackground(context);
            if (IsKeyboardFocusWithin && context.FocusStyle != null)
            {
                DrawingHelpers.PaintStyle(context.Graphics, context.FocusStyle, this.Bounds);
            }
        }
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override void ScaleItem(SizeF factor)
        {
            base.ScaleItem(factor);
            bool widthChanged = factor.Width != 1f;
            bool heightChanged = factor.Height != 1f;
            if (!_ControlSize.IsEmpty && (widthChanged || heightChanged))
            {
                Size newSize = new Size();
                if (widthChanged)
                    newSize.Width = (int)(_ControlSize.Width * factor.Width);
                else
                    newSize.Width = _ControlSize.Width;
                if (heightChanged)
                    newSize.Height = (int)(_ControlSize.Height * factor.Height);
                else
                    newSize.Height = _ControlSize.Height;
                ControlSize = newSize;
            }
        }
        internal override void UpdateScrollBounds(int xScroll, int yScroll, bool moveControls)
        {
            base.UpdateScrollBounds(xScroll, yScroll, moveControls);
            if (moveControls && _Control != null)
                _Control.Location = new Point(_Control.Location.X + xScroll, _Control.Location.Y + yScroll);
        }
        protected override Size OnMeasureText(LayoutContext c)
        {
            if (_Control is TextBoxBase && this.TextPosition == eLayoutPosition.Default)
            {
                TextBoxBase textBox = (TextBoxBase)_Control;
                int textBaseLine = Helpers.GetTextBaseline(_Control, ContentAlignment.TopLeft);
                if (textBox is DevComponents.DotNetBar.Controls.TextBoxX)
                    textBaseLine += 3;
                else if (textBox.BorderStyle == BorderStyle.FixedSingle || textBox.BorderStyle == BorderStyle.None)
                    textBaseLine += 2;
                else if (textBox.BorderStyle == BorderStyle.Fixed3D)
                    textBaseLine += 3;
                _ControlTextBaseline = textBaseLine;
            }
            else
                _ControlTextBaseline = 0;
            return base.OnMeasureText(c);
        }
        internal override int TextBaseline
        {
            get
            {
                if (_ControlTextBaseline > 0 && _ControlTextBaseline > base.TextBaseline)
                    return _ControlTextBaseline;
                return base.TextBaseline;
            }
            set
            {
                base.TextBaseline = value;
            }
        }
        private int _ControlTextBaseline = 0;
        private Control _Control = null;
        /// 
        /// Gets or sets the control managed by layout item.
        /// 
        [DefaultValue(null), Category("Data"), Description("Indicates control managed by layout item.")]
        public Control Control
        {
            get { return _Control; }
            set
            {
                if (value != _Control)
                {
                    Control oldValue = _Control;
                    _Control = value;
                    OnControlChanged(oldValue, value);
                }
            }
        }
        private void UnhookControlEventHandlers(Control control)
        {
            if (control == null) return;
            control.Enter -= ControlEnter;
            control.Leave -= ControlLeave;
            control.MouseHover -= ControlMouseHover;
            control.MouseDown -= ControlMouseDown;
            control.MouseMove -= ControlMouseMove;
            control.MouseLeave -= ControlMouseLeave;
        }
        /// 
        /// Called when Control property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnControlChanged(Control oldValue, Control newValue)
        {
            if (oldValue != null)
            {
                UnhookControlEventHandlers(oldValue);
            }
            OnPropertyChanged(new PropertyChangedEventArgs("Control"));
            if (_Control != null)
            {
                _Control.Enter += ControlEnter;
                _Control.Leave += ControlLeave;
                _Control.MouseHover += ControlMouseHover;
                _Control.MouseDown += ControlMouseDown;
                _Control.MouseMove += ControlMouseMove;
                _Control.MouseLeave += ControlMouseLeave;
                if (_Control.Visible != this.Visible)
                    _Control.Visible = this.Visible;
            }
            InvalidateLayout();
        }
        private Point _MouseTooltipLocation = Point.Empty;
        void ControlMouseLeave(object sender, EventArgs e)
        {
            _MouseTooltipLocation = Point.Empty;
            if (ToolTipVisible)
                HideToolTip();
        }
        void ControlMouseMove(object sender, MouseEventArgs e)
        {
            if (!_MouseTooltipLocation.IsEmpty && ToolTipVisible && (Math.Abs(_MouseTooltipLocation.X - e.X) > 1 || Math.Abs(_MouseTooltipLocation.Y - e.Y) > 1))
                HideToolTip();
        }
        void ControlMouseDown(object sender, MouseEventArgs e)
        {
            if (ToolTipVisible)
                HideToolTip();
        }
        void ControlMouseHover(object sender, EventArgs e)
        {
            if (_EnableControlTooltip)
            {
                ShowToolTip();
                _MouseTooltipLocation = _Control.PointToClient(Control.MousePosition);
            }
        }
        private void ControlLeave(object sender, EventArgs e)
        {
            IsKeyboardFocusWithin = false;
        }
        private void ControlEnter(object sender, EventArgs e)
        {
            IsKeyboardFocusWithin = true;
        }
        private bool _EnableControlTooltip = true;
        /// 
        /// Indicates whether Tooltip for the item is shown when mouse is over the control.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether Tooltip for the item is shown when mouse is over the control.")]
        public bool EnableControlTooltip
        {
            get { return _EnableControlTooltip; }
            set
            {
                if (value != _EnableControlTooltip)
                {
                    bool oldValue = _EnableControlTooltip;
                    _EnableControlTooltip = value;
                    OnEnableControlTooltipChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when EnableControlTooltip property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnEnableControlTooltipChanged(bool oldValue, bool newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs("EnableControlTooltip"));
        }
        private int _TextControlSpacing = 3;
        /// 
        /// Indicates spacing between text and the control.
        /// 
        [DefaultValue(3), Category("Appearance"), Description("Indicates spacing between text and the control."), RefreshProperties(RefreshProperties.All)]
        public int TextControlSpacing
        {
            get { return _TextControlSpacing; }
            set
            {
                if (value != _TextControlSpacing)
                {
                    int oldValue = _TextControlSpacing;
                    _TextControlSpacing = value;
                    OnTextControlSpacingChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when TextControlSpacing property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnTextControlSpacingChanged(int oldValue, int newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs("TextControlSpacing"));
            InvalidateLayout();
        }
        /// 
        /// Processes accelerator key for the item.
        /// 
        /// 
        internal override bool ProcessMnemonic(char charCode)
        {
            if (MnemonicsEnabled && _Control != null && _Control.CanSelect)
            {
                _Control.Select();
                return true;
            }
            return false;
        }
        private Size _ControlSize = Size.Empty;
        /// 
        /// Indicates suggested control size which is used only if calculated layout size for the control exceeds the size specified here. Either width or height may be set or both.
        /// ControlSize property can be used in conjuction with Dock and Anchor properties on the Control. When available space for the Control
        /// exceeds ControlSize the Dock and Anchor properties will indicate the control position inside of the control box.
        /// 
        [Category("Appearance"), Description("Indicates suggested control size which is used only if calculated layout size for the control exceeds the size specified here. Either width or height may be set or both.")]
        public Size ControlSize
        {
            get { return _ControlSize; }
            set
            {
                if (value != _ControlSize)
                {
                    Size oldValue = _ControlSize;
                    _ControlSize = value;
                    OnControlSizeChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when ControlSize property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnControlSizeChanged(Size oldValue, Size newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs("ControlSize"));
            InvalidateLayout();
        }
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeControlSize()
        {
            return !_ControlSize.IsEmpty;
        }
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetControlSize()
        {
            ControlSize = Size.Empty;
        }
        private bool _AutoSetTabIndex = true;
        /// 
        /// Indicates whether Control TabIndex is automatically set based on the position of the item inside of the layout.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether Control TabIndex is automatically set based on the position of the item inside of the layout.")]
        public bool AutoSetTabIndex
        {
            get { return _AutoSetTabIndex; }
            set
            {
                if (value != _AutoSetTabIndex)
                {
                    bool oldValue = _AutoSetTabIndex;
                    _AutoSetTabIndex = value;
                    OnAutoSetTabIndexChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when AutoSetTabIndex property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnAutoSetTabIndexChanged(bool oldValue, bool newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs("AutoSetTabIndex"));
        }
        protected override void OnAbsoluteIndexChanged(int oldValue, int newValue)
        {
            if (_Control != null && _AutoSetTabIndex) _Control.TabIndex = newValue;
            base.OnAbsoluteIndexChanged(oldValue, newValue);
        }
        private bool _FocusVisualStyleEnabled = true;
        /// 
        /// Indicates whether LayoutControl.FocusStyle is used to paint background of item when control has input focus.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether LayoutControl.FocusStyle is used to paint background of item when control has input focus.")]
        public bool FocusVisualStyleEnabled
        {
            get { return _FocusVisualStyleEnabled; }
            set
            {
                if (_FocusVisualStyleEnabled == value)
                    return;
                _FocusVisualStyleEnabled = value;
                if (this.IsKeyboardFocusWithin)
                    this.Invalidate();
                OnPropertyChanged(new PropertyChangedEventArgs("FocusVisualStyleEnabled"));
            }
        }
        protected override void OnVisibleChanged(bool oldValue, bool newValue)
        {
            if (_Control != null)
                _Control.Visible = newValue;
            base.OnVisibleChanged(oldValue, newValue);
        }
        #endregion
    }
}