using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
    [ToolboxItem(false)]
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public class HScrollBarLite : ScrollBarLite
    {
        public HScrollBarLite()
        {
            Orientation = Orientation.Horizontal;
        }
    }
    [ToolboxItem(false)]
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public class VScrollBarLite : ScrollBarLite
    {
        public VScrollBarLite()
        {
            Orientation = Orientation.Vertical;
        }
    }
    [ToolboxItem(false)]
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public class ScrollBarLite : ChartVisualElement
    {
        #region Events
        #region Scroll
        /// 
        /// Occurs when the Horizontal or Vertical scrollbar has been scrolled
        /// 
        [Description("Occurs when the Horizontal or Vertical scrollbar has been scrolled.")]
        public event EventHandler Scroll;
        #endregion
        #region ValueChanged
        /// 
        /// Occurs when the Value property is changed.
        /// 
        public event EventHandler ValueChanged;
        #endregion
        #endregion
        #region Private Variables
        private Orientation _Orientation = Orientation.Horizontal;
        private int _LargeChange = 10;
        private int _Maximum = 100;
        private int _Minimum;
        private int _SmallChange = 1;
        private int _Value;
        private bool _Enabled = true;
        private Rectangle _ArrowIncreaseBounds;
        private Rectangle _ArrowDecreaseBounds;
        private Rectangle _ThumbBounds;
        private Size _MinArrowSize = new Size(5, 7);
        private Size _MaxArrowSize = new Size(50, 50);
        private Size _MinThumbSize = new Size(10, 12);
        private ScrollBarVisualStyles _ScrollBarVisualStyles;
        private EffectiveStyles _EffectiveStyles;
        private ItemHitArea _HitArea;
        private ItemHitArea _LastHitArea;
        private ItemHitArea _MouseDownHitArea;
        private int _ThumbOffset;
        private Timer _ClickTimer;
        private int _ClickCount;
        private bool _RaiseEndScroll;
        private bool _Inverted;
        #endregion
        #region Constructor
        public ScrollBarLite()
        {
            Size = new Size(10, 10);
            _EffectiveStyles = new EffectiveStyles(this);
        }
        #endregion
        #region Public properties
        #region Enabled
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Enabled
        {
            get { return (_Enabled); }
            internal set
            {
                if (value != _Enabled)
                {
                    _Enabled = value;
                    InvalidateRender();
                }
            }
        }
        #endregion
        #region Orientation
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Orientation Orientation
        {
            get { return (_Orientation); }
            internal set
            {
                if (value != _Orientation)
                {
                    _Orientation = value;
                    InvalidateLayout();
                }
            }
        }
        #endregion
        #region ScrollBarVisualStyles
        /// 
        /// Gets or sets the visual styles for the ScrollBar.
        /// 
        [Category("Style")]
        [Description("Indicates the visual styles for the ScrollBar.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ScrollBarVisualStyles ScrollBarVisualStyles
        {
            get
            {
                if (_ScrollBarVisualStyles == null)
                {
                    _ScrollBarVisualStyles = new ScrollBarVisualStyles();
                    StyleVisualChangeHandler(null, _ScrollBarVisualStyles);
                }
                return (_ScrollBarVisualStyles);
            }
            set
            {
                if (_ScrollBarVisualStyles != value)
                {
                    ScrollBarVisualStyles oldValue = _ScrollBarVisualStyles;
                    _ScrollBarVisualStyles = value;
                    OnStyleChanged("ScrollBarVisualStyles", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #region Value
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int Value
        {
            get { return (_Value); }
            set
            {
                if (value < Minimum)
                    throw new ArgumentOutOfRangeException("Value must be >= to Minimum property value.");
                if (value > Maximum)
                    throw new ArgumentOutOfRangeException("Value must be <= to Maximum property value.");
                value = NormalizeValue(value);
                if (value != _Value)
                {
                    int oldValue = _Value;
                    _Value = value;
                    OnValueChanged(oldValue, value);
                    InvalidateLayoutBounds(this);
                }
            }
        }
        #region OnValueChanged
        private void OnValueChanged(int oldValue, int newValue)
        {
            if (ValueChanged != null)
            {
                ValueChangedEventArgs args
                    = new ValueChangedEventArgs(oldValue, newValue);
                ValueChanged(this, args);
            }
        }
        #endregion
        #endregion
        #region Visible
        /// 
        /// Get or sets whether the item is visible
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool Visible
        {
            get { return (base.Visible); }
            set { base.Visible = value; }
        }
        #endregion
        #endregion
        #region Internal properties
        #region Height
        internal int Height
        {
            get { return (BoundsRelative.Height); }
            set
            {
                if (value != BoundsRelative.Height)
                {
                    Rectangle r = BoundsRelative;
                    _ThumbOffset -= (value - r.Height);
                    r.Height = value;
                    BoundsRelative = r;
                }
            }
        }
        #endregion
        #region Inverted
        internal bool Inverted
        {
            get { return (_Inverted); }
            set { _Inverted = value; }
        }
        #endregion
        #region IsAtMaxumum
        internal bool IsAtMaxumum
        {
            get { return (_Value + _LargeChange >= _Maximum); }
        }
        #endregion
        #region IsAtMinumum
        internal bool IsAtMinumum
        {
            get { return (_Value == _Minimum); }
        }
        #endregion
        #region IsVertical
        internal bool IsVertical
        {
            get { return (Orientation == Orientation.Vertical); }
        }
        #endregion
        #region LargeChange
        internal int LargeChange
        {
            get { return (_LargeChange); }
            set
            {
                if (value != _LargeChange)
                {
                    if (value < 0)
                        throw new ArgumentOutOfRangeException();
                    _LargeChange = value;
                    InvalidateRender();
                }
            }
        }
        #endregion
        #region Location
        internal Point Location
        {
            get { return (BoundsRelative.Location); }
            set
            {
                Rectangle r = BoundsRelative;
                r.Location = value;
                BoundsRelative = r;
            }
        }
        #endregion
        #region Maximum
        internal int Maximum
        {
            get { return (_Maximum); }
            set
            {
                if (value != _Maximum)
                {
                    _Maximum = value;
                    InvalidateRender();
                }
            }
        }
        #endregion
        #region Minimum
        internal int Minimum
        {
            get { return (_Minimum); }
            set
            {
                if (value != _Minimum)
                {
                    _Minimum = value;
                    InvalidateRender();
                }
            }
        }
        #endregion
        #region SmallChange
        internal int SmallChange
        {
            get { return (_SmallChange); }
            set
            {
                if (value != _SmallChange)
                {
                    if (value < 0)
                        throw new ArgumentOutOfRangeException();
                    _SmallChange = value;
                    InvalidateRender();
                }
            }
        }
        #endregion
        #region Width
        internal int Width
        {
            get { return (BoundsRelative.Width); }
            set
            {
                if (value != BoundsRelative.Width)
                {
                    Rectangle r = BoundsRelative;
                    _ThumbOffset -= (value - r.Width);
                    r.Width = value;
                    BoundsRelative = r;
                }
            }
        }
        #endregion
        #endregion
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
        }
        #endregion
        #region ArrangeOverride
        protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
        {
            UpdateBarBounds();
        }
        #region UpdateBarBounds
        private void UpdateBarBounds()
        {
            Rectangle bounds = Bounds;
            _ThumbBounds = Rectangle.Empty;
            if (Orientation == Orientation.Horizontal)
            {
                int arrowWidth = Height;
                arrowWidth = Math.Max(arrowWidth, _MinArrowSize.Width);
                arrowWidth = Math.Min(arrowWidth, _MaxArrowSize.Width);
                _ArrowDecreaseBounds = bounds;
                _ArrowDecreaseBounds.Width = arrowWidth;
                _ArrowIncreaseBounds = bounds;
                _ArrowIncreaseBounds.X = _ArrowIncreaseBounds.Right - arrowWidth;
                _ArrowIncreaseBounds.Width = arrowWidth;
                if (bounds.Width > (_ArrowDecreaseBounds.Width +
                    _ArrowIncreaseBounds.Width + _MinThumbSize.Width))
                {
                    int tv = Maximum - Minimum;
                    int width = Width - (2 * arrowWidth);
                    int x = (width * Value) / tv;
                    _ThumbBounds = bounds;
                    _ThumbBounds.X += (x + arrowWidth);
                    _ThumbBounds.Width = GetThumbSize();
                    _ThumbBounds.Y += 1;
                    _ThumbBounds.Height -= 2;
                }
            }
            else
            {
                int arrowHeight = Width;
                arrowHeight = Math.Max(arrowHeight, _MinArrowSize.Height);
                arrowHeight = Math.Min(arrowHeight, _MaxArrowSize.Height);
                _ArrowDecreaseBounds = bounds;
                _ArrowDecreaseBounds.Height = arrowHeight;
                _ArrowIncreaseBounds = bounds;
                _ArrowIncreaseBounds.Y = bounds.Bottom - arrowHeight;
                _ArrowIncreaseBounds.Height = arrowHeight;
                if (bounds.Height > (_ArrowDecreaseBounds.Height +
                    _ArrowIncreaseBounds.Height + _MinThumbSize.Height))
                {
                    int tv = Maximum - Minimum;
                    int height = Height - (2 * arrowHeight);
                    int y = (height * Value) / tv;
                    _ThumbBounds = bounds;
                    _ThumbBounds.Height = GetThumbSize();
                    if (Inverted == true)
                        _ThumbBounds.Y = (bounds.Bottom - _ThumbBounds.Height) - (y + arrowHeight);
                    else
                        _ThumbBounds.Y += (y + arrowHeight);
                    _ThumbBounds.X += 1;
                    _ThumbBounds.Width -= 2;
                }
            }
        }
        #region GetThumbSize
        private int GetThumbSize()
        {
            int size = GetAvailableTrackArea();
            int i = (int)(size * ((float)LargeChange / (float)(Maximum - Minimum))) + 1;
            if (Orientation == Orientation.Horizontal)
                i = Math.Max(_MinThumbSize.Width, i);
            else
                i = Math.Max(_MinThumbSize.Height, i);
            i = Math.Min(i, size);
            return i;
        }
        #endregion
        #region GetAvailableTrackArea
        private int GetAvailableTrackArea()
        {
            Rectangle r = BoundsRelative;
            int size;
            if (Orientation == Orientation.Horizontal)
                size = r.Width - (_ArrowDecreaseBounds.Width + _ArrowIncreaseBounds.Width);
            else
                size = r.Height - (_ArrowDecreaseBounds.Height + _ArrowIncreaseBounds.Height);
            return Math.Max(size, 8);
        }
        #endregion
        #endregion
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            Graphics g = renderInfo.Graphics;
            if (CanDrawScrollBar())
            {
                Rectangle bounds = Bounds;
                RenderBackground(g, bounds);
                RenderArrowDecrease(g, bounds);
                RenderArrowIncrease(g, bounds);
                RenderThumb(g, bounds);
                RenderBorder(g, bounds);
            }
        }
        #region CanDrawScrollBar
        private bool CanDrawScrollBar()
        {
            Rectangle bounds = Bounds;
            if (Orientation == Orientation.Horizontal)
            {
                if (bounds.Height < _MinArrowSize.Height)
                    return (false);
                int widthNeeded = (_ArrowIncreaseBounds.Width + _ArrowDecreaseBounds.Width);
                return (bounds.Width >= widthNeeded);
            }
            else
            {
                if (bounds.Width < _MinArrowSize.Width)
                    return (false);
                int heightNeeded = (_ArrowIncreaseBounds.Height + _ArrowDecreaseBounds.Height);
                return (bounds.Height >= heightNeeded);
            }
        }
        #endregion
        #region RenderBackground
        private void RenderBackground(Graphics g, Rectangle bounds)
        {
            ScrollBarVisualStyle style = GetEffectiveStyle();
            bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
            using (Brush br = style.TrackBackground.GetBrush(bounds, noAlpha))
                g.FillRectangle(br, bounds);
        }
        #endregion
        #region RenderArrowDecrease
        private void RenderArrowDecrease(Graphics g, Rectangle bounds)
        {
            ScrollBarVisualStyle style = GetAreaStyle(Inverted == true ? ItemHitArea.ArrowIncrease : ItemHitArea.ArrowDecrease);
            Rectangle r = _ArrowDecreaseBounds;
            bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
            using (Brush br = style.ArrowBackground.GetBrush(r, noAlpha))
                g.FillRectangle(br, r);
            if (style.ArrowColor.IsEmpty == false)
            {
                Color color = style.GetColor(style.ArrowColor, noAlpha);
                using (Pen pen = new Pen(color))
                {
                    int n = Math.Min(r.Width, r.Height) / 4 + 1;
                    if (Orientation == Orientation.Horizontal)
                    {
                        int x = r.X + (n * 5 / 4);
                        int y = r.Y + (r.Height / 2);
                        for (int i = 0; i < n; i++)
                        {
                            g.DrawLine(pen, x + i, y - i, x + i + 1, y - i);
                            g.DrawLine(pen, x + i, y + i, x + i + 1, y + i);
                        }
                    }
                    else
                    {
                        int x = r.X + (r.Width / 2);
                        int y = r.Y + (n * 5 / 4);
                        for (int i = 0; i < n; i++)
                        {
                            g.DrawLine(pen, x - i, y + i, x - i, y + i + 1);
                            g.DrawLine(pen, x + i, y + i, x + i, y + i + 1);
                        }
                    }
                }
            }
            if (style.ArrowBorderColor.IsEmpty == false)
            {
                Color color = style.GetColor(style.ArrowBorderColor, noAlpha);
                using (Pen pen = new Pen(color))
                    g.DrawRectangle(pen, r);
            }
        }
        #endregion
        #region RenderArrowIncrease
        private void RenderArrowIncrease(Graphics g, Rectangle bounds)
        {
            ScrollBarVisualStyle style = GetAreaStyle(Inverted == true ? ItemHitArea.ArrowDecrease : ItemHitArea.ArrowIncrease);
            Rectangle r = _ArrowIncreaseBounds;
            bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
            using (Brush br = style.ArrowBackground.GetBrush(r, noAlpha))
                g.FillRectangle(br, r);
            if (style.ArrowColor.IsEmpty == false)
            {
                Color color = style.GetColor(style.ArrowColor, noAlpha);
                using (Pen pen = new Pen(color))
                {
                    int n = Math.Min(r.Width, r.Height) / 4 + 1;
                    if (Orientation == Orientation.Horizontal)
                    {
                        int x = r.Right - (n * 5 / 4);
                        int y = r.Y + (r.Height / 2);
                        for (int i = 0; i < n; i++)
                        {
                            g.DrawLine(pen, x - i, y - i, x - i - 1, y - i);
                            g.DrawLine(pen, x - i, y + i, x - i - 1, y + i);
                        }
                    }
                    else
                    {
                        int x = r.X + (r.Width / 2);
                        int y = r.Bottom - (n * 5 / 4);
                        for (int i = 0; i < n; i++)
                        {
                            g.DrawLine(pen, x - i, y - i, x - i, y - i - 1);
                            g.DrawLine(pen, x + i, y - i, x + i, y - i - 1);
                        }
                    }
                }
            }
            if (style.ArrowBorderColor.IsEmpty == false)
            {
                Color color = style.GetColor(style.ArrowBorderColor, noAlpha);
                using (Pen pen = new Pen(color))
                    g.DrawRectangle(pen, r);
            }
        }
        #endregion
        #region RenderThumb
        private void RenderThumb(Graphics g, Rectangle bounds)
        {
            if (_ThumbBounds.IsEmpty == false)
            {
                ScrollBarVisualStyle style = GetAreaStyle(ItemHitArea.Thumb);
                bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
                using (Brush br = style.ThumbBackground.GetBrush(_ThumbBounds, noAlpha))
                    g.FillRectangle(br, _ThumbBounds);
                if (style.ThumbColor.IsEmpty == false)
                {
                    Color color = style.GetColor(style.ThumbColor, noAlpha);
                    if (Orientation == Orientation.Horizontal)
                        RenderHThumbHashMarks(g, bounds, color);
                    else
                        RenderVThumbHashMarks(g, bounds, color);
                }
                if (style.ThumbBorderColor.IsEmpty == false)
                {
                    Color color = style.GetColor(style.ThumbBorderColor, noAlpha);
                    using (Pen pen = new Pen(color))
                        g.DrawRectangle(pen, _ThumbBounds);
                }
            }
        }
        #region RenderHThumbHashMarks
        private void RenderHThumbHashMarks(
            Graphics g, Rectangle bounds, Color color)
        {
            Rectangle r = _ThumbBounds;
            if (_ThumbBounds.Width > 20)
            {
                int n = r.Height / 6 + 1;
                int m = r.Height / 10 + 1;
                r.X += (r.Width / 2 - 1 - m);
                r.Y += n;
                r.Width = m * 2 + 3;
                r.Height -= (n * 2);
                Point pt1 = new Point(r.X, r.Y);
                Point pt2 = new Point(r.X, r.Bottom);
                using (Pen pen = new Pen(color))
                {
                    for (int i = 0; i < 3; i++)
                    {
                        g.DrawLine(pen, pt1, pt2);
                        pt1.X += (m + 1);
                        pt2.X += (m + 1);
                    }
                }
            }
        }
        #endregion
        #region RenderVThumbHashMarks
        private void RenderVThumbHashMarks(
            Graphics g, Rectangle bounds, Color color)
        {
            Rectangle r = _ThumbBounds;
            if (_ThumbBounds.Height > 20)
            {
                int n = r.Width / 6 + 1;
                int m = r.Width / 10 + 1;
                r.Y += (r.Height / 2 - 1 - m);
                r.X += n;
                r.Height = m * 2 + 3;
                r.Width -= (n * 2);
                Point pt1 = new Point(r.Left, r.Y);
                Point pt2 = new Point(r.Right, r.Y);
                using (Pen pen = new Pen(color))
                {
                    for (int i = 0; i < 3; i++)
                    {
                        g.DrawLine(pen, pt1, pt2);
                        pt1.Y += (m + 1);
                        pt2.Y += (m + 1);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region RenderBorder
        private void RenderBorder(Graphics g, Rectangle bounds)
        {
            ScrollBarVisualStyle style = GetEffectiveStyle();
            if (style.BorderColor.IsEmpty == false)
            {
                bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
                Color color = style.GetColor(style.BorderColor, noAlpha);
                using (Pen pen = new Pen(color))
                    g.DrawRectangle(pen, bounds);
            }
        }
        #endregion
        #region GetAreaStyle
        private ScrollBarVisualStyle GetAreaStyle(ItemHitArea scrollBarArea)
        {
            StyleState state = StyleState.Default;
            if (_HitArea == scrollBarArea)
                state |= StyleState.MouseOver;
            if (_MouseDownHitArea == scrollBarArea)
                state |= StyleState.Selected;
            return (GetEffectiveStyle(state));
        }
        #endregion
        #endregion
        #region Mouse handling
        #region OnMouseEnter
        protected override bool OnMouseEnter(EventArgs e)
        {
            ChartCursor = Cursors.Default;
            InvalidateRender();
            return (true);
        }
        #endregion
        #region OnMouseLeave
        protected override bool OnMouseLeave(EventArgs e)
        {
            _HitArea = ItemHitArea.None;
            InvalidateRender();
            return (true);
        }
        #endregion
        #region OnMouseMove
        /// 
        /// InternalMouseMove
        /// 
        /// 
        protected override bool OnMouseMove(MouseEventArgs e)
        {
            _HitArea = GetHitArea(e.Location);
            if (_HitArea != _LastHitArea)
            {
                _LastHitArea = _HitArea;
                InvalidateRender();
            }
            if (IsMouseDown == false)
                _MouseDownHitArea = ItemHitArea.None;
            if (_MouseDownHitArea == ItemHitArea.Thumb)
                ProcessThumbMove(e);
            ChartCursor = Cursors.Default;
            return (true);
        }
        #region ProcessThumbMove
        private void ProcessThumbMove(MouseEventArgs e)
        {
            int track;
            int tc;
            int tv = Maximum - Minimum - _LargeChange;
            if (Orientation == Orientation.Horizontal)
            {
                track = e.Location.X - _ThumbOffset;
                track -= _ArrowDecreaseBounds.Right;
                tc = Width - (_ArrowDecreaseBounds.Width + _ArrowIncreaseBounds.Width + _ThumbBounds.Width);
            }
            else
            {
                track = e.Location.Y - _ThumbOffset;
                track -= _ArrowDecreaseBounds.Bottom;
                tc = Height - (_ArrowDecreaseBounds.Height + _ArrowIncreaseBounds.Height + _ThumbBounds.Height);
            }
            if (tc > 0)
            {
                int value = (tv * track) / tc;
                if (Inverted == true)
                    value = tv - value;
                SetScrollValue(value, ScrollEventType.ThumbPosition);
            }
        }
        #endregion
        #endregion
        #region OnMouseDown
        protected override bool OnMouseDown(MouseEventArgs e)
        {
            _MouseDownHitArea = _HitArea;
            if (_HitArea != ItemHitArea.None)
            {
                ChartControl.CapturedItem = this;
                switch (_HitArea)
                {
                    case ItemHitArea.Thumb:
                        if (Orientation == Orientation.Horizontal)
                            _ThumbOffset = MouseDownPoint.X - _ThumbBounds.X;
                        else
                            _ThumbOffset = MouseDownPoint.Y - _ThumbBounds.Y;
                        break;
                    case ItemHitArea.TrackDecrease:
                        SetScrollValue(Value - _LargeChange, ScrollEventType.LargeDecrement);
                        break;
                    case ItemHitArea.TrackIncrease:
                        SetScrollValue(Value + _LargeChange, ScrollEventType.LargeIncrement);
                        break;
                    case ItemHitArea.ArrowDecrease:
                        SetScrollValue(Value - _SmallChange, ScrollEventType.SmallDecrement);
                        break;
                    case ItemHitArea.ArrowIncrease:
                        SetScrollValue(Value + _SmallChange, ScrollEventType.SmallIncrement);
                        break;
                }
                if (_HitArea != ItemHitArea.Thumb)
                    SetupClickTimer();
            }
            InvalidateRender();
            return (true);
        }
        #endregion
        #region OnMouseUp
        protected override bool OnMouseUp(MouseEventArgs e)
        {
            ChartControl.CapturedItem = null;
            if (_MouseDownHitArea != ItemHitArea.None)
            {
                if (_RaiseEndScroll == true)
                {
                    OnScroll(ScrollEventType.EndScroll, Value, Value);
                    _RaiseEndScroll = false;
                }
            }
            DisposeTimer();
            _MouseDownHitArea = ItemHitArea.None;
            InvalidateRender();
            return (true);
        }
        #endregion
        #endregion
        #region NormalizeValue
        private int NormalizeValue(int value)
        {
            value = Math.Max(Minimum, value);
            if (value + _LargeChange > _Maximum)
                value = _Maximum - _LargeChange;
            return (value);
        }
        #endregion
        #region Timer support
        #region SetupClickTimer
        private void SetupClickTimer()
        {
            if (_ClickTimer == null)
            {
                _ClickCount = 0;
                _ClickTimer = new Timer();
                _ClickTimer.Interval = 100;
                _ClickTimer.Tick += new EventHandler(ClickTimerTick);
                _ClickTimer.Enabled = true;
            }
        }
        #endregion
        #region DisposeTimer
        private void DisposeTimer()
        {
            Timer clickTimer = _ClickTimer;
            if (clickTimer != null)
            {
                _ClickTimer = null;
                clickTimer.Enabled = false;
                clickTimer.Tick -= new EventHandler(ClickTimerTick);
                clickTimer.Dispose();
            }
        }
        #endregion
        #region ClickTimerTick
        private void ClickTimerTick(object sender, EventArgs e)
        {
            if (IsMouseDown == true)
            {
                if (_MouseDownHitArea == ItemHitArea.TrackDecrease || _MouseDownHitArea == ItemHitArea.TrackIncrease)
                {
                    Point pt = ChartControl.PointToClient(Control.MousePosition);
                    if (_ThumbBounds.Contains(pt))
                    {
                        DisposeTimer();
                    }
                    else
                    {
                        if (_MouseDownHitArea == ItemHitArea.TrackDecrease)
                            SetScrollValue(Value - _LargeChange, ScrollEventType.LargeDecrement);
                        else
                            SetScrollValue(Value + _LargeChange, ScrollEventType.LargeIncrement);
                    }
                }
                else
                {
                    if (_HitArea == ItemHitArea.ArrowDecrease)
                        SetScrollValue(Value - _SmallChange, ScrollEventType.SmallDecrement);
                    else if (_HitArea == ItemHitArea.ArrowIncrease)
                        SetScrollValue(Value + _SmallChange, ScrollEventType.SmallIncrement);
                    else
                    {
                        _ClickCount = 0;
                        _ClickTimer.Interval = 100;
                    }
                }
                Timer clickTimer = _ClickTimer;
                if (clickTimer != null)
                {
                    _ClickCount++;
                    if (_ClickCount > 4 && clickTimer.Interval > 20)
                        clickTimer.Interval -= 10;
                }
            }
        }
        #endregion
        #endregion
        #region SetScrollValue
        private void SetScrollValue(int value, ScrollEventType type)
        {
            value = NormalizeValue(value);
            int oldValue = _Value;
            Value = value;
            OnScroll(type, _Value, oldValue);
            _RaiseEndScroll = true;
        }
        #endregion
        #region OnScroll
        private void OnScroll(ScrollEventType type, int oldValue, int newValue)
        {
            ScrollEventArgs args = null;
            if (Scroll != null)
            {
                ScrollOrientation so = (Orientation == Orientation.Horizontal)
                    ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll;
                args = new ScrollEventArgs(type, oldValue, newValue, so);
                Scroll(this, args);
            }
            if (ChartControl.IsScrollHooked == true)
            {
                if (args == null)
                {
                    ScrollOrientation so = (Orientation == Orientation.Horizontal)
                        ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll;
                    args = new ScrollEventArgs(type, oldValue, newValue, so);
                }
                ChartControl.DoScrollEvent((ChartContainer)Parent, args, this);
            }
        }
        #endregion
        #region GetBarAreaAt
        public override ItemHitArea GetHitArea(Point pt)
        {
            if ((Bounds.Contains(pt) == false) ||
                (Visible == false || Enabled == false))
            {
                return (ItemHitArea.None);
            }
            if (_ArrowDecreaseBounds.Contains(pt))
                return (Inverted ? ItemHitArea.ArrowIncrease : ItemHitArea.ArrowDecrease);
            if (_ArrowIncreaseBounds.Contains(pt))
                return (Inverted ? ItemHitArea.ArrowDecrease : ItemHitArea.ArrowIncrease);
            if (_ThumbBounds.Contains(pt))
                return (ItemHitArea.Thumb);
            if (Orientation == Orientation.Horizontal)
            {
                if (pt.X < _ThumbBounds.Left)
                {
                    if (Inverted == false)
                        return (ItemHitArea.TrackDecrease);
                }
            }
            else
            {
                if (pt.Y < _ThumbBounds.Top)
                {
                    if (Inverted == false)
                        return (ItemHitArea.TrackDecrease);
                }
            }
            return (ItemHitArea.TrackIncrease);
        }
        #endregion
        #region Style handling
        #region GetEffectiveStyle
        ///
        /// Gets the EffectiveStyle for the ScrollBar. The effective
        /// style is a composite, cached style definition.
        ///
        /// 
        /// 
        public ScrollBarVisualStyle GetEffectiveStyle(StyleState state)
        {
            return (_EffectiveStyles[state]);
        }
        ///
        /// Gets the EffectiveStyle for the ScrollBar. The effective
        /// style is a composite, cached style definition.
        ///
        ///
        public ScrollBarVisualStyle GetEffectiveStyle()
        {
            StyleState state = GetStyleState();
            return (_EffectiveStyles[state]);
        }
        #region GetStyleState
        private StyleState GetStyleState()
        {
            StyleState state = StyleState.Default;
            Point pt = ChartControl.PointToClient(Control.MousePosition);
            if (Bounds.Contains(pt))
                state |= StyleState.MouseOver;
            if (_MouseDownHitArea != ItemHitArea.None)
                state |= StyleState.Selected;
            return (state);
        }
        #endregion
        #endregion
        #region ApplyStyles
        public override void ApplyStyles(BaseVisualStyle style, StyleType cs)
        {
            ScrollBarVisualStyle pstyle = style as ScrollBarVisualStyle;
            if (pstyle != null)
            {
                ApplyParentStyles(pstyle, cs, Parent as ChartContainer);
                pstyle.ApplyStyle(ScrollBarVisualStyles[cs]);
            }
        }
        #region ApplyParentStyles
        private void ApplyParentStyles(
            ScrollBarVisualStyle pstyle, StyleType cs, ChartContainer item)
        {
            if (item != null)
            {
                ApplyParentStyles(pstyle, cs, item.Parent as ChartContainer);
                if (item is ChartXy)
                {
                    if (Orientation == Orientation.Horizontal)
                        pstyle.ApplyStyle(((ChartXy)item).ChartVisualStyle.HScrollBarVisualStyles[cs]);
                    else
                        pstyle.ApplyStyle(((ChartXy)item).ChartVisualStyle.VScrollBarVisualStyles[cs]);
                }
                else if (item is ChartPanel)
                {
                    if (Orientation == Orientation.Horizontal)
                        pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.HScrollBarVisualStyles[cs]);
                    else
                        pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.VScrollBarVisualStyles[cs]);
                }
            }
            else
            {
                if (Orientation == Orientation.Horizontal)
                {
                    pstyle.ApplyStyle(ChartControl.BaseVisualStyles.HScrollBarVisualStyles[cs]);
                    pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.HScrollBarVisualStyles[cs]);
                }
                else
                {
                    pstyle.ApplyStyle(ChartControl.BaseVisualStyles.VScrollBarVisualStyles[cs]);
                    pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.VScrollBarVisualStyles[cs]);
                }
            }
        }
        #endregion
        #endregion
        #region ApplyDefaults
        public override void ApplyDefaults(BaseVisualStyle style, StyleType cs)
        {
            ScrollBarVisualStyle pstyle = style as ScrollBarVisualStyle;
            if (pstyle != null)
                pstyle.ApplyDefaults();
            base.ApplyDefaults(style, cs);
        }
        #endregion
        #region InvalidateStyle
        ///
        ///Invalidate the cached Styles
        ///
        public void InvalidateStyle()
        {
            ClearEffectiveStyles();
        }
        #endregion
        #region ClearEffectiveStyles
        protected override void ClearEffectiveStyles()
        {
            _EffectiveStyles.InvalidateStyles();
            base.ClearEffectiveStyles();
        }
        #endregion
        #endregion
        #region InvalidateLayoutBounds
        /// 
        /// Invalidates the layout bounds for the item container
        /// 
        public override void InvalidateLayoutBounds(ScrollBarLite sbar)
        {
            ChartVisualElement parent = Parent as ChartVisualElement;
            if (parent is IScrollable)
            {
                IScrollable isc = (IScrollable)parent;
                isc.InvalidateLayoutBounds(sbar);
                Rectangle scrollBounds = GetScrollBounds(isc.ScrollBounds);
                parent.InvalidateRender(scrollBounds);
            }
        }
        #endregion
        #region GetSerialData
        internal override SerialElementCollection GetSerialData(string serialName)
        {
            SerialElementCollection sec = new SerialElementCollection();
            if (serialName != null)
            {
                if (serialName.Equals("") == true)
                    serialName = "ChartXy";
                sec.AddStartElement(serialName);
            }
            if (_ScrollBarVisualStyles != null && _ScrollBarVisualStyles.IsEmpty == false)
                sec.AddElement(_ScrollBarVisualStyles.GetSerialData("ScrollBarVisualStyles"));
            sec.AddElement(base.GetSerialData(null));
            if (serialName != null)
                sec.AddEndElement(serialName);
            return (sec);
        }
        #endregion
        #region PutSerialData
        #region ProcessCollection
        internal override void ProcessCollection(SerialElement se)
        {
            SerialElementCollection sec = se.Sec;
            switch (se.Name)
            {
                case "ScrollBarVisualStyles":
                    sec.PutSerialData(ScrollBarVisualStyles);
                    break;
                default:
                    base.ProcessCollection(se);
                    break;
            }
        }
        #endregion
        #endregion
        #region IDisposable
        public override void Dispose()
        {
            ScrollBarVisualStyles = null;
            base.Dispose();
        }
        #endregion
    }
    #region EventArgs
    #region ValueChangedEventArgs
    /// 
    /// ValueChangedEventArgs
    /// 
    public class ValueChangedEventArgs : EventArgs
    {
        #region Private variables
        private int _OldValue;
        private int _NewValue;
        #endregion
        ///
        /// ValueChangedEventArgs
        ///
        ///
        ///
        public ValueChangedEventArgs(int oldValue, int newValue)
        {
            _OldValue = oldValue;
            _NewValue = newValue;
        }
        #region Public properties
        /// 
        /// Gets the old scroll Value
        /// 
        public int OldValue
        {
            get { return (_OldValue); }
        }
        /// 
        /// Gets the new scroll Value
        /// 
        public int NewValue
        {
            get { return (_NewValue); }
        }
        #endregion
    }
    #endregion
    #endregion
    #region Interfaces
    #region IScrollable
    internal interface IScrollable
    {
        Rectangle ScrollBounds { get; }
        Rectangle ScrollBoundsEx { get; }
        Point ScrollBoundsOffset { get; }
        void InvalidateLayoutBounds(ScrollBarLite sbar);
    }
    #endregion
    #endregion
}