using DevComponents.DotNetBar.Primitives;
using DevComponents.DotNetBar.Rendering;
using DevComponents.DotNetBar.TextMarkup;
using DevComponents.Editors;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
namespace DevComponents.DotNetBar.Controls
{
    [ToolboxItem(true), ToolboxBitmap(typeof(TokenEditor), "Controls.TokenEditor.ico")]
    [Designer("DevComponents.DotNetBar.Design.TokenEditorDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf")]
    [DefaultEvent("SelectedTokensChanged")]
    public class TokenEditor : Control, IMessageHandlerClient
    {
        #region Constructor
        private TextBoxX _EditBox;
        private VScrollBarAdv _VScrollBar = null;
        /// 
        /// Initializes a new instance of the TokenEditor class.
        /// 
        public TokenEditor()
        {
            _SelectedTokens = new CustomCollection();
            _SelectedTokens.CollectionChanged += SelectedTokensCollectionChanged;
            _Tokens = new CustomCollection();
            _Tokens.CollectionChanged += TokensCollectionChanged;
            this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
            ControlStyles.Opaque | ControlStyles.ResizeRedraw | ControlStyles.Selectable |
            ControlStyles.StandardDoubleClick | DisplayHelp.DoubleBufferFlag, true);
            _BackgroundStyle = new ElementStyle();
            _BackgroundStyle.Class = ElementStyleClassKeys.DateTimeInputBackgroundKey;
            _BackgroundStyle.StyleChanged += new EventHandler(this.VisualPropertyChanged);
            _EditBox = new TextBoxX();
            _EditBox.BorderStyle = BorderStyle.None;
            _EditBox.Visible = false;
            _EditBox.TextChanged += EditBoxTextChanged;
            _EditBox.KeyDown += EditBoxKeyDown;
            _EditBox.GotFocus += EditBoxGotFocus;
            this.Controls.Add(_EditBox);
            _EditBox.SetAutoHeight();
            _VScrollBar = new VScrollBarAdv();
            _VScrollBar.Visible = false;
            _VScrollBar.Scroll += VScrollBarScroll;
            this.Controls.Add(_VScrollBar);
            VisualGroup group = new VisualGroup();
            group.HorizontalItemSpacing = 0;
            group.ArrangeInvalid += ButtonGroupArrangeInvalid;
            group.RenderInvalid += ButtonGroupRenderInvalid;
            group.ResetMouseHover += ButtonGroupResetMouseHover;
            _ButtonGroup = group;
            CreateButtons();
        }
        protected override void Dispose(bool disposing)
        {
            if (_MessageHandlerInstalled)
            {
                MessageHandler.UnregisterMessageClient(this);
                _MessageHandlerInstalled = false;
            }
            base.Dispose(disposing);
        }
        #endregion
        #region Implementation
        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
        {
            if (Dpi.RecordScalePerControl)
                Dpi.SetScaling(factor);
            base.ScaleControl(factor, specified);
            _EditBox.SetAutoHeight();
            LayoutTokens();
        }
        private void EditBoxGotFocus(object sender, EventArgs e)
        {
            FocusToken = null;
        }
        private TokenEditorColorTable GetTokenColorTable()
        {
            return ((Office2007Renderer)GlobalManager.Renderer).ColorTable.TokenEditor;
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            if ((this.BackColor.IsEmpty || this.BackColor == Color.Transparent))
            {
                base.OnPaintBackground(e);
            }
            if (_BackgroundStyle != null)
                _BackgroundStyle.SetColorScheme(this.GetColorScheme());
            TokenEditorColorTable colorTable = GetTokenColorTable();
            PaintBackground(e);
            Rectangle clientBounds = GetClientBounds();
            e.Graphics.SetClip(clientBounds);
            if (this.WatermarkEnabled && this.WatermarkText.Length > 0 && this.IsWatermarkRendered)
            {
                DrawWatermark(e.Graphics);
            }
            foreach (EditToken token in _SelectedTokens)
            {
                PaintToken(token, e, colorTable);
            }
            PaintButtons(e.Graphics);
            e.Graphics.ResetClip();
            base.OnPaint(e);
        }
        private void PaintToken(EditToken token, PaintEventArgs e, TokenEditorColorTable colorTable)
        {
            Graphics g = e.Graphics;
            Rectangle r = token.Bounds;
            r.Offset(_AutoScrollPosition);
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.HighQuality;
            Color textColor = colorTable.Normal.TextColor;
            LinearGradientColorTable background = colorTable.Normal.Background;
            if (token.IsFocused)
            {
                textColor = colorTable.Focused.TextColor;
                background = colorTable.Focused.Background;
            }
            else if (token.MouseOverPart == eTokenPart.Token || token.MouseOverPart == eTokenPart.Image)
                background = colorTable.MouseOver.Background;
            DisplayHelp.FillRoundedRectangle(g, r, 2, background.Start, background.End, background.GradientAngle);
            g.SmoothingMode = sm;
            string text = GetTokenText(token);
            Rectangle rText = r;
            if (EffectiveRemoveTokenButtonVisible)
            {
                Rectangle removeBounds = new Rectangle(r.X, r.Y + (r.Height - _RemoveTokenButtonSize.Height) / 2,
                    _RemoveTokenButtonSize.Width, _RemoveTokenButtonSize.Height);
                Color closeTextColor = textColor;
                if (token.MouseOverPart == eTokenPart.RemoveButton)
                {
                    Office2007ColorTable ct = ((Office2007Renderer)GlobalManager.Renderer).ColorTable;
                    Office2007ButtonItemColorTable buttonColorTable = ct.ButtonItemColors[Enum.GetName(typeof(eButtonColor), eButtonColor.OrangeWithBackground)];
                    Office2007ButtonItemPainter.PaintBackground(g, buttonColorTable.MouseOver, removeBounds, RoundRectangleShapeDescriptor.RectangleShape);
                    closeTextColor = buttonColorTable.MouseOver.Text;
                    //g.FillRectangle(Brushes.Red, removeBounds);
                }
                float symbolSize = Math.Max(1, Math.Min(removeBounds.Width, removeBounds.Height) * 72 / g.DpiX - 1.5f);
                TextDrawing.DrawStringLegacy(g, "\uf00d", Symbols.GetFont(symbolSize, eSymbolSet.Awesome),
                    closeTextColor, removeBounds, eTextFormat.HorizontalCenter | eTextFormat.VerticalCenter);
                token.RemoveButtonBounds = removeBounds;
                rText.X = removeBounds.Right + _TokenPartSpacing;
                rText.Width -= rText.Right - r.Right;
            }
            if (!string.IsNullOrEmpty(token.SymbolRealized))
            {
                Rectangle imageBounds = new Rectangle(rText.X, r.Y, r.Height, r.Height);
                float symbolSize = Math.Max(1, Math.Min(imageBounds.Width, imageBounds.Height) * 72 / g.DpiX - 1.5f);
                TextDrawing.DrawStringLegacy(g, token.SymbolRealized, Symbols.GetFont(symbolSize, token.SymbolSet),
                    (token.SymbolColor.IsEmpty ? textColor : token.SymbolColor),
                    imageBounds, eTextFormat.HorizontalCenter | eTextFormat.VerticalCenter);
                token.ImageBounds = imageBounds;
                rText.X = imageBounds.Right + _TokenPartSpacing;
                rText.Width -= rText.Right - r.Right;
            }
            else if (token.Image != null)
            {
                Rectangle imageBounds = new Rectangle(rText.X, r.Y, token.ImageBounds.Width, token.Image.Height);
                g.DrawImage(token.Image, imageBounds);
                token.ImageBounds = imageBounds;
                rText.X = imageBounds.Right + _TokenPartSpacing;
                rText.Width -= rText.Right - r.Right;
            }
            TextDrawing.DrawString(g, text, this.Font, textColor, rText, eTextFormat.Default | eTextFormat.VerticalCenter);
        }
        protected virtual void PaintBackground(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle r = this.ClientRectangle;
            ElementStyle style = _BackgroundStyle;
            if (!this.BackColor.IsEmpty && this.BackColor != Color.Transparent)
            {
                DisplayHelp.FillRectangle(g, r, this.BackColor);
            }
            if (this.BackgroundImage != null)
                base.OnPaintBackground(e);
            if (style.Custom)
            {
                SmoothingMode sm = g.SmoothingMode;
                //if (m_AntiAlias)
                //    g.SmoothingMode = SmoothingMode.HighQuality;
                ElementStyleDisplayInfo displayInfo = new ElementStyleDisplayInfo(style, e.Graphics, r);
                ElementStyleDisplay.Paint(displayInfo);
                //if (m_AntiAlias)
                //    g.SmoothingMode = sm;
            }
        }
        protected override void OnResize(EventArgs e)
        {
            LayoutTokens();
            base.OnResize(e);
        }
        /// 
        /// Gets or sets the location of the auto-scroll position.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), Description("Indicates location of the auto-scroll position.")]
        public Point AutoScrollPosition
        {
            get
            {
                return _AutoScrollPosition;
            }
            set
            {
                if (_AutoScrollPosition == value) return;
                _AutoScrollPosition = value;
                if (_VScrollBar != null && _VScrollBar.Value != -_AutoScrollPosition.Y)
                    _VScrollBar.Value = Math.Min(_VScrollBar.Maximum, Math.Max(_VScrollBar.Minimum, -_AutoScrollPosition.Y));
                RepositionEditTextBox();
                Invalidate();
            }
        }
        private Rectangle GetClientBounds()
        {
            bool disposeStyle = false;
            ElementStyle style = ElementStyleDisplay.GetElementStyle(_BackgroundStyle, out disposeStyle);
            Rectangle clientRect = this.ClientRectangle;
            clientRect.X += style.PaddingLeft;
            clientRect.Width -= style.PaddingHorizontal;
            clientRect.Y += style.PaddingTop;
            clientRect.Height -= style.PaddingVertical;
            if (disposeStyle)
                style.Dispose();
            style = null;
            return clientRect;
        }
        private Point _AutoScrollPosition = Point.Empty;
        private int _TokenSpacing = 2;
        private int _TokenPartSpacing = 2; // Spacing between different parts of the token, like between image and text and image and close button etc. Its spacing between each part.
        private readonly Size _TokenPadding = new Size(2, 2);
        private void LayoutTokens()
        {
            if (!this.IsHandleCreated || this.IsDisposed || this.Width == 0 || this.Height == 0) return;
            int lineCount = 0;
            Rectangle clientRect = GetClientBounds();
            Graphics g = this.CreateGraphics();
            Size totalSize = LayoutTokens(g, clientRect, out lineCount);
            if (_AutoSizeHeight)
            {
                int heightLines = Math.Min(_MaxHeightLines, lineCount);
                int newHeight = (int)(Math.Ceiling((double)totalSize.Height / lineCount) * heightLines) + (this.Height - clientRect.Height);
                if (_MaxHeightLines == 1)
                    newHeight = GetSingleLineTextBoxHeight();
                if (newHeight != this.Height)
                {
                    g.Dispose();
                    this.Height = newHeight;
                    return;
                }
            }
            if (totalSize.Height > clientRect.Height)
            {
                Rectangle reducedBounds = clientRect;
                int visibleLines = (int)(clientRect.Height / (Math.Ceiling((double)totalSize.Height / lineCount)));
                if (_DropDownButtonVisible && visibleLines <= 2 || visibleLines == 1)
                {
                    // Using scroll button due to space limitation
                    _VScrollBar.Visible = false;
                    _ScrollButton.Visible = true;
                    reducedBounds.Width -= SystemInformation.VerticalScrollBarWidth * (_DropDownButtonVisible ? 2 : 1);
                    if (visibleLines > 1)
                        _ButtonGroup.Orientation = eOrientation.Vertical;
                    else
                        _ButtonGroup.Orientation = eOrientation.Horizontal;
                }
                else
                {
                    int buttonOffset = (_DropDownButtonVisible ? GetButtonHeight() + 1 : 0);
                    // Activate Scroll-bar
                    _VScrollBar.Bounds = new Rectangle(clientRect.Right - SystemInformation.VerticalScrollBarWidth,
                        clientRect.Y + buttonOffset,
                        SystemInformation.VerticalScrollBarWidth,
                        clientRect.Height - buttonOffset);
                    _VScrollBar.Visible = true;
                    _ScrollButton.Visible = false;
                    reducedBounds.Width -= _VScrollBar.Width;
                }
                totalSize = LayoutTokens(g, reducedBounds, out lineCount);
                _VScrollBar.Maximum = totalSize.Height;
                _VScrollBar.LargeChange = clientRect.Height;
                if (this.SelectedTokens.Count > 0)
                    _VScrollBar.SmallChange = this.SelectedTokens[0].Bounds.Height;
                else
                    _VScrollBar.SmallChange = 17;
            }
            else
            {
                _VScrollBar.Visible = false;
                _AutoScrollPosition = Point.Empty;
                _ScrollButton.Visible = false;
            }
            g.Dispose();
            RepositionEditTextBox();
            EnsureTextBoxScrollPosition();
            UpdateButtons();
            this.Invalidate();
        }
        private int GetSingleLineTextBoxHeight()
        {
            Font font = this.Font;
            return font.Height + ((SystemInformation.BorderSize.Height * 4) + 4);
        }
        private Size LayoutTokens(Graphics g, Rectangle clientRect, out int lineCount)
        {
            lineCount = 0;
            if (!this.IsHandleCreated || this.IsDisposed) return Size.Empty;
            clientRect.Inflate(-1, -1);
            Font font = this.Font;
            Size totalSize = Size.Empty;
            int singleLineTextBoxHeight = GetSingleLineTextBoxHeight() - 2; // 2 is for top and bottom border
            if (_SelectedTokens.Count == 0)
            {
                lineCount = 1;
                totalSize = new Size(clientRect.Width, singleLineTextBoxHeight);
                _EditBoxLocation = new Point(clientRect.X, clientRect.Y + (totalSize.Height - _EditBox.Height) / 2);
                _EditBox.Width = clientRect.Width - (_DropDownButtonVisible ? SystemInformation.VerticalScrollBarWidth : 0);
                return totalSize;
            }
            int largestTokenHeight = 0;
            foreach (EditToken token in _SelectedTokens)
            {
                token.RemoveButtonBounds = Rectangle.Empty;
                token.ImageBounds = Rectangle.Empty;
                string text = GetTokenText(token);
                Size size = TextDrawing.MeasureString(g, (string.IsNullOrEmpty(text) ? "A" : text), font);
                size.Width += _TokenPadding.Width * 2;
                size.Height += _TokenPadding.Height * 2;
                if (EffectiveRemoveTokenButtonVisible)
                {
                    size.Width += _RemoveTokenButtonSize.Width + _TokenPartSpacing;
                    if (_RemoveTokenButtonSize.Height > size.Height)
                        size.Height = _RemoveTokenButtonSize.Height;
                }
                if (!string.IsNullOrEmpty(token.SymbolRealized))
                {
                    size.Width += size.Height + _TokenPartSpacing;
                }
                else if (token.Image != null)
                {
                    size.Width += token.Image.Width + _TokenPartSpacing;
                    if (token.Image.Height > size.Height)
                        size.Height = token.Image.Height;
                }
                largestTokenHeight = Math.Max(largestTokenHeight, size.Height);
                token.Bounds = new Rectangle(Point.Empty, size);
            }
            lineCount = 1;
            totalSize.Height = largestTokenHeight;
            Point currentPos = clientRect.Location;
            foreach (EditToken token in _SelectedTokens)
            {
                Rectangle tokenBounds = new Rectangle(currentPos.X, currentPos.Y, token.Bounds.Width, largestTokenHeight);
                if (tokenBounds.Right > clientRect.Right && currentPos.X > clientRect.X)
                {
                    currentPos.Y += largestTokenHeight + _TokenSpacing;
                    currentPos.X = clientRect.X;
                    tokenBounds.Y = currentPos.Y;
                    tokenBounds.X = currentPos.X;
                    totalSize.Height += largestTokenHeight + _TokenSpacing;
                    lineCount++;
                }
                currentPos.X += tokenBounds.Width + _TokenSpacing;
                token.Bounds = tokenBounds;
                if (tokenBounds.Right - clientRect.X > totalSize.Width)
                    totalSize.Width = tokenBounds.Right - clientRect.X;
            }
            if (clientRect.Right - currentPos.X < _TextBoxMinWidth)
            {
                currentPos.Y += largestTokenHeight + _TokenSpacing;
                currentPos.X = clientRect.X;
                lineCount++;
                totalSize.Height += largestTokenHeight + _TokenSpacing;
            }
            if (lineCount == 1)
                totalSize.Height = Math.Max(totalSize.Height, singleLineTextBoxHeight);
            _EditBoxLocation = new Point(currentPos.X, currentPos.Y + (largestTokenHeight - _EditBox.Height) / 2);
            _EditBox.Width = clientRect.Right - currentPos.X - (lineCount == 1 && _DropDownButtonVisible ? SystemInformation.VerticalScrollBarWidth : 0);
            return totalSize;
        }
        private Point _EditBoxLocation = Point.Empty;
        private void RepositionEditTextBox()
        {
            Point loc = _EditBoxLocation;
            loc.Offset(_AutoScrollPosition);
            _EditBox.Location = loc;
        }
        private void VScrollBarScroll(object sender, ScrollEventArgs e)
        {
            if (e.NewValue != e.OldValue)
            {
                _AutoScrollPosition.Y = -e.NewValue;
                RepositionEditTextBox();
                this.Invalidate();
            }
        }
        private const int _TextBoxMinWidth = 36;
        protected override void OnHandleCreated(EventArgs e)
        {
            _EditBox.SetAutoHeight();
            LayoutTokens();
            base.OnHandleCreated(e);
        }
        private string GetTokenText(EditToken token)
        {
            if (!string.IsNullOrEmpty(token.Text))
                return token.Text;
            return token.Value;
        }
        /// 
        /// Returns the color scheme used by control. Color scheme for Office2007 style will be retrieved from the current renderer instead of
        /// local color scheme referenced by ColorScheme property.
        /// 
        /// An instance of ColorScheme object.
        protected virtual ColorScheme GetColorScheme()
        {
            BaseRenderer r = Rendering.GlobalManager.Renderer;
            if (r is Office2007Renderer)
                return ((Office2007Renderer)r).ColorTable.LegacyColors;
            return new ColorScheme();
        }
        private ElementStyle _BackgroundStyle = null;
        /// 
        /// Specifies the background style of the control.
        /// 
        [Browsable(true), Category("Style"), Description("Gets or sets bar background style."), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ElementStyle BackgroundStyle
        {
            get { return _BackgroundStyle; }
        }
        /// 
        /// Resets style to default value. Used by windows forms designer.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetBackgroundStyle()
        {
            _BackgroundStyle.StyleChanged -= new EventHandler(this.VisualPropertyChanged);
            _BackgroundStyle = new ElementStyle();
            _BackgroundStyle.StyleChanged += new EventHandler(this.VisualPropertyChanged);
            this.Invalidate();
        }
        private void VisualPropertyChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }
        private CustomCollection _SelectedTokens;
        /// 
        /// Gets the collection of the selected tokens.
        /// 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public CustomCollection SelectedTokens
        {
            get
            {
                return _SelectedTokens;
            }
        }
        private void SelectedTokensCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (object item in e.NewItems)
                {
                    ((EditToken)item).IsSelected = true;
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (object item in e.OldItems)
                {
                    ((EditToken)item).IsSelected = false;
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (object item in e.NewItems)
                {
                    ((EditToken)item).IsSelected = true;
                }
                foreach (object item in e.OldItems)
                {
                    ((EditToken)item).IsSelected = false;
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (EditToken item in _Tokens)
                {
                    item.IsSelected = false;
                }
            }
            LayoutTokens();
            UpdateText();
            UpdateEditBoxWatermark();
            OnSelectedTokensChanged(EventArgs.Empty);
        }
        /// 
        /// Occurs when SelectedTokens collection changes.
        /// 
        [Description("Occurs when SelectedTokens collection changes.")]
        public event EventHandler SelectedTokensChanged;
        /// 
        /// Raises SelectedTokensChanged event.
        /// 
        /// Provides event arguments.
        protected virtual void OnSelectedTokensChanged(EventArgs e)
        {
            EventHandler handler = SelectedTokensChanged;
            if (handler != null)
                handler(this, e);
        }
        private CustomCollection _Tokens;
        /// 
        /// Gets the collection of the tokens available for selection.
        /// 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public CustomCollection Tokens
        {
            get
            {
                return _Tokens;
            }
        }
        private void TokensCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
        }
        private bool EffectiveRemoveTokenButtonVisible
        {
            get
            {
                return _RemoveTokenButtonVisible && !_ReadOnly;
            }
        }
        private Size _RemoveTokenButtonSize = new Size(14, 14);
        private bool _RemoveTokenButtonVisible = true;
        /// 
        /// Indicates whether remove token button is displayed on individual tokens so they can be removed from the selection.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether remove token button is displayed on individual tokens so they can be removed from the selection.")]
        public bool RemoveTokenButtonVisible
        {
            get { return _RemoveTokenButtonVisible; }
            set
            {
                if (value != _RemoveTokenButtonVisible)
                {
                    bool oldValue = _RemoveTokenButtonVisible;
                    _RemoveTokenButtonVisible = value;
                    OnRemoveTokenButtonVisibleChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when RemoveTokenButtonVisible property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnRemoveTokenButtonVisibleChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("RemoveTokenButtonVisible"));
            if (_SelectedTokens.Count > 0)
                LayoutTokens();
        }
        /// 
        /// Returns the token from SelectedTokens at specified position or null/nothing if no token is at given location.
        /// 
        /// Location in client coordinates to test.
        /// EditToken instance or null/nothing
        public EditToken GetSelectedTokenAt(Point p)
        {
            foreach (EditToken token in _SelectedTokens)
            {
                Rectangle tokenBounds = token.Bounds;
                tokenBounds.Offset(_AutoScrollPosition);
                if (tokenBounds.Contains(p))
                    return token;
            }
            return null;
        }
        private EditToken _MouseOverToken = null;
        private EditToken MouseOverToken
        {
            get
            {
                return _MouseOverToken;
            }
            set
            {
                if (_MouseOverToken != value)
                {
                    if (_MouseOverToken != null)
                        _MouseOverToken = value;
                    this.Invalidate();
                }
            }
        }
        /// 
        /// Occurs when mouse enters one of the SelectedTokens token.
        /// 
        [Description("Occurs when mouse enters one of the SelectedTokens token.")]
        public event EventHandler TokenMouseEnter;
        /// 
        /// Raises TokenMouseEnter event.
        /// 
        /// Provides event arguments.
        protected virtual void OnTokenMouseEnter(object sender, EventArgs e)
        {
            EventHandler handler = TokenMouseEnter;
            if (handler != null)
                handler(sender, e);
        }
        /// 
        /// Occurs when mouse leaves one of the SelectedTokens token.
        /// 
        [Description("Occurs when mouse leaves one of the SelectedTokens token.")]
        public event EventHandler TokenMouseLeave;
        /// 
        /// Raises TokenMouseLeave event.
        /// 
        /// Provides event arguments.
        protected virtual void OnTokenMouseLeave(object sender, EventArgs e)
        {
            HideToolTip();
            EventHandler handler = TokenMouseLeave;
            if (handler != null)
                handler(sender, e);
        }
        /// 
        /// Occurs when mouse clicks one of the SelectedTokens token.
        /// 
        [Description("Occurs when mouse clicks one of the SelectedTokens token.")]
        public event MouseEventHandler TokenMouseClick;
        /// 
        /// Raises TokenMouseClick event.
        /// 
        /// Provides event arguments.
        protected virtual void OnTokenMouseClick(object sender, MouseEventArgs e)
        {
            MouseEventHandler handler = TokenMouseClick;
            if (handler != null)
                handler(sender, e);
        }
        /// 
        /// Occurs when mouse double clicks one of the SelectedTokens token.
        /// 
        [Description("Occurs when mouse double clicks one of the SelectedTokens token.")]
        public event MouseEventHandler TokenMouseDoubleClick;
        /// 
        /// Raises TokenMouseClick event.
        /// 
        /// Provides event arguments.
        protected virtual void OnTokenMouseDoubleClick(object sender, MouseEventArgs e)
        {
            MouseEventHandler handler = TokenMouseDoubleClick;
            if (handler != null)
                handler(sender, e);
        }
        /// 
        /// Occurs when mouse hovers one of the SelectedTokens token.
        /// 
        [Description("Occurs when mouse hovers one of the SelectedTokens token.")]
        public event EventHandler TokenMouseHover;
        /// 
        /// Raises TokenMouseHover event.
        /// 
        /// Provides event arguments.
        protected virtual void OnTokenMouseHover(object sender, EventArgs e)
        {
            EventHandler handler = TokenMouseHover;
            if (handler != null)
                handler(sender, e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            EditToken token = GetSelectedTokenAt(e.Location);
            if (token != _MouseOverToken)
            {
                if (_MouseOverToken != null)
                {
                    _MouseOverToken.MouseOverPart = eTokenPart.None;
                    OnTokenMouseLeave(_MouseOverToken, e);
                }
                _MouseOverToken = token;
                this.Invalidate();
                DevComponents.AdvTree.Interop.WinApi.ResetHover(this);
                if (_MouseOverToken != null)
                    OnTokenMouseEnter(_MouseOverToken, e);
            }
            if (_MouseOverToken != null)
            {
                eTokenPart oldMouseOverPart = _MouseOverToken.MouseOverPart;
                if (EffectiveRemoveTokenButtonVisible && !_MouseOverToken.RemoveButtonBounds.IsEmpty && _MouseOverToken.RemoveButtonBounds.Contains(e.Location))
                    _MouseOverToken.MouseOverPart = eTokenPart.RemoveButton;
                else if (!_MouseOverToken.ImageBounds.IsEmpty && _MouseOverToken.ImageBounds.Contains(e.Location))
                    _MouseOverToken.MouseOverPart = eTokenPart.Image;
                else
                    _MouseOverToken.MouseOverPart = eTokenPart.Token;
                if (oldMouseOverPart != _MouseOverToken.MouseOverPart)
                    this.Invalidate();
            }
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseMove(e);
            base.OnMouseMove(e);
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            HideToolTip();
            if (_MouseOverToken == null && !_ReadOnly && !(_ButtonGroup.Visible && _ButtonGroup.RenderBounds.Contains(e.Location)))
            {
                ShowEditTextBox();
            }
            else
                this.Select();
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseDown(e);
            base.OnMouseDown(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseUp(e);
            base.OnMouseUp(e);
        }
        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (_MouseOverToken != null && _MouseOverToken.MouseOverPart == eTokenPart.RemoveButton)
            {
                EditToken token = _MouseOverToken;
                RemovingTokenEventArgs args = new RemovingTokenEventArgs(token, eEventSource.Mouse);
                OnRemovingToken(args);
                if (args.Cancel) return;
                LeaveMouseOverToken();
                this.SelectedTokens.Remove(token);
            }
            else if (_MouseOverToken != null)
            {
                OnTokenMouseClick(_MouseOverToken, e);
            }
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseClick(e);
            base.OnMouseClick(e);
        }
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            if (_MouseOverToken != null)
            {
                OnTokenMouseDoubleClick(_MouseOverToken, e);
            }
            base.OnMouseDoubleClick(e);
        }
        protected override void OnMouseHover(EventArgs e)
        {
            if (_MouseOverToken != null)
            {
                OnTokenMouseHover(_MouseOverToken, e);
                ShowToolTip(_MouseOverToken);
            }
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseHover(e);
            base.OnMouseHover(e);
        }
        /// 
        /// Occurs before token is removed from the SelectedTokens by end user.
        /// 
        [Description("Occurs before token is removed from the SelectedTokens by end user.")]
        public event RemovingTokenEventHandler RemovingToken;
        /// 
        /// Raises RemovingToken event.
        /// 
        /// Provides event arguments.
        protected virtual void OnRemovingToken(RemovingTokenEventArgs e)
        {
            RemovingTokenEventHandler handler = RemovingToken;
            if (handler != null)
                handler(this, e);
        }
        private void LeaveMouseOverToken()
        {
            HideToolTip();
            if (_MouseOverToken != null)
            {
                _MouseOverToken.MouseOverPart = eTokenPart.None;
                OnTokenMouseLeave(_MouseOverToken, EventArgs.Empty);
                _MouseOverToken = null;
                this.Invalidate();
            }
        }
        private bool _IsMouseOver = false;
        protected override void OnMouseLeave(EventArgs e)
        {
            _IsMouseOver = false;
            LeaveMouseOverToken();
            if (_ButtonGroup.Visible)
                _ButtonGroup.ProcessMouseLeave();
            base.OnMouseLeave(e);
        }
        protected override void OnMouseEnter(EventArgs e)
        {
            _IsMouseOver = true;
            base.OnMouseEnter(e);
        }
        private EditToken _FocusToken = null;
        private EditToken FocusToken
        {
            get { return _FocusToken; }
            set
            {
                if (_FocusToken != value)
                {
                    if (_FocusToken != null)
                        _FocusToken.IsFocused = false;
                    _FocusToken = value;
                    if (_FocusToken != null)
                        _FocusToken.IsFocused = true;
                    this.Invalidate();
                }
            }
        }
        private void FocusPreviousToken()
        {
            if (this.SelectedTokens.Count == 0) return;
            int index = _SelectedTokens.Count - 1;
            if (_FocusToken != null)
                index = Math.Max(0, _SelectedTokens.IndexOf(_FocusToken) - 1);
            FocusToken = _SelectedTokens[index];
        }
        private void FocusNextToken()
        {
            if (this.SelectedTokens.Count == 0) return;
            int index = 0;
            if (_FocusToken != null)
            {
                if (_SelectedTokens.IndexOf(_FocusToken) == _SelectedTokens.Count - 1)
                {
                    FocusToken = null;
                    _EditBox.Select();
                    return;
                }
                index = Math.Min(_SelectedTokens.Count - 1, _SelectedTokens.IndexOf(_FocusToken) + 1);
            }
            FocusToken = _SelectedTokens[index];
        }
        private void DeleteFocusedToken(bool isBackspace, eEventSource eventSource)
        {
            EditToken focusToken = _FocusToken;
            if (focusToken == null) return;
            RemovingTokenEventArgs e = new RemovingTokenEventArgs(focusToken, eventSource);
            OnRemovingToken(e);
            if (e.Cancel) return;
            FocusToken = null;
            int index = Math.Max(0, _SelectedTokens.IndexOf(focusToken) - 1);
            _SelectedTokens.Remove(focusToken);
            if (_SelectedTokens.Count > 0)
            {
                FocusToken = _SelectedTokens[index];
            }
            else
            {
                _EditBox.Select();
            }
        }
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (!_EditBox.Focused)
            {
                if (keyData == Keys.Left)
                {
                    FocusPreviousToken();
                    return true;
                }
                else if (keyData == Keys.Right)
                {
                    FocusNextToken();
                    return true;
                }
                else if (keyData == Keys.Back)
                {
                    DeleteFocusedToken(true, eEventSource.Keyboard);
                    return true;
                }
                else if (keyData == Keys.Delete)
                {
                    DeleteFocusedToken(false, eEventSource.Keyboard);
                    return true;
                }
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (_FocusToken != null)
            {
                FocusToken = null;
                _EditBox.Select();
            }
            base.OnKeyDown(e);
        }
        protected override void OnLeave(EventArgs e)
        {
            if (_EditBox.Visible)
            {
                _EditBox.Visible = false;
                if (_ValidateTokenTextOnLostFocus && !string.IsNullOrEmpty(_EditBox.Text))
                {
                    ValidateAndConvertEditText(_EditBox.Text);
                }
            }
            _EditBox.Text = "";
            FocusToken = null;
            if (IsPopupOpen)
                CloseAutoCompleteDropDown();
            HideToolTip();
            base.OnLeave(e);
        }
        protected override void OnEnter(EventArgs e)
        {
            if (!_ReadOnly)
            {
                ShowEditTextBox();
            }
            base.OnEnter(e);
        }
        private bool _ReadOnly = false;
        /// 
        /// Indicates whether tokens can be added or removed by end user. Default value is false.
        /// 
        [DefaultValue(false), Category("Behavior"), Description("Indicates whether tokens can be added or removed by end user. Default value is false.")]
        public bool ReadOnly
        {
            get { return _ReadOnly; }
            set
            {
                if (value != _ReadOnly)
                {
                    bool oldValue = _ReadOnly;
                    _ReadOnly = value;
                    OnReadOnlyChanged(oldValue, value);
                }
            }
        }
        private void ShowEditTextBox()
        {
            _EditBox.Visible = true;
            _EditBox.Focus();
            EnsureTextBoxScrollPosition();
        }
        private void EnsureTextBoxScrollPosition()
        {
            if (!_EditBox.Visible) return;
            Rectangle clientBounds = GetClientBounds();
            if (clientBounds.Contains(_EditBox.Bounds))
                return;
            // Scroll content vertically to ensure text-box is withing client bounds
            AutoScrollPosition = new Point(0, AutoScrollPosition.Y + (clientBounds.Bottom - _EditBox.Bounds.Bottom));
        }
        /// 
        /// Called when ReadOnly property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnReadOnlyChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("ReadOnly"));
            if (_ReadOnly)
            {
                if (_EditBox.Visible)
                    _EditBox.Visible = false;
            }
            else if (this.Focused)
            {
                ShowEditTextBox();
                _EditBox.Focus();
            }
            if (_RemoveTokenButtonVisible)
                LayoutTokens();
        }
        private int _DropDownHeight = 120;
        /// 
        /// Indicates the height of the auto-complete drop-down.
        /// 
        [DefaultValue(120), Category("Appearance"), Description("Indicates the height of the auto-complete drop-down")]
        public int DropDownHeight
        {
            get { return _DropDownHeight; }
            set
            {
                if (value != _DropDownHeight)
                {
                    int oldValue = _DropDownHeight;
                    _DropDownHeight = value;
                    OnDropDownHeightChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when DropDownHeight property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnDropDownHeightChanged(int oldValue, int newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("DropDownHeight"));   
        }
        private int _DropDownWidth = 180;
        /// 
        /// Indicates the width of the auto-complete drop-down.
        /// 
        [DefaultValue(180), Category("Appearance"), Description("Indicates the width of the auto-complete drop-down.")]
        public int DropDownWidth
        {
            get { return _DropDownWidth; }
            set
            {
                if (value != _DropDownWidth)
                {
                    int oldValue = _DropDownWidth;
                    _DropDownWidth = value;
                    OnDropDownWidthChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when DropDownWidth property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnDropDownWidthChanged(int oldValue, int newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("DropDownWidth"));
        }
        private bool _EnterKeyValidatesToken = true;
        /// 
        /// Indicates whether when token text is entered into the text-box pressing the Enter key attempts to validate the token and converts the text to token.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether when token text is entered into the text-box pressing the Enter key attempts to validate the token and converts the text to token.")]
        public bool EnterKeyValidatesToken
        {
            get
            {
                return _EnterKeyValidatesToken;
            }
            set
            {
                _EnterKeyValidatesToken = value;
            }
        }
        private void EditBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape && IsPopupOpen)
            {
                CloseAutoCompleteDropDown();
            }
            else if (e.KeyCode == Keys.Enter && IsPopupOpen && _AutoCompleteListBox != null && _AutoCompleteListBox.SelectedIndex >= 0)
            {
                SelectToken(_Tokens[_AutoCompleteListBox.SelectedIndex]);
            }
            else if (e.KeyCode == Keys.Enter && EnterKeyValidatesToken)
            {
                ValidateAndConvertEditText(_EditBox.Text);
            }
            else if (e.KeyCode == Keys.Down)
            {
                if (IsPopupOpen && _AutoCompleteListBox != null)
                {
                    _AutoCompleteListBox.SelectNextItem();
                    e.Handled = true;
                }
                else if (!IsPopupOpen && string.IsNullOrEmpty(_EditBox.Text))
                {
                    IsPopupOpen = true;
                    e.Handled = true;
                }
            }
            else if (_AutoCompleteListBox != null && e.KeyCode == Keys.Up)
            {
                _AutoCompleteListBox.SelectPreviousItem();
                e.Handled = true;
            }
            else if ((e.KeyCode == Keys.Left || e.KeyCode == Keys.Back) && string.IsNullOrEmpty(_EditBox.Text))
            {
                CloseAutoCompleteDropDown();
                if (this.SelectedTokens.Count > 0)
                {
                    this.Select();
                    FocusPreviousToken();
                }
                e.Handled = true;
            }
        }
        private void AutoCompleteListBoxItemClick(object sender, EventArgs e)
        {
            if (_AutoCompleteListBox.SelectedIndex >= 0)
                SelectToken(_Tokens[_AutoCompleteListBox.SelectedIndex]);
        }
        private bool SelectToken(EditToken token)
        {
            if (token.IsSelected) return false;
            ValidateTokenEventArgs args = new ValidateTokenEventArgs(token, false);
            if (args.IsValid && args.Token != null)
            {
                token = args.Token;
                this.SelectedTokens.Add(token);
                _EditBox.Text = "";
                CloseAutoCompleteDropDown();
                return true;
            }
            return false;
        }
        private bool ValidateAndConvertEditText(string text)
        {
            if (string.IsNullOrEmpty(text))
                return false;
            IsPopupOpen = false;
            bool isNewToken = false;
            EditToken token = FindOrCreateToken(text, out isNewToken);
            ValidateTokenEventArgs args = new ValidateTokenEventArgs(token, isNewToken);
            OnValidateToken(args);
            if (args.IsValid && args.Token != null)
            {
                token = args.Token;
                this.SelectedTokens.Add(token);
                _EditBox.Text = "";
                CloseAutoCompleteDropDown();
                return true;
            }
            return false;
        }
        private bool IsSelected(EditToken item)
        {
            return item.IsSelected;
            //foreach (EditToken selectedToken in _SelectedTokens)
            //{
            //    if(selectedToken == item)
            //        return true;
            //}
            //return false;
        }
        private EditToken FindOrCreateToken(string text, out bool isNew)
        {
            isNew = false;
            foreach (EditToken item in _Tokens)
            {
                if (!item.IsSelected && TokenExactMatch(text, item, _TokenFilterBehavior))
                {
                    return item;
                }
            }
            isNew = true;
            return new EditToken(text);
        }
        private void EditBoxTextChanged(object sender, EventArgs e)
        {
            string text = _EditBox.Text;
            if (!_DroppedDown && FilteredTokenExists(text))
            {
                OpenAutoCompleteDropDown();
            }
            if (_AutoCompleteListBox != null)
            {
                FilterAutoCompleteBox(_AutoCompleteListBox, text);
            }
            foreach (string separator in _Separators)
            {
                if (text.EndsWith(separator))
                {
                    text = text.Substring(0, text.Length - separator.Length);
                    ValidateAndConvertEditText(text);
                    break;
                }
            }
        }
        private PopupHostController _PopupController = null;
        private ListBoxAdv _AutoCompleteListBox = null;
        private DateTime _MultiDropDownOpenedAtTime = DateTime.MinValue;
        private DateTime _MultiDropDownClosedAtTime = DateTime.MinValue;
        /// 
        /// Occurs before token auto-complete popup is displayed and allows cancelation of popup display.
        /// 
        [Description("Occurs before token auto-complete popup is displayed and allows cancelation of popup display.")]
        public event CancelEventHandler BeforeAutoCompletePopupOpen;
        /// 
        /// Occurs after auto-complete popup is open.
        /// 
        [Description("Occurs after auto-complete popup is open.")]
        public event EventHandler AutoCompletePopupOpened;
        /// 
        /// Raises AutoCompletePopupOpened event.
        /// 
        /// Provides event arguments.
        protected virtual void OnAutoCompletePopupOpened(EventArgs e)
        {
            EventHandler handler = AutoCompletePopupOpened;
            if (handler != null)
                handler(this, e);
        }
        /// 
        /// Raises BeforeAutoCompletePopupOpen event.
        /// 
        /// Provides event arguments.
        protected virtual void OnBeforeAutoCompletePopupOpen(CancelEventArgs e)
        {
            CancelEventHandler handler = BeforeAutoCompletePopupOpen;
            if (handler != null)
                handler(this, e);
        }
        private void OpenAutoCompleteDropDown()
        {
            if (_PopupController == null)
            {
                _PopupController = new PopupHostController();
                _PopupController.Closed += PopupControllerClosed;
            }
            if (_AutoCompleteListBox == null)
            {
                _AutoCompleteListBox = CreateAutoCompleteListBox();
                //_AutoCompleteListBox.Resize += _AutoCompleteListBox_Resize;
                //this.Parent.Controls.Add(_AutoCompleteListBox);
                //_AutoCompleteListBox.Location = new Point(10,100);
            }
            
            if (!_MessageHandlerInstalled && _DropDownButtonVisible)
            {
                MessageHandler.RegisterMessageClient(this);
                _MessageHandlerInstalled = true;
            }
            LoadAutoCompleteBox(_AutoCompleteListBox);
            if (!_PopupController.PopupUserSize || !_PreservePopupSize)
            {
                _AutoCompleteListBox.Height = Dpi.Height(this.DropDownHeight);
                _AutoCompleteListBox.Width = (this.DropDownWidth > 0 ? Dpi.Width(this.DropDownWidth) : this.Width);
                //_AutoCompleteListBox.MinimumSize = _AutoCompleteListBox.Size;
            }
            CancelEventArgs cancelArgs = new CancelEventArgs();
            OnBeforeAutoCompletePopupOpen(cancelArgs);
            if (cancelArgs.Cancel)
                return;
            Point location = PointToScreen(new Point(0, Height));
            TokenEditorPopupEventArgs popupArgs = new TokenEditorPopupEventArgs(location, _AutoCompleteListBox.Size);
            OnBeforePopupOpen(popupArgs);
            location = popupArgs.PopupLocation;
            ePopupResizeEdge resize = _EnablePopupResize ? ePopupResizeEdge.BottomRight : ePopupResizeEdge.None;
            _PopupController.AutoClose = false;
            _PopupController.ParentControlBounds = new Rectangle(PointToScreen(Point.Empty), this.Size);
            _PopupController.Show(_AutoCompleteListBox, location.X, location.Y, 0, 0, resize);
            _EditBox.Focus();
            _EditBox.SelectionLength = 0; // Clear selection that happens upon focus
            if (_EditBox.TextLength > 0)
                _EditBox.SelectionStart = _EditBox.TextLength;
            _PopupController.AutoClose = true;
            _DroppedDown = true;
            _MultiDropDownOpenedAtTime = DateTime.Now;
            OnAutoCompletePopupOpened(EventArgs.Empty);
        }
        /// 
        /// Occurs before the auto-complete popup is displayed and allows you to adjust popup location.
        /// 
        [Description("Occurs before the auto-complete popup is displayed and allows you to adjust popup location.")]
        public event TokenEditorPopupEventHandler BeforePopupOpen;
        /// 
        /// Raises BeforePopupOpen event.
        /// 
        /// Provides event arguments.
        protected virtual void OnBeforePopupOpen(TokenEditorPopupEventArgs e)
        {
            TokenEditorPopupEventHandler handler = BeforePopupOpen;
            if (handler != null)
                handler(this, e);
        }
        private void LoadAutoCompleteBox(ListBoxAdv listBox)
        {
            listBox.BeginUpdate();
            listBox.Items.Clear();
            listBox.CheckBoxesVisible = _CheckBoxesVisible;
            listBox.ShowToolTips = _ShowToolTips;
            foreach (EditToken item in _Tokens)
            {
                ListBoxItem listItem = new ListBoxItem();
                listItem.Text = GetTokenText(item);
                listItem.Tooltip = item.Tooltip;
                if (_CheckBoxesVisible)
                    listItem.CheckState = (item.IsSelected ? CheckState.Checked : CheckState.Unchecked);
                else
                    listItem.Visible = !item.IsSelected;
                listBox.Items.Add(listItem);
            }
            listBox.EndUpdate();
        }
        private bool FilteredTokenExists(string text)
        {
            foreach (EditToken item in _Tokens)
            {
                if (item.IsSelected) continue;
                if (TokenMatch(text, item, _TokenFilterBehavior))
                    return true;
            }
            return false;
        }
        private eTokenFilterBehavior _TokenFilterBehavior = eTokenFilterBehavior.TextAndValue;
        /// 
        /// Indicates how tokens are filtered based on the entered text
        /// 
        [DefaultValue(eTokenFilterBehavior.TextAndValue), Category("Behavior"), Description("Indicates how tokens are filtered based on the entered text")]
        public eTokenFilterBehavior TokenFilterBehavior
        {
            get { return _TokenFilterBehavior; }
            set { _TokenFilterBehavior = value; }
        }
        private static bool TokenMatch(string filterText, EditToken token, eTokenFilterBehavior behavior)
        {
            filterText = filterText.ToLower();
            if(behavior == eTokenFilterBehavior.Text)
                return !string.IsNullOrEmpty(token.Text) && token.Text.ToLower().Contains(filterText);
            else if(behavior == eTokenFilterBehavior.Value)
                return !string.IsNullOrEmpty(token.Value) && token.Value.ToLower().Contains(filterText);
            return !string.IsNullOrEmpty(token.Text) && token.Text.ToLower().Contains(filterText) || !string.IsNullOrEmpty(token.Value) && token.Value.ToLower().Contains(filterText);
        }
        private static bool TokenExactMatch(string filterText, EditToken token, eTokenFilterBehavior behavior)
        {
            filterText = filterText.ToLower();
            if (behavior == eTokenFilterBehavior.Text)
                return !string.IsNullOrEmpty(token.Text) && token.Text.ToLower() == filterText;
            else if (behavior == eTokenFilterBehavior.Value)
                return !string.IsNullOrEmpty(token.Value) && token.Value.ToLower() == filterText;
            return !string.IsNullOrEmpty(token.Text) && token.Text.ToLower() == filterText || !string.IsNullOrEmpty(token.Value) && token.Value.ToLower() == filterText;
        }
        private void FilterAutoCompleteBox(ListBoxAdv listBox, string filterText)
        {
            bool oneVisible = false;
            listBox.BeginUpdate();
            if (string.IsNullOrEmpty(filterText))
            {
                if (!_CheckBoxesVisible)
                {
                    foreach (ListBoxItem item in listBox.Items)
                    {
                        item.IsSelected = false;
                        item.Visible = !item.IsSelected;
                        if (item.Visible)
                            oneVisible = true;
                    }
                }
            }
            else
            {
                for (int i = 0; i < listBox.Items.Count; i++)
                {
                    ListBoxItem item = (ListBoxItem)listBox.Items[i];
                    EditToken token = _Tokens[i];
                    if (!token.IsSelected && TokenMatch(filterText, token, _TokenFilterBehavior))
                    {
                        if (!_CheckBoxesVisible)
                            item.Visible = true;
                        if (!oneVisible)
                            item.IsSelected = true;
                        else
                            item.IsSelected = false;
                        oneVisible = true;
                    }
                    else if (!_CheckBoxesVisible)
                        item.Visible = false;
                    else
                        item.IsSelected = false;
                }
            }
            listBox.EndUpdate();
            if (!oneVisible && !_CheckBoxesVisible)
                CloseAutoCompleteDropDown();
        }
        private ListBoxAdv CreateAutoCompleteListBox()
        {
            ListBoxAdv listBox = new ListBoxAdv();
#if (!TRIAL)
            listBox.LicenseKey = "F962CEC7-CD8F-4911-A9E9-CAB39962FC1F";
#endif
            //listBox.BackColor = Color.White;
            listBox.BackgroundStyle.Class = ElementStyleClassKeys.ListBoxAdvKey;
            listBox.ItemClick += AutoCompleteListBoxItemClick;
            listBox.ItemCheck += AutoCompleteListBoxItemCheck;
            listBox.AutoScroll = true;
            //listBox.BackgroundStyle.Reset();
            //listBox.BackgroundStyle.BackColor = SystemColors.Window;
            //listBox.BackgroundStyle.Border = eStyleBorderType.None;
            return listBox;
        }
        void AutoCompleteListBoxItemCheck(object sender, ListBoxAdvItemCheckEventArgs e)
        {
            int index = _AutoCompleteListBox.Items.IndexOf(e.Item);
            EditToken token = _Tokens[index];
            if (e.Item.CheckState == CheckState.Unchecked && token.IsSelected)
                this.SelectedTokens.Remove(token);
            else if (!token.IsSelected)
                this.SelectedTokens.Add(token);
        }
        private void PopupControllerClosed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            _DroppedDown = false;
            //m_SelectedIndexInternal = this.SelectedIndex;
            _MultiDropDownClosedAtTime = DateTime.Now;
            //OnDropDownClosed(e);
        }
        private void CloseAutoCompleteDropDown()
        {
            if (_PopupController != null && _DroppedDown)
            {
                _PopupController.Hide();
            }
        }
        private bool _PreservePopupSize = true;
        /// 
        /// Indicates whether auto-complete popup size is preserved between popup displays if popup is resized by end-user.
        /// 
        [DefaultValue(true), Category("Auto-Complete"), Description("Indicates whether auto-complete popup size is preserved between popup displays if popup is resized by end-user.")]
        public bool PreservePopupSize
        {
            get { return _PreservePopupSize; }
            set
            {
                _PreservePopupSize = value;
            }
        }
        private bool _EnablePopupResize = true;
        /// 
        /// Indicates whether auto-complete popup can be resized by end user.
        /// 
        [DefaultValue(true), Category("Auto-Complete"), Description("Indicates whether auto-complete popup can be resized by end user.")]
        public bool EnablePopupResize
        {
            get { return _EnablePopupResize; }
            set
            {
                _EnablePopupResize = value;
            }
        }
        private bool _PopupCloseButtonVisible = true;
        /// 
        /// Indicates whether multi-column popup close button is visible.
        /// 
        [DefaultValue(true), Category("Auto-Complete"), Description("Indicates whether multi-column popup close button is visible.")]
        public bool PopupCloseButtonVisible
        {
            get { return _PopupCloseButtonVisible; }
            set
            {
                _PopupCloseButtonVisible = value;
            }
        }
        private bool _DroppedDown = false;
        /// 
        /// Gets or sets whether auto-complete popup window is open.
        /// 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsPopupOpen
        {
            get { return _DroppedDown; }
            set
            {
                if (value != _DroppedDown)
                {
                    if (value)
                        OpenAutoCompleteDropDown();
                    else
                        CloseAutoCompleteDropDown();
                }
            }
        }
        private List _Separators = new List();
        /// 
        /// Gets the list of separators which are used to divide entered text into the tokens.
        /// 
        [Category("Behavior"), Description("Gets the list of separators which are used to divide entered text into the tokens."), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MergableProperty(false), Localizable(true)]
        [Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version= 2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public List Separators
        {
            get { return _Separators; }
        }
        /// 
        /// Occurs when an token is selected from the auto-complete list or when text entry by end user is parsed into token to validate it.
        /// 
        [Description("Occurs when an token is selected from the auto-complete list or when text entry by end user is parsed into token to validate it.")]
        public event ValidateTokenEventHandler ValidateToken;
        /// 
        /// Raises ValidateToken event.
        /// 
        /// Provides event arguments.
        protected virtual void OnValidateToken(ValidateTokenEventArgs e)
        {
            ValidateTokenEventHandler handler = ValidateToken;
            if (handler != null)
                handler(this, e);
        }
        private bool _AutoSizeHeight = true;
        /// 
        /// Indicates whether control automatically increases its height as more tokens are selected. MaxHeightLines property controls the maximum number of lines control will grow to before showing scroll-bar.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether control automatically increases its height as more tokens are selected. MaxHeightLines property controls the maximum number of lines control will grow to before showing scroll-bar.")]
        public bool AutoSizeHeight
        {
            get { return _AutoSizeHeight; }
            set
            {
                if (_AutoSizeHeight != value)
                {
                    _AutoSizeHeight = value;
                    if (_AutoSizeHeight)
                        LayoutTokens();
                }
            }
        }
        private int _MaxHeightLines = 5;
        /// 
        /// Indicates maximum number of lines control will grow to when AutoSizeHeight=true. Set to 0 to indicates unlimited growth.
        /// Default value is 5.
        /// 
        [DefaultValue(5), Category("Behavior"), Description("Indicates maximum number of lines control will grow to when AutoSizeHeight=true. Set to 0 to indicates unlimited growth.")]
        public int MaxHeightLines
        {
            get { return _MaxHeightLines; }
            set { _MaxHeightLines = value; }
        }
        /// 
        /// Gets reference to internal text-box control that is used to input the token text.
        /// 
        [Browsable(false)]
        public TextBox EditTextBox
        {
            get
            {
                return _EditBox;
            }
        }
        private bool _ValidateTokenTextOnLostFocus = true;
        /// 
        /// Indicates whether any text entered into the token editor is validated and converted to token when control loses focus.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether any text entered into the token editor is validated and converted to token when control loses focus.")]
        public bool ValidateTokenTextOnLostFocus
        {
            get { return _ValidateTokenTextOnLostFocus; }
            set { _ValidateTokenTextOnLostFocus = value; }
        }
        private string _WatermarkText = "";
        private Font _WatermarkFont = null;
        private Color _WatermarkColor = SystemColors.GrayText;
        private bool _WatermarkEnabled = true;
        /// 
        /// Gets or sets whether watermark text is displayed when control is empty. Default value is true.
        /// 
        [DefaultValue(true), Description("Indicates whether watermark text is displayed when control is empty.")]
        public virtual bool WatermarkEnabled
        {
            get { return _WatermarkEnabled; }
            set { _WatermarkEnabled = value; this.Invalidate(); UpdateEditBoxWatermark(); }
        }
        private Image _WatermarkImage = null;
        /// 
        /// Gets or sets the watermark image displayed inside of the control when Text is not set and control does not have input focus.
        /// 
        [DefaultValue(null), Category("Appearance"), Description("Indicates watermark image displayed inside of the control when Text is not set and control does not have input focus.")]
        public Image WatermarkImage
        {
            get { return _WatermarkImage; }
            set { _WatermarkImage = value; this.Invalidate(); UpdateEditBoxWatermark(); }
        }
        private ContentAlignment _WatermarkImageAlignment = ContentAlignment.MiddleLeft;
        /// 
        /// Gets or sets the watermark image alignment.
        /// 
        [DefaultValue(ContentAlignment.MiddleLeft), Category("Appearance"), Description("Indicates watermark image alignment.")]
        public ContentAlignment WatermarkImageAlignment
        {
            get { return _WatermarkImageAlignment; }
            set { _WatermarkImageAlignment = value; this.Invalidate(); UpdateEditBoxWatermark(); }
        }
        /// 
        /// Gets or sets the watermark (tip) text displayed inside of the control when Text is not set and control does not have input focus. This property supports text-markup.
        /// 
        [Browsable(true), DefaultValue(""), Localizable(true), Category("Appearance"), Description("Indicates watermark text displayed inside of the control when Text is not set and control does not have input focus."), Editor("DevComponents.DotNetBar.Design.TextMarkupUIEditor, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf", typeof(System.Drawing.Design.UITypeEditor))]
        public string WatermarkText
        {
            get { return _WatermarkText; }
            set
            {
                if (value == null) value = "";
                _WatermarkText = value;
                MarkupTextChanged();
                UpdateEditBoxWatermark();
                this.Invalidate();
            }
        }
        /// 
        /// Gets or sets the watermark font.
        /// 
        [Browsable(true), Category("Appearance"), Description("Indicates watermark font."), DefaultValue(null)]
        public Font WatermarkFont
        {
            get { return _WatermarkFont; }
            set { _WatermarkFont = value; this.Invalidate(); UpdateEditBoxWatermark(); }
        }
        /// 
        /// Gets or sets the watermark text color.
        /// 
        [Browsable(true), Category("Appearance"), Description("Indicates watermark text color.")]
        public Color WatermarkColor
        {
            get { return _WatermarkColor; }
            set { _WatermarkColor = value; this.Invalidate(); UpdateEditBoxWatermark(); }
        }
        /// 
        /// Indicates whether property should be serialized by Windows Forms designer.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeWatermarkColor()
        {
            return _WatermarkColor != SystemColors.GrayText;
        }
        /// 
        /// Resets the property to default value.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetWatermarkColor()
        {
            this.WatermarkColor = SystemColors.GrayText;
        }
        protected virtual bool IsWatermarkRendered
        {
            get
            {
                return (!this.Focused || _WatermarkBehavior == eWatermarkBehavior.HideNonEmpty) && this.SelectedTokens.Count == 0;
            }
        }
        private eWatermarkBehavior _WatermarkBehavior = eWatermarkBehavior.HideOnFocus;
        /// 
        /// Gets or sets the watermark hiding behaviour. Default value indicates that watermark is hidden when control receives input focus.
        /// 
        [DefaultValue(eWatermarkBehavior.HideOnFocus), Category("Behavior"), Description("Indicates watermark hiding behaviour.")]
        public eWatermarkBehavior WatermarkBehavior
        {
            get { return _WatermarkBehavior; }
            set { _WatermarkBehavior = value; this.Invalidate();
                UpdateEditBoxWatermark();
            }
        }
        private void UpdateEditBoxWatermark()
        {
            _EditBox.WatermarkText = _WatermarkText;
            _EditBox.WatermarkColor = _WatermarkColor;
            _EditBox.WatermarkFont = _WatermarkFont;
            _EditBox.WatermarkImage = _WatermarkImage;
            _EditBox.WatermarkImageAlignment = _WatermarkImageAlignment;
            if (this.SelectedTokens.Count > 0 || !_WatermarkEnabled)
                _EditBox.WatermarkEnabled = false;
            else if (_WatermarkBehavior == eWatermarkBehavior.HideNonEmpty)
            {
                _EditBox.WatermarkEnabled = true;
                _EditBox.WatermarkBehavior = eWatermarkBehavior.HideNonEmpty;
            }
            else
            {
                _EditBox.WatermarkBehavior = eWatermarkBehavior.HideOnFocus;
            }
        }
        private TextMarkup.BodyElement _TextMarkup = null;
        private void MarkupTextChanged()
        {
            _TextMarkup = null;
            if (!TextMarkup.MarkupParser.IsMarkup(ref _WatermarkText))
                return;
            _TextMarkup = TextMarkup.MarkupParser.Parse(_WatermarkText);
            ResizeMarkup();
        }
        private MarkupDrawContext GetMarkupDrawContext(Graphics g)
        {
            return new MarkupDrawContext(g, (_WatermarkFont == null ? this.Font : _WatermarkFont), _WatermarkColor, this.RightToLeft == RightToLeft.Yes);
        }
        private void ResizeMarkup()
        {
            if (_TextMarkup != null)
            {
                using (Graphics g = this.CreateGraphics())
                {
                    MarkupDrawContext dc = GetMarkupDrawContext(g);
                    _TextMarkup.Measure(GetWatermarkBounds().Size, dc);
                    Size sz = _TextMarkup.Bounds.Size;
                    _TextMarkup.Arrange(new Rectangle(GetWatermarkBounds().Location, sz), dc);
                }
            }
        }
        private Rectangle GetWatermarkBounds()
        {
            Rectangle r = this.ClientRectangle;
            r.Inflate(-1, 0);
            r.X += 2;
            r.Width -= 2;
            return r;
        }
        private void DrawWatermark(Graphics g)
        {
            Rectangle bounds = GetWatermarkBounds();
            if (_WatermarkImage != null)
            {
                Rectangle imageBounds = new Rectangle(Point.Empty, _WatermarkImage.Size);
                if (_WatermarkImageAlignment == ContentAlignment.BottomCenter)
                    imageBounds.Location = new Point(bounds.X + (bounds.Width - imageBounds.Width) / 2, bounds.Bottom - imageBounds.Height);
                else if (_WatermarkImageAlignment == ContentAlignment.BottomLeft)
                    imageBounds.Location = new Point(bounds.X, bounds.Bottom - imageBounds.Height);
                else if (_WatermarkImageAlignment == ContentAlignment.BottomRight)
                    imageBounds.Location = new Point(bounds.Right - imageBounds.Width, bounds.Bottom - imageBounds.Height);
                else if (_WatermarkImageAlignment == ContentAlignment.MiddleCenter)
                    imageBounds.Location = new Point(bounds.X + (bounds.Width - imageBounds.Width) / 2, bounds.Y + (bounds.Height - imageBounds.Height) / 2);
                else if (_WatermarkImageAlignment == ContentAlignment.MiddleLeft)
                    imageBounds.Location = new Point(bounds.X, bounds.Y + (bounds.Height - imageBounds.Height) / 2);
                else if (_WatermarkImageAlignment == ContentAlignment.MiddleRight)
                    imageBounds.Location = new Point(bounds.Right - imageBounds.Width, bounds.Y + (bounds.Height - imageBounds.Height) / 2);
                else if (_WatermarkImageAlignment == ContentAlignment.TopCenter)
                    imageBounds.Location = new Point(bounds.X + (bounds.Width - imageBounds.Width) / 2, bounds.Y);
                else if (_WatermarkImageAlignment == ContentAlignment.TopLeft)
                    imageBounds.Location = new Point(bounds.X, bounds.Y);
                else if (_WatermarkImageAlignment == ContentAlignment.TopRight)
                    imageBounds.Location = new Point(bounds.Right - imageBounds.Width, bounds.Y);
                g.DrawImage(_WatermarkImage, imageBounds);
                if (_WatermarkImageAlignment == ContentAlignment.BottomLeft || _WatermarkImageAlignment == ContentAlignment.MiddleLeft || _WatermarkImageAlignment == ContentAlignment.TopLeft)
                {
                    bounds.X = imageBounds.Right;
                    bounds.Width = Math.Max(0, bounds.Width - imageBounds.Width);
                }
                else if (_WatermarkImageAlignment == ContentAlignment.BottomRight || _WatermarkImageAlignment == ContentAlignment.MiddleRight || _WatermarkImageAlignment == ContentAlignment.TopRight)
                {
                    bounds.Width = Math.Max(0, bounds.Width - imageBounds.Width);
                }
            }
            if (bounds.Width <= 0) return;
            if (_TextMarkup != null)
            {
                MarkupDrawContext dc = GetMarkupDrawContext(g);
                if (_TextMarkup.Bounds.Height < bounds.Height)
                    _TextMarkup.Bounds = new Rectangle(bounds.X, bounds.Y + (bounds.Height - _TextMarkup.Bounds.Height) / 2, _TextMarkup.Bounds.Width, _TextMarkup.Bounds.Height);
                _TextMarkup.Render(dc);
            }
            else
            {
                eTextFormat tf = eTextFormat.Left | eTextFormat.VerticalCenter;
                if (this.RightToLeft == RightToLeft.Yes) tf |= eTextFormat.RightToLeft;
                tf |= eTextFormat.EndEllipsis;
                tf |= eTextFormat.WordBreak;
                TextDrawing.DrawString(g, _WatermarkText, (_WatermarkFont == null ? this.Font : _WatermarkFont),
                    _WatermarkColor, bounds, tf);
            }
        }
        protected override void OnTextChanged(EventArgs e)
        {
            if (!_UpdatingText)
            {
                this.SelectedTokens.Clear();
                if (!string.IsNullOrEmpty(this.Text))
                {
                    if (!string.IsNullOrEmpty(_TextSeparator))
                    {
                        string[] tokens = this.Text.Split(new string[] { _TextSeparator }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string item in tokens)
                        {
                            bool isNew = false;
                            SelectToken(FindOrCreateToken(this.Text, out isNew));
                        }
                    }
                    else
                    {
                        bool isNew = false;
                        SelectToken(FindOrCreateToken(this.Text, out isNew));
                    }
                }
            }
            base.OnTextChanged(e);
        }
        private bool _UpdatingText = false;
        private void UpdateText()
        {
            _UpdatingText = true;
            string text = "";
            for (int i = 0; i < _SelectedTokens.Count; i++)
            {
                text += GetTokenText(_SelectedTokens[i]);
                if (i < _SelectedTokens.Count - 1)
                    text += _TextSeparator;
            }
            this.Text = text;
            _UpdatingText = false;
        }
        private string _TextSeparator = ",";
        /// 
        /// Indicates the character separator that is used to separate tokens when controls Text property is updated or parsed.
        /// 
        [DefaultValue(","), Category("Behavior"), Description("Indicates the character separator that is used to separate tokens when controls Text property is updated or parsed.")]
        public string TextSeparator
        {
            get { return _TextSeparator; }
            set
            {
                if (value != _TextSeparator)
                {
                    string oldValue = _TextSeparator;
                    _TextSeparator = value;
                    OnTextSeparatorChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when TextSeparator property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnTextSeparatorChanged(string oldValue, string newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("TextSeparator"));
            UpdateText();
        }
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }
        private bool _DropDownButtonVisible = false;
        /// 
        /// Indicates whether drop-down button which shows available token popup is displayed
        /// 
        [DefaultValue(false), Category("Appearance"), Description("Indicates whether drop-down button which shows available token popup is displayed")]
        public bool DropDownButtonVisible
        {
            get { return _DropDownButtonVisible; }
            set
            {
                if (value != _DropDownButtonVisible)
                {
                    bool oldValue = _DropDownButtonVisible;
                    _DropDownButtonVisible = value;
                    OnDropDownButtonVisibleChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when DropDownButtonVisible property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnDropDownButtonVisibleChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("DropDownButtonVisible"));
            UpdateButtons();
            LayoutTokens();
            Invalidate();
        }
        private bool _CheckBoxesVisible = false;
        /// 
        /// Indicates whether check-boxes are displayed on popup token selection list and used for token selection.
        /// 
        [DefaultValue(false), Category("Behavior"), Description("Indicates whether check-boxes are displayed on popup token selection list and used for token selection.")]
        public bool CheckBoxesVisible
        {
            get { return _CheckBoxesVisible; }
            set
            {
                if (value != _CheckBoxesVisible)
                {
                    bool oldValue = _CheckBoxesVisible;
                    _CheckBoxesVisible = value;
                    OnCheckBoxesVisibleChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when CheckBoxesVisible property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnCheckBoxesVisibleChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("CheckBoxesVisible"));
        }
        private VisualGroup _ButtonGroup = null;
        private VisualDropDownButton _DropDownButton = null;
        private VisualUpDownButton _ScrollButton = null;
        private int GetButtonHeight()
        {
            return GetSingleLineTextBoxHeight() - 4;
        }
        private void UpdateButtons()
        {
            if (!_DropDownButtonVisible && !_ScrollButton.Visible)
                _ButtonGroup.Visible = false;
            else
            {
                _ButtonGroup.Visible = true;
                _DropDownButton.Height = GetButtonHeight();
            }
            _DropDownButton.Visible = _DropDownButtonVisible;
            _ButtonGroup.InvalidateArrange();
        }
        protected virtual void CreateButtons()
        {
            _DropDownButton = new VisualDropDownButton();
            _DropDownButton.MouseClick += DropDownButtonClick;
            _DropDownButton.Visible = false;
            _ButtonGroup.Items.Add(_DropDownButton);
            _ScrollButton = new VisualUpDownButton();
            _ScrollButton.UpClick += ScrollButtonUpClick;
            _ScrollButton.DownClick += ScrollButtonDownClick;
            _ScrollButton.Visible = false;
            _ButtonGroup.Items.Add(_ScrollButton);
        }
        void ScrollButtonDownClick(object sender, EventArgs e)
        {
            if (Math.Abs(_AutoScrollPosition.Y) < (_VScrollBar.Maximum - _VScrollBar.LargeChange - 1))
                AutoScrollPosition = new Point(_AutoScrollPosition.X, _AutoScrollPosition.Y - _VScrollBar.SmallChange);
        }
        void ScrollButtonUpClick(object sender, EventArgs e)
        {
            if (_AutoScrollPosition.Y < 0)
                AutoScrollPosition = new Point(_AutoScrollPosition.X, Math.Min(0, _AutoScrollPosition.Y + _VScrollBar.SmallChange));
        }
        void DropDownButtonClick(object sender, MouseEventArgs e)
        {
            IsPopupOpen = !IsPopupOpen;
        }
        private void ButtonGroupRenderInvalid(object sender, EventArgs e)
        {
            Invalidate();
        }
        private void ButtonGroupArrangeInvalid(object sender, EventArgs e)
        {
            Invalidate();
        }
        private void ButtonGroupResetMouseHover(object sender, EventArgs e)
        {
            DevComponents.AdvTree.Interop.WinApi.ResetHover(this);
        }
        private void PaintButtons(Graphics g)
        {
            PaintInfo p = CreatePaintInfo(g);
            if (!_ButtonGroup.IsLayoutValid)
            {
                _ButtonGroup.PerformLayout(p);
            }
            bool disposeStyle = false;
            ElementStyle style = ElementStyleDisplay.GetElementStyle(_BackgroundStyle, out disposeStyle);
            _ButtonGroup.RenderBounds = new Rectangle(this.Width - (ElementStyleLayout.RightWhiteSpace(style, eSpacePart.Border) + 1) - _ButtonGroup.Size.Width, ElementStyleLayout.TopWhiteSpace(style, eSpacePart.Border) + 1,
                _ButtonGroup.Size.Width, _ButtonGroup.Size.Height);
            _ButtonGroup.ProcessPaint(p);
            if (disposeStyle) style.Dispose();
        }
        private PaintInfo CreatePaintInfo(Graphics g)
        {
            PaintInfo p = new PaintInfo();
            p.Graphics = g;
            p.DefaultFont = this.Font;
            p.ForeColor = this.ForeColor;
            p.RenderOffset = new System.Drawing.Point();
            Size s = this.Size;
            bool disposeStyle = false;
            ElementStyle style = ElementStyleDisplay.GetElementStyle(_BackgroundStyle, out disposeStyle);
            s.Height -= (ElementStyleLayout.TopWhiteSpace(style, eSpacePart.Border) + ElementStyleLayout.BottomWhiteSpace(style, eSpacePart.Border)) + 2;
            s.Width -= (ElementStyleLayout.LeftWhiteSpace(style, eSpacePart.Border) + ElementStyleLayout.RightWhiteSpace(style, eSpacePart.Border)) + 2;
            p.AvailableSize = s;
            p.ParentEnabled = this.Enabled;
            p.MouseOver = _IsMouseOver || this.Focused;
            if (disposeStyle) style.Dispose();
            return p;
        }
        #endregion
        #region Tooltip Support
        private DevComponents.DotNetBar.ToolTip _ToolTipWnd = null;
        /// 
        /// Shows tooltip for this item.
        /// 
        public virtual void ShowToolTip(EditToken token)
        {
            if (this.DesignMode || token==null || !token.IsSelected)
                return;
            if (this.Visible && this.ShowToolTips )
            {
                string tooltip = token.Tooltip;
                if (!string.IsNullOrEmpty(tooltip))
                {
                    if (_ToolTipWnd == null)
                        _ToolTipWnd = new DevComponents.DotNetBar.ToolTip();
                    _ToolTipWnd.Style = StyleManager.GetEffectiveStyle();
                    _ToolTipWnd.Text = tooltip;
                    _ToolTipWnd.ReferenceRectangle = new Rectangle(PointToScreen(token.Bounds.Location), token.Bounds.Size);
                    OnToolTipVisibleChanged(new EventArgs());
                    _ToolTipWnd.ShowToolTip();
                }
            }
        }
        /// 
        /// Destroys tooltip window.
        /// 
        internal protected void HideToolTip()
        {
            if (_ToolTipWnd != null)
            {
                System.Drawing.Rectangle tipRect = _ToolTipWnd.Bounds;
                tipRect.Width += 5;
                tipRect.Height += 6;
                OnToolTipVisibleChanged(new EventArgs());
                try
                {
                    if (_ToolTipWnd != null)
                    {
                        _ToolTipWnd.Hide();
                        _ToolTipWnd.Dispose();
                        _ToolTipWnd = null;
                    }
                }
                catch { }
                this.Invalidate();
            }
        }
        /// 
        /// Occurs when item's tooltip visibility has changed.
        /// 
        [System.ComponentModel.Description("Occurs when item's tooltip visibility has changed.")]
        public event EventHandler ToolTipVisibleChanged;
        private void OnToolTipVisibleChanged(EventArgs eventArgs)
        {
            EventHandler h = ToolTipVisibleChanged;
            if (h != null)
                ToolTipVisibleChanged(this, eventArgs);
        }
        private bool _ShowToolTips = true;
        /// 
        /// Gets or sets whether tooltips are shown when mouse is over the selected token when Tooltip property is set.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether tooltips are shown when mouse is over the cell when Tooltip property is set.")]
        public bool ShowToolTips
        {
            get { return _ShowToolTips; }
            set
            {
                _ShowToolTips = value;
            }
        }
        
        #endregion
        #region IMessageHandlerClient
        private bool _MessageHandlerInstalled = false;
        bool IMessageHandlerClient.OnSysKeyDown(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            return false;
        }
        bool IMessageHandlerClient.OnSysKeyUp(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            return false;
        }
        bool IMessageHandlerClient.OnKeyDown(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            return false;
        }
        bool IMessageHandlerClient.OnMouseDown(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            if (IsPopupOpen && _PopupController != null)
            {
                if (!_PopupController.Bounds.Contains(Control.MousePosition))
                {
                    IsPopupOpen = false;
                }
            }
            return false;
        }
        bool IMessageHandlerClient.OnMouseMove(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            return false;
        }
        bool IMessageHandlerClient.OnMouseWheel(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
        {
            return false;
        }
        bool IMessageHandlerClient.IsModal
        {
            get { return false; }
        }
        #endregion
    }
    /// 
    /// Delegate for the ValidateTokenEvent event.
    /// 
    public delegate void ValidateTokenEventHandler(object sender, ValidateTokenEventArgs ea);
    /// 
    /// Arguments for the ValidateTokenEvent event.
    /// 
    public class ValidateTokenEventArgs : EventArgs
    {
        /// 
        /// Indicates whether validated token is valid. Default value is true. When you set this property to false the token being validated will be discared.
        /// 
        public bool IsValid = true;
        /// 
        /// Indicates the Token that will be accepted by the control if IsValid=true.
        /// 
        public EditToken Token = null;
        /// 
        /// Indicates whether token is newly created. When false it means that token was taken from Tokens collection.
        /// 
        public readonly bool IsNewToken;
        /// 
        /// Initializes a new instance of the ValidateTokenEventArgs class.
        /// 
        /// 
        public ValidateTokenEventArgs(EditToken token, bool isNewToken)
        {
            Token = token;
            IsNewToken = isNewToken;
        }
    }
    /// 
    /// Delegate for RemovingToken event.
    /// 
    public delegate void RemovingTokenEventHandler(object sender, RemovingTokenEventArgs ea);
    /// 
    /// Defines event arguments for RemovingToken event.
    /// 
    public class RemovingTokenEventArgs : EventArgs
    {
        /// 
        /// Indicates the Token that will be removed.
        /// 
        public readonly EditToken Token;
        /// 
        /// Set to true to cancel removal of the token.
        /// 
        public bool Cancel = false;
        /// 
        /// Indicates the source of the event.
        /// 
        public readonly eEventSource EventSource;
        /// 
        /// Initializes a new instance of the RemovingTokenEventArgs class.
        /// 
        /// 
        public RemovingTokenEventArgs(EditToken token, eEventSource eventSource)
        {
            Token = token;
            EventSource = eventSource;
        }
    }
    /// 
    /// Specifies the filter behavior on token editor popup list.
    /// 
    public enum eTokenFilterBehavior
    {
        /// 
        /// Token text is searched for the match.
        /// 
        Text,
        /// 
        /// Token value is searched for the match.
        /// 
        Value,
        /// 
        /// Both token text and value are searched for the match.
        /// 
        TextAndValue
    }
    /// 
    /// Delegate for TokenEditor.BeforePopupOpen event.
    /// 
    public delegate void TokenEditorPopupEventHandler(object sender, TokenEditorPopupEventArgs ea);
    /// 
    /// Defines event arguments for BeforePopupOpen event.
    /// 
    public class TokenEditorPopupEventArgs : EventArgs
    {
        /// 
        /// Gets or sets the screen location of the popup in relation to the TokenEditor control.
        /// 
        public Point PopupLocation = Point.Empty;
        /// 
        /// Gets the suggested popup size.
        /// 
        public readonly Size PopupSize;
        /// 
        /// Initializes a new instance of the TokenEditorPopupEventArgs class.
        /// 
        /// 
        public TokenEditorPopupEventArgs(Point popupLocation, Size popupSize)
        {
            PopupLocation = popupLocation;
            PopupSize = popupSize;
        }
    }
}