using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
    #region MajorTickmarks
    #region MajorTickmarksX
    /// 
    /// Represents a chart MajorTickmark on the X-Axis.
    /// 
    public class MajorTickmarksX : MajorTickmarks
    {
        public MajorTickmarksX()
            : base(AxisOrientation.X)
        {
        }
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartTickmarkVisualStyle tstyle = EffectiveStyle;
            Rectangle bounds = Rectangle.Empty;
            MeasureTickmarks(layoutInfo, chartAxis);
            if (TickmarkLayout.MajorCount > 0)
            {
                bounds = MeasureTickmarkLabels(layoutInfo, chartAxis);
                float angle = GetLabelAngle();
                if (angle == 0)
                    CullOverlappingLabels();
            }
            BoundsRelative = bounds;
        }
        #region MeasureTickmarks
        private void MeasureTickmarks(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
        {
            TickmarkLayout layout = TickmarkLayout;
            if (layout.MajorCount > 0)
            {
                Graphics g = layoutInfo.Graphics;
                Rectangle bounds = layoutInfo.LayoutBounds;
                layout.TickmarkStart = GetStartIndex();
                layout.TickmarkEnd = layout.TickmarkStart + (int)Math.Ceiling((bounds.Width + layout.MarginOffset) / layout.MajorInterval) + 3;
                UpdateTickmarkTicks(g, chartAxis, bounds, layout);
                ArrangeTickmarks();
            }
        }
        #endregion
        #region MeasureTickmarkLabels
        private Rectangle MeasureTickmarkLabels(
            ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
        {
            ChartTickmarkVisualStyle tstyle = EffectiveStyle;
            int labelHeight = GetTotalLabelHeight();
            int tickmarkHeight = Dpi.Height(GetMaxTickmarkLength(chartAxis, false));
            if (tickmarkHeight == 0)
                tickmarkHeight = Dpi.Height4;
            Rectangle bounds = layoutInfo.LayoutBounds;
            bounds.Height = (labelHeight + tickmarkHeight);
            ChartXy chartXy = chartAxis.Parent as ChartXy;
            if (chartXy.DropShadowDisplayed == true)
                bounds.Width -= 3;
            Rectangle r = bounds;
            if (chartAxis.GetAxisAlignment() == AxisAlignment.Far)
            {
                LabelBounds = new Rectangle(r.X, r.Y, r.Width, labelHeight);
                r.Y += labelHeight;
                r.Height -= labelHeight;
                TickmarkBounds = r;
            }
            else
            {
                r.Y = layoutInfo.LayoutBounds.Bottom - labelHeight;
                bounds.Y = r.Y;
                LabelBounds = new Rectangle(r.X, r.Y, r.Width, labelHeight);
                r.Y -= tickmarkHeight;
                r.Height = tickmarkHeight;
                TickmarkBounds = r;
            }
            if (chartAxis.EdgeAxis == false)
                bounds.Height += Dpi.Height(GetMaxTickmarkLength(chartAxis, true)) + 2;
            return (bounds);
        }
        #endregion
        #endregion
        #region ArrangeTickmarks
        protected override void ArrangeTickmarks()
        {
            TickmarkLayout layout = TickmarkLayout;
            if (layout.Ticks != null)
            {
                ChartAxis chartAxis = Parent as ChartAxis;
                Rectangle tmBounds = TickmarkBounds;
                Rectangle lbounds = LabelBounds;
                AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                Point tickPoint = new Point(0, 
                    (axisAlignment == AxisAlignment.Near) ? tmBounds.Y : tmBounds.Bottom + 1);
                float angle = GetLabelAngle();
                for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
                {
                    TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
                    tickPoint.X = (int)(tmBounds.Location.X + (i * layout.MajorInterval) - layout.MarginOffset);
                    tick.TickPoint = tickPoint;
                    if (tick.Label != null)
                    {
                        tick.LabelPoint = tickPoint;
                        tick.LabelPoint.Y = lbounds.Y;
                        int height = LabelBounds.Height;
                        if (LabelsAreStaggered == true)
                        {
                            double value = GetTickmarkValue(chartAxis, tick);
                            int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
                            if ((tick.Index % 2) != (axisAlignment == AxisAlignment.Far ? 0 : 1))
                            {
                                height -= MaxLabelSize[0].Height;
                                tick.LabelPoint.Y += MaxLabelSize[0].Height;
                            }
                            else
                            {
                                height -= MaxLabelSize[1].Height;
                            }
                        }
                        if (axisAlignment == AxisAlignment.Far)
                            tick.LabelPoint.Y += (height - tick.LabelSize.Height);
                        if (angle == 0)
                            tick.LabelPoint.X -= (tick.LabelSize.Width / 2);
                    }
                }
            }
        }
        #region CullOverlappingLabels
        private void CullOverlappingLabels()
        {
            TickmarkLayout layout = TickmarkLayout;
            for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
            {
                TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
                if (tick.LabelVisible == true)
                {
                    for (int j = i + 1; j < layout.TickmarkEnd; j++)
                    {
                        TickmarkTick tick2 = layout.Ticks[j - layout.TickmarkStart];
                        if (tick2.LabelVisible == true)
                        {
                            if (tick2.LabelPoint.X < tick.LabelPoint.X + tick.LabelSize.Width - 1)
                            {
                                if ((LabelsAreStaggered == false) ||
                                    (tick.LabelIndex % 2 == tick2.LabelIndex % 2))
                                {
                                    tick2.LabelVisible = false;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            base.RenderOverride(renderInfo);
            Graphics g = renderInfo.Graphics;
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartTickmarkVisualStyle tstyle = EffectiveStyle;
            if (CanRenderTickmarks(tstyle) == true)
                RenderTickmarks(g, tstyle, chartAxis);
            if (TickmarkLayout.MajorCount > 0)
                RenderTickmarkLabels(g, chartAxis);
        }
        #region RenderTickmarks
        private void RenderTickmarks(Graphics g,
            ChartTickmarkVisualStyle tstyle, ChartAxis chartAxis)
        {
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.None;
            using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Width(tstyle.TickmarkThickness)))
            {
                int tlen = Dpi.Width(tstyle.TickmarkLength - ((tstyle.TickmarkThickness > 1) ? 0 : 1));
                AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                Point pt = GetLocalAdjustedPoint(Point.Empty);
                if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
                    (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
                    (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
                {
                    // Bottom
                    RenderMarks(g, pen, chartAxis, pt, 0, tlen, axisAlignment == AxisAlignment.Far);
                }
                if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
                    (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
                    (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
                {
                    // Top
                    ChartXy chartXy = chartAxis.Parent as ChartXy;
                    if (axisAlignment == AxisAlignment.Near)
                    {
                        int n = 1;
                        if (chartAxis.EdgeAxis == true)
                            n = chartXy.GetScBorderThickness(XyAlignment.Bottom) + 1;
                        RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, true);
                    }
                    else
                    {
                        int n = 1;
                        RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, false);
                    }
                }
            }
            g.SmoothingMode = sm;
        }
        #region RenderMarks
        private void RenderMarks(Graphics g,
            Pen pen, ChartAxis chartAxis, Point pt, int voff, int len, bool skipFirst)
        {
            foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
            {
                Point pt1 = tmi.TickPoint;
                pt1.X += pt.X;
                pt1.Y += (pt.Y + voff);
                if (pt1.X >= chartAxis.AxisLineBounds.X - ScrollOffset.X &&
                    pt1.X < chartAxis.AxisLineBounds.Right - ScrollOffset.X)
                {
                    if (tmi.Index > 0 || skipFirst == false)
                    {
                        Point pt2 = pt1;
                        pt2.Y += len;
                        g.DrawLine(pen, pt1, pt2);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region RenderTickmarkLabels
        private void RenderTickmarkLabels(Graphics g, ChartAxis chartAxis)
        {
            if (LabelBounds.IsEmpty == false)
            {
                TickmarkLabelVisualStyle lstyle = EffectiveLabelStyle;
                Point pt = GetLocalAdjustedPoint(Point.Empty);
                float angle = GetLabelAngle();
                using (SolidBrush br = new SolidBrush(lstyle.TextColor))
                {
                    SmoothingMode sm = g.SmoothingMode;
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    ChartXy chartXy = chartAxis.Parent as ChartXy;
                    Rectangle alb = chartXy.GetScrollBounds(chartAxis.AxisLineBounds);
                    foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
                    {
                        if (tmi.LabelVisible == true)
                        {
                            if ((tmi.TickPoint.X + pt.X >= alb.X) &&
                                (tmi.TickPoint.X + pt.X < alb.Right))
                            {
                                if (tmi.LabelColor.IsEmpty == true)
                                {
                                    RenderLabel(g, tmi, pt, angle, br, lstyle.Font);
                                }
                                else
                                {
                                    using (SolidBrush br2 = new SolidBrush(tmi.LabelColor))
                                        RenderLabel(g, tmi, pt, angle, br2, lstyle.Font);
                                }
                            }
                        }
                    }
                    g.SmoothingMode = sm;
                }
            }
        }
        #region RenderLabel
        private void RenderLabel(Graphics g,
            TickmarkTick tmi, Point pt, float angle, Brush br, Font font)
        {
            Rectangle r = new Rectangle(tmi.LabelPoint, tmi.LabelSize);
            r.X += pt.X;
            r.Y += pt.Y;
            if (angle == 0)
            {
                g.DrawString(tmi.Label, font, br, r);
            }
            else
            {
                Point pt1 = Point.Empty;
                if (angle > 0)
                {
                    if (angle > 90)
                    {
                        angle = angle - 180;
                        pt1.X = -(int)tmi.TextSize.Width;
                    }
                    pt1.Y = -(int)((Math.Abs(angle) / 90f) * (font.Height / 2));
                    g.TranslateTransform(r.X, r.Y);
                }
                else
                {
                    if (angle < -90)
                    {
                        angle = angle + 180;
                        pt1.X = -(int)tmi.TextSize.Width + 4;
                    }
                    pt1.Y = -(int)(tmi.TextSize.Height -
                        (Math.Abs(angle) / 90f) * (tmi.TextSize.Height / 2));
                    g.TranslateTransform(r.X, LabelBounds.Bottom - 1);
                }
                g.RotateTransform(angle);
                g.DrawString(tmi.Label, font, br, pt1);
                g.ResetTransform();
            }
        }
        #endregion
        #endregion
        #endregion
        #region GetStartIndex
        internal override int GetStartIndex()
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartXy chartXy = chartAxis.Parent as ChartXy;
            return (GetStartIndexEx(chartXy.HScrollBar));
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Create a copy of the chart element.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            MajorTickmarksX copy = new MajorTickmarksX();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MajorTickmarksX c = copy as MajorTickmarksX;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region MajorTickmarksY
    /// 
    /// Represents a chart MajorTickmark on the Y-Axis.
    /// 
    public class MajorTickmarksY : MajorTickmarks
    {
        public MajorTickmarksY()
            : base(AxisOrientation.Y)
        {
        }
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartTickmarkVisualStyle tstyle = EffectiveStyle;
            Rectangle bounds = Rectangle.Empty;
            MeasureTickmarks(layoutInfo, chartAxis);
            if (TickmarkLayout.MajorCount > 0)
                bounds = MeasureTickmarkLabels(layoutInfo, chartAxis);
            BoundsRelative = bounds;
        }
        #region MeasureTickmarks
        private void MeasureTickmarks(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
        {
            TickmarkLayout layout = TickmarkLayout;
            if (layout.MajorCount > 0)
            {
                Graphics g = layoutInfo.Graphics;
                Rectangle bounds = layoutInfo.LayoutBounds;
                layout.TickmarkStart = GetStartIndex();
                layout.TickmarkEnd = layout.TickmarkStart + (int)((Math.Ceiling(bounds.Height / layout.MajorInterval))) + 3;
                UpdateTickmarkTicks(g, chartAxis, bounds, layout);
                ArrangeTickmarks();
            }
        }
        #endregion
        #region MeasureTickmarkLabels
        private Rectangle MeasureTickmarkLabels(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
        {
            Rectangle bounds = layoutInfo.LayoutBounds;
            int labelWidth = GetTotalLabelWidth();
            int tickmarkWidth = Dpi.Width(GetMaxTickmarkLength(chartAxis, false));
            bounds.Width = (labelWidth + tickmarkWidth);
            ChartXy chartXy = chartAxis.Parent as ChartXy;
            if (chartXy.DropShadowDisplayed == true)
                bounds.Height -= 3;
            Rectangle r = bounds;
            AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
            if (axisAlignment == AxisAlignment.Far)
            {
                LabelBounds = new Rectangle(r.X, r.Y, labelWidth, r.Height);
                r.X += labelWidth;
                r.Width -= labelWidth;
                TickmarkBounds = r;
            }
            else
            {
                r.X = layoutInfo.LayoutBounds.Right - labelWidth;
                bounds.X = r.X;
                LabelBounds = new Rectangle(r.X, r.Y, labelWidth, r.Height);
                r.X -= tickmarkWidth;
                r.Width = tickmarkWidth;
                TickmarkBounds = r;
            }
            if (chartAxis.EdgeAxis == false)
                bounds.Width += Dpi.Width(GetMaxTickmarkLength(chartAxis, true)) + 2;
            return (bounds);
        }
        #endregion
        #endregion
        #region ArrangeTickmarks
        protected override void ArrangeTickmarks()
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            Rectangle tmBounds = TickmarkBounds;
            Rectangle lbounds = LabelBounds;
            TickmarkLayout layout = TickmarkLayout;
            AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
            Point tickPoint = new Point((axisAlignment == AxisAlignment.Near) ? tmBounds.X : tmBounds.Right + 1, 0);
            float angle = GetLabelAngle();
            for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
            {
                TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
                tickPoint.Y = (int)(tmBounds.Bottom - 1 - (i * layout.MajorInterval) + layout.MarginOffset);
                tick.TickPoint = tickPoint;
                tick.LabelPoint = tickPoint;
                tick.LabelPoint.X = lbounds.X;
                int width = LabelBounds.Width;
                if (LabelsAreStaggered == true)
                {
                    double value = GetTickmarkValue(chartAxis, tick);
                    int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
                    if ((n % 2) != (axisAlignment == AxisAlignment.Near ? 0 : 1))
                    {
                        width -= MaxLabelSize[0].Width;
                        tick.LabelPoint.X += MaxLabelSize[0].Width;
                    }
                    else
                    {
                        width -= MaxLabelSize[1].Width;
                    }
                }
                if (axisAlignment == AxisAlignment.Far)
                    tick.LabelPoint.X += (width - tick.LabelSize.Width);
                if ((angle + 90) % 180 == 0)
                    tick.LabelPoint.Y -= (tick.LabelSize.Height / 2);
            }
        }
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            base.RenderOverride(renderInfo);
            Graphics g = renderInfo.Graphics;
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartTickmarkVisualStyle tstyle = EffectiveStyle;
            if (CanRenderTickmarks(tstyle) == true)
                RenderTickmarks(g, tstyle, chartAxis);
            if (TickmarkLayout.MajorCount > 0)
                RenderTickmarkLabels(g, chartAxis);
        }
        #region RenderTickmarks
        private void RenderTickmarks(Graphics g,
            ChartTickmarkVisualStyle tstyle, ChartAxis chartAxis)
        {
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.None;
            using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Height(tstyle.TickmarkThickness)))
            {
                int tlen = Dpi.Height(tstyle.TickmarkLength) - ((tstyle.TickmarkThickness > 1) ? 0 : 1);
                Point pt = GetLocalAdjustedPoint(Point.Empty);
                AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                if (tstyle.TickmarkAlignment == LineAlignment.Center ||
                    (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
                    (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
                {
                    // Right
                    RenderMarks(g, pen, chartAxis, pt, 0, tlen, axisAlignment == AxisAlignment.Far);
                }
                if (tstyle.TickmarkAlignment == LineAlignment.Center ||
                    (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
                    (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
                {
                    // Left
                    ChartXy chartXy = chartAxis.Parent as ChartXy;
                    if (axisAlignment == AxisAlignment.Near)
                    {
                        int n = 1;
                        if (chartAxis.EdgeAxis == true)
                            n = chartXy.GetScBorderThickness(XyAlignment.Right) + 1;
                        RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, true);
                    }
                    else
                    {
                        int n = 2;
                        RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, false);
                    }
                }
            }
            g.SmoothingMode = sm;
        }
        #region RenderMarks
        private void RenderMarks(Graphics g,
            Pen pen, ChartAxis chartAxis, Point pt, int hoff, int len, bool skipFirst)
        {
            foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
            {
                Point pt1 = tmi.TickPoint;
                pt1.X += (pt.X + hoff);
                pt1.Y += pt.Y;
                if (pt1.Y >= chartAxis.AxisLineBounds.Y - ScrollOffset.Y &&
                    pt1.Y < chartAxis.AxisLineBounds.Bottom - ScrollOffset.Y)
                {
                    if (tmi.Index > 0 || skipFirst == false)
                    {
                        Point pt2 = pt1;
                        pt2.X += len;
                        g.DrawLine(pen, pt1, pt2);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region RenderTickmarkLabels
        private void RenderTickmarkLabels(Graphics g, ChartAxis chartAxis)
        {
            if (LabelBounds.IsEmpty == false)
            {
                TickmarkLabelVisualStyle lstyle = EffectiveLabelStyle;
                Point pt = GetLocalAdjustedPoint(Point.Empty);
                AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                float angle = GetLabelAngle();
                using (SolidBrush br = new SolidBrush(lstyle.TextColor))
                {
                    SmoothingMode sm = g.SmoothingMode;
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    Rectangle bounds = chartAxis.Bounds;
                    foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
                    {
                        if (tmi.LabelVisible == true)
                        {
                            if (tmi.TickPoint.Y + pt.Y < bounds.Y)
                                break;
                            if (tmi.TickPoint.Y + pt.Y > bounds.Bottom)
                                continue;
                            if (tmi.LabelColor.IsEmpty == true)
                            {
                                RenderLabel(g, tmi, pt, axisAlignment, angle, br, lstyle.Font);
                            }
                            else
                            {
                                using (SolidBrush br2 = new SolidBrush(tmi.LabelColor))
                                    RenderLabel(g, tmi, pt, axisAlignment, angle, br2, lstyle.Font);
                            }
                        }
                    }
                    g.SmoothingMode = sm;
                }
            }
        }
        #region RenderLabel
        private void RenderLabel(Graphics g, TickmarkTick tmi,
            Point pt, AxisAlignment axisAlignment, float angle, Brush br, Font font)
        {
            Rectangle r = new Rectangle(tmi.LabelPoint, tmi.LabelSize);
            r.X += pt.X;
            r.Y += pt.Y;
            int n = (int)(tmi.TextSize.Height / 2);
            if (angle == 0)
            {
                r.Y -= n;
                g.DrawString(tmi.Label, font, br, r);
            }
            else
            {
                Point pt1 = Point.Empty;
                if (angle > 0)
                {
                    if (angle > 90)
                    {
                        angle = angle - 180;
                        pt1.Y -= (int)(((90 + angle) / 90f) * (font.Height / 2));
                    }
                    else
                    {
                        pt1.Y -= (n + (int)((Math.Abs(angle) / 90f) * (font.Height / 2)));
                    }
                    g.TranslateTransform(r.X, r.Y);
                }
                else
                {
                    if (angle < -90)
                    {
                        angle = angle + 180;
                        pt1.Y -= ((int)((Math.Abs(90 - angle) / 90f) * (tmi.TextSize.Height / 2)));
                    }
                    else
                    {
                        pt1.Y -= (n + (int)((Math.Abs(angle) / 90f) * (font.Height / 2)));
                    }
                    pt1.X = -(int)tmi.TextSize.Width;
                    g.TranslateTransform(r.Right, r.Y);
                }
                g.RotateTransform(angle);
                g.DrawString(tmi.Label, font, br, pt1);
                g.ResetTransform();
            }
        }
        #endregion
        #endregion
        #endregion
        #region GetStartIndex
        internal override int GetStartIndex()
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            ChartXy chartXy = chartAxis.Parent as ChartXy;
            return (GetStartIndexEx(chartXy.VScrollBar));
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Creates a copy of the chart element.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            MajorTickmarksY copy = new MajorTickmarksY();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MajorTickmarksY c = copy as MajorTickmarksY;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region MajorTickmarks
    /// 
    /// Represents a chart MajorTickmark.
    /// 
    public class MajorTickmarks : ChartTickmarks
    {
        #region Private variables
        private MajorStates _MajorStates;
        private float _LabelAngle;
        private int _MinLabelGap = 4;
        private int _LabelSkip;
        private Rectangle _LabelBounds;
        private Size[] _MaxLabelSize;
        private TickmarkLabelVisualStyle _LabelVisualStyle;
        private EffectiveStyle _EffectiveLabelStyle;
        #endregion
        public MajorTickmarks(AxisOrientation orientation)
            : base(orientation)
        {
            InitDefaultStates();
            _EffectiveLabelStyle = new EffectiveStyle(this);
        }
        #region InitDefaultStates
        private void InitDefaultStates()
        {
            SetState(MajorStates.AutoLayout, true);
            SetState(MajorStates.ShowLabels, true);
            SetState(MajorStates.StaggerLabels, true);
        }
        #endregion
        #region Public properties
        #region AutoTickmarkLayout
        /// 
        /// Gets or sets whether Major Tickmark layout is automatic.
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether Major Tickmark layout is automatic.")]
        public bool AutoTickmarkLayout
        {
            get { return (TestState(MajorStates.AutoLayout)); }
            set
            {
                if (value != AutoTickmarkLayout)
                {
                    SetState(MajorStates.AutoLayout, value);
                    OnPropertyChangedEx("AutoTickmarkLayout", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region EffectiveLabelStyles
        /// 
        /// Gets a reference to the Tickmark Label's Effective (cached, composite) style.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TickmarkLabelVisualStyle EffectiveLabelStyle
        {
            get { return (_EffectiveLabelStyle.Style); }
        }
        #endregion
        #region LabelAngle
        ///
        /// Gets or sets the angle at which the Tickmark labels are displayed.
        ///
        [DefaultValue(0f), Category("Layout")]
        [Description("Indicates the angle at which the Tickmark labels are displayed.")]
        [Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, " +
                "Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
        public float LabelAngle
        {
            get { return (_LabelAngle); }
            set
            {
                if (value != _LabelAngle)
                {
                    _LabelAngle = value;
                    OnPropertyChangedEx("LabelAngle", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region LabelSkip
        /// 
        /// Gets or sets the number of inter-labels to skip.
        /// 
        [DefaultValue(0), Category("Layout")]
        [Description("Indicates the number of inter-labels to skip.")]
        public int LabelSkip
        {
            get { return (_LabelSkip); }
            set
            {
                if (value != _LabelSkip)
                {
                    _LabelSkip = value;
                    OnPropertyChangedEx("LabelSkip", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region LabelVisualStyle
        /// 
        /// Gets or sets the visual style for the Tickmark Labels.
        /// 
        [Category("Style")]
        [Description("Indicates the visual style for the Tickmark Labels.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public TickmarkLabelVisualStyle LabelVisualStyle
        {
            get
            {
                if (_LabelVisualStyle == null)
                {
                    _LabelVisualStyle = new TickmarkLabelVisualStyle();
                    StyleVisualChangeHandler(null, _LabelVisualStyle);
                }
                return (_LabelVisualStyle);
            }
            set
            {
                if (_LabelVisualStyle != value)
                {
                    TickmarkLabelVisualStyle oldValue = _LabelVisualStyle;
                    _LabelVisualStyle = value;
                    OnStyleChanged("LabelVisualStyle", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #region MinLabelGap
        /// 
        /// Gets or sets the minimum gap between tickmark labels.
        /// 
        [DefaultValue(4), Category("Layout")]
        [Description("Indicates the minimum gap between tickmark labels.")]
        public int MinLabelGap
        {
            get { return (_MinLabelGap); }
            set
            {
                if (value != _MinLabelGap)
                {
                    _MinLabelGap = value;
                    OnPropertyChangedEx("MinLabelGap", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region ShowLabels
        /// 
        /// Gets or sets whether Tickmark labels are shown.
        /// 
        [DefaultValue(true), Category("Layout")]
        [Description("Indicates whether Tickmark labels are shown.")]
        public bool ShowLabels
        {
            get { return (TestState(MajorStates.ShowLabels)); }
            set
            {
                if (value != ShowLabels)
                {
                    SetState(MajorStates.ShowLabels, value);
                    OnPropertyChangedEx("ShowLabels", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region StaggerLabels
        /// 
        /// Gets or sets whether overlapping labels are staggered.
        /// 
        [DefaultValue(true), Category("Layout")]
        [Description("Indicates whether overlapping labels are staggered.")]
        public bool StaggerLabels
        {
            get { return (TestState(MajorStates.StaggerLabels)); }
            set
            {
                if (value != StaggerLabels)
                {
                    SetState(MajorStates.StaggerLabels, value);
                    OnPropertyChangedEx("StaggerLabels", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region LabelBounds
        internal Rectangle LabelBounds
        {
            get { return (_LabelBounds); }
            set { _LabelBounds = value; }
        }
        #endregion
        #region LabelsAreStaggered
        internal bool LabelsAreStaggered
        {
            get { return (TestState(MajorStates.LabelsAreStaggered)); }
            set { SetState(MajorStates.LabelsAreStaggered, value); }
        }
        #endregion
        #region MaxLabelSize
        internal Size[] MaxLabelSize
        {
            get { return (_MaxLabelSize); }
            set { _MaxLabelSize = value; }
        }
        #endregion
        #endregion
        #region UpdateTickmarkTicks
        internal void UpdateTickmarkTicks(Graphics g,
            ChartAxis chartAxis, Rectangle bounds, TickmarkLayout layout)
        {
            TickmarkTick[] ticks = new TickmarkTick[layout.TickmarkEnd - layout.TickmarkStart];
            CalculateBaseValue(chartAxis, layout);
            if (ShowLabels == true)
            {
                TickmarkLabelVisualStyle lbstyle = EffectiveLabelStyle;
                using (StringFormat sf = new StringFormat())
                {
                    lbstyle.GetStringFormatFlags(sf);
                    if (lbstyle.MaxLineCount <= 1)
                        sf.FormatFlags |= StringFormatFlags.NoWrap;
                    int maxLabelWidth = lbstyle.MaxWidth < 0 ? 0 : lbstyle.MaxWidth;
                    float angle = GetLabelAngle();
                    int skip = (LabelSkip > 0 ? LabelSkip + 1 : 0);
                    for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
                    {
                        TickmarkTick tmi = new TickmarkTick();
                        tmi.Index = i;
                        SetTickValue(chartAxis, layout, lbstyle, tmi);
                        if ((tmi.Label != null) && (skip <= 0 || (tmi.LabelIndex) % skip == 0))
                        {
                            lbstyle.GetStringFormatFlags(sf);
                            tmi.TextSize = g.MeasureString(tmi.Label, lbstyle.Font, maxLabelWidth, sf);
                            if (tmi.TextSize.IsEmpty == false)
                            {
                                tmi.TextSize.Width++;
                                tmi.TextSize.Height++;
                            }
                            if (lbstyle.MaxLineCount > 1)
                            {
                                int lineHeight = (int)(Math.Ceiling(lbstyle.Font.GetHeight())) * lbstyle.MaxLineCount;
                                if (tmi.TextSize.Height > lineHeight)
                                    tmi.TextSize.Height = lineHeight;
                            }
                            if (angle != 0)
                            {
                                double radians = MathHelper.ToRadians(angle);
                                tmi.LabelSize.Width = (int)(Math.Abs(tmi.TextSize.Width * Math.Cos(radians)) + Math.Abs(tmi.TextSize.Height * Math.Sin(radians)));
                                tmi.LabelSize.Height = (int)(Math.Abs(tmi.TextSize.Width * Math.Sin(radians)) + Math.Abs(tmi.TextSize.Height * Math.Cos(radians)));
                            }
                            else
                            {
                                tmi.LabelSize = tmi.TextSize.ToSize();
                            }
                            tmi.LabelVisible = true;
                        }
                        else
                        {
                            tmi.LabelVisible = false;
                        }
                        ticks[i - layout.TickmarkStart] = tmi;
                    }
                }
            }
            else
            {
                for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
                {
                    TickmarkTick tmi = new TickmarkTick();
                    tmi.Index = i;
                    SetTickValue(chartAxis, layout, null, tmi);
                    ticks[i - layout.TickmarkStart] = tmi;
                }
            }
            layout.Ticks = ticks;
        }
        #region CalculateBaseValue
        private void CalculateBaseValue(ChartAxis axis, TickmarkLayout layout)
        {
            switch (axis.ScaleType)
            {
                case ScaleType.Qualitative:
                    int iminValue = (int)layout.MinValue;
                    int ivalue = (int)Math.Floor(iminValue / layout.GridSpacing);
                    layout.BaseValue = (int)(ivalue * layout.GridSpacing);
                    break;
                case ScaleType.DateTime:
                    layout.BaseValue = layout.MinValue;
                    break;
                default:
                    Type otype = layout.MinValue.GetType();
                    double dminValue = Convert.ToDouble(layout.MinValue);
                    double n = dminValue < 0 ? -1 : 1;
                    double dvalue = Math.Floor(Math.Abs(dminValue) / layout.MajorSpacing);
                    layout.BaseValue = Convert.ChangeType((int)dvalue * layout.MajorSpacing * n, otype);
                    break;
            }
        }
        #endregion
        #region SetTickValue
        private void SetTickValue(ChartAxis chartAxis, 
            TickmarkLayout layout, TickmarkLabelVisualStyle lbstyle, TickmarkTick tmi)
        {
            tmi.LabelIndex = -1;
            switch (chartAxis.ScaleType)
            {
                case ScaleType.Qualitative:
                    tmi.Value = (int)layout.BaseValue + tmi.Index;
                    if (ShowLabels == true)
                    {
                        int i = (int)tmi.Value;
                        if ((uint)i < chartAxis.QualitativeValues.Count)
                        {
                            object value = chartAxis.QualitativeValues[i];
                            if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
                                tmi.Label = string.Format(lbstyle.TextFormat, value);
                            else
                                tmi.Label = value.ToString();
                            tmi.LabelIndex = i;
                        }
                    }
                    break;
                case ScaleType.DateTime:
                    tmi.Value = chartAxis.GetDateTime((DateTime)layout.BaseValue, tmi.Index * layout.MajorSpacing);
                    if (ShowLabels == true)
                    {
                        DateTime dt = (DateTime)tmi.Value;
                        if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
                            tmi.Label = dt.ToString(lbstyle.TextFormat);
                        else
                            tmi.Label = chartAxis.GetDateTimeLabel(dt);
                        tmi.LabelIndex = tmi.Index;
                    }
                    break;
                default:
                    Type otype = layout.BaseValue.GetType();
                    double dbase = Convert.ToDouble(layout.BaseValue);
                    tmi.Value = dbase + (tmi.Index * layout.MajorSpacing);
                    if (ShowLabels == true)
                    {
                        if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
                            tmi.Label = String.Format("{0:" + lbstyle.TextFormat + "}", tmi.Value);
                        else
                            tmi.Label = tmi.Value.ToString();
                        tmi.LabelIndex = tmi.Index;
                    }
                    break;
            }
            if (ShowLabels == true && tmi.LabelIndex >= 0)
            {
                ChartControl chartControl = ChartControl;
                chartControl.DoGetTickmarkLabelEvent(chartAxis, tmi.Value, ref tmi.Label, ref tmi.LabelColor);
            }
        }
        #endregion
        #endregion
        #region GetTickmarkValue
        internal double GetTickmarkValue(ChartAxis chartAxis, TickmarkTick tick)
        {
            switch (chartAxis.ScaleType)
            {
                case ScaleType.DateTime:
                    return (chartAxis.GetDateTimeValue((DateTime)tick.Value));
                case ScaleType.Qualitative:
                    return ((int)tick.Value + TickmarkLayout.MajorSpacing / 2);
                default:
                    return (Convert.ToDouble(tick.Value) + TickmarkLayout.MajorSpacing / 2);
            }
        }
        #endregion
        #region GetLabelAngle
        protected virtual float GetLabelAngle()
        {
            float angle = LabelAngle % 180;
            ChartAxis chartAxis = Parent as ChartAxis;
            AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
            if (axisAlignment == AxisAlignment.Near)
            {
                if (angle < -90)
                    angle += 180;
            }
            else
            {
                if (angle > 0)
                    angle -= 180;
            }
            return (angle);
        }
        #endregion
        #region GetStartIndex
        internal virtual int GetStartIndex()
        {
            return (0);
        }
        internal int GetStartIndexEx(ScrollBarLite srollBar)
        {
            int offset = srollBar.Value;
            if (offset <= 0)
                return (0);
            int range = TickmarkLayout.MajorCount - 1;
            int smax = srollBar.Maximum;
            double dx = (((double)(offset * range)) / smax);
            return (int)(dx);
        }
        #endregion
        #region ArrangeTickmarks
        protected virtual void ArrangeTickmarks()
        {
        }
        #endregion
        #region ArrangeOverride
        protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
        {
            ChartAxis axis = Parent as ChartAxis;
            ChartXy chartXy = axis.Parent as ChartXy;
            if (TickmarkLayout.TickmarkStart != GetStartIndex())
            {
                Rectangle bounds = layoutInfo.LayoutBounds;
                layoutInfo.LayoutBounds = chartXy.BoundsRelative;
                chartXy.Measure(layoutInfo);
                chartXy.Arrange(layoutInfo);
                layoutInfo.LayoutBounds = bounds;
                if (layoutInfo.LayoutBoundsAdjusted == true)
                {
                    layoutInfo.LayoutBoundsAdjusted = false;
                    chartXy.InvalidateRender();
                }
            }
                
            ArrangeTickmarks();
        }
        #endregion
        #region GetTotalLabelHeight
        internal int GetTotalLabelHeight()
        {
            return (GetTotalLabelSize().Height);
        }
        #endregion
        #region GetTotalLabelWidth
        internal int GetTotalLabelWidth()
        {
            return (GetTotalLabelSize().Width);
        }
        #endregion
        #region GetTotalLabelSize
        internal Size GetTotalLabelSize()
        {
            _MaxLabelSize = new Size[2];
            _MaxLabelSize[0] = Size.Empty;
            _MaxLabelSize[1] = Size.Empty;
            TickmarkTick lastTmi = null;
            LabelsAreStaggered = false;
            float angle = GetLabelAngle();
            int minLabelGap = Dpi.Width(MinLabelGap);
            foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
            {
                if (tmi.LabelVisible == true && tmi.LabelPoint.IsEmpty == false && tmi.LabelIndex >= 0)
                {
                    int n = tmi.Index % 2;
                    if (tmi.LabelSize.Height > _MaxLabelSize[n].Height)
                        _MaxLabelSize[n].Height = tmi.LabelSize.Height;
                    if (tmi.LabelSize.Width > _MaxLabelSize[n].Width)
                        _MaxLabelSize[n].Width = tmi.LabelSize.Width;
                    if (StaggerLabels == true && LabelsAreStaggered == false)
                    {
                        if (lastTmi != null)
                        {
                            if (AxisOrientation == AxisOrientation.X)
                            {
                                if (angle % 180 == 0)
                                {
                                    if (lastTmi.LabelPoint.X +
                                        lastTmi.LabelSize.Width + minLabelGap > tmi.LabelPoint.X)
                                    {
                                        LabelsAreStaggered = true;
                                    }
                                }
                            }
                            else
                            {
                                if ((angle + 90) % 180 == 0)
                                {
                                    if (tmi.LabelPoint.Y +
                                        tmi.LabelSize.Height + minLabelGap > lastTmi.LabelPoint.Y)
                                    {
                                        LabelsAreStaggered = true;
                                    }
                                }
                            }
                        }
                        lastTmi = tmi;
                    }
                }
            }
            Size maxSize = Size.Empty;
            if (LabelsAreStaggered == true)
            {
                if (AxisOrientation == AxisOrientation.X)
                    maxSize.Height = _MaxLabelSize[0].Height + _MaxLabelSize[1].Height;
                else
                    maxSize.Width = _MaxLabelSize[0].Width + _MaxLabelSize[1].Width;
            }
            else
            {
                maxSize.Height = Math.Max(_MaxLabelSize[0].Height, _MaxLabelSize[1].Height);
                maxSize.Width = Math.Max(_MaxLabelSize[0].Width, _MaxLabelSize[1].Width);
            }
            return (maxSize);
        }
        #endregion
        #region Style handling
        #region ApplyStyles
        public override void ApplyStyles(BaseVisualStyle style)
        {
            base.ApplyStyles(style);
            TickmarkLabelVisualStyle lstyle = style as TickmarkLabelVisualStyle;
            if (lstyle != null)
            {
                ApplyParentStyles(lstyle, Parent as ChartContainer);
                lstyle.ApplyStyle(LabelVisualStyle);
                if (lstyle.Font == null)
                    lstyle.Font = SystemFonts.DefaultFont;
                if (lstyle.TextColor.IsEmpty)
                    lstyle.TextColor = Color.Black;
            }
        }
        #region ApplyParentStyles
        private void ApplyParentStyles(
            TickmarkLabelVisualStyle pstyle, ChartContainer item)
        {
            if (item != null)
            {
                ApplyParentStyles(pstyle, item.Parent as ChartContainer);
            }
            else
            {
                pstyle.ApplyStyle(ChartControl.BaseVisualStyles.TickmarkLabelVisualStyle);
                pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.TickmarkLabelVisualStyle);
            }
        }
        #endregion
        #endregion
        #region ClearEffectiveStyles
        protected override void ClearEffectiveStyles()
        {
            base.ClearEffectiveStyles();
            _EffectiveLabelStyle.InvalidateStyle();
        }
        #endregion
        #endregion
        #region Copy/CopyTo
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MajorTickmarks c = copy as MajorTickmarks;
            if (c != null)
            {
                base.CopyTo(c);
                c.AutoTickmarkLayout = AutoTickmarkLayout;
                c.LabelAngle = LabelAngle;
                c.LabelVisualStyle = (_LabelVisualStyle != null) ? LabelVisualStyle.Copy() : null;
                c.MinLabelGap = MinLabelGap;
                c.ShowLabels = ShowLabels;
                c.StaggerLabels = StaggerLabels;
            }
        }
        #endregion
        #region GetSerialData
        internal override SerialElementCollection GetSerialData(string serialName)
        {
            SerialElementCollection sec = new SerialElementCollection();
            if (serialName != null)
            {
                if (serialName.Equals("") == true)
                    serialName = "MajorTickmarks";
                sec.AddStartElement(serialName);
            }
            sec.AddValue("AutoTickmarkLayout", AutoTickmarkLayout, true);
            sec.AddValue("LabelAngle", LabelAngle, 0f);
            sec.AddValue("LabelSkip", LabelSkip, 0);
            if (_LabelVisualStyle != null && _LabelVisualStyle.IsEmpty == false)
                sec.AddElement(_LabelVisualStyle.GetSerialData("LabelVisualStyle"));
            sec.AddValue("MinLabelGap", MinLabelGap, 4);
            sec.AddValue("ShowLabels", ShowLabels, true);
            sec.AddValue("StaggerLabels", StaggerLabels, true);
            sec.AddElement(base.GetSerialData(null));
            if (serialName != null)
                sec.AddEndElement(serialName);
            return (sec);
        }
        #endregion
        #region PutSerialData
        #region ProcessValue
        internal override void ProcessValue(SerialElement se)
        {
            switch (se.Name)
            {
                case "AutoTickmarkLayout":
                    AutoTickmarkLayout = bool.Parse(se.StringValue);
                    break;
                case "LabelAngle":
                    LabelAngle = float.Parse(se.StringValue);
                    break;
                case "LabelSkip":
                    LabelSkip = int.Parse(se.StringValue);
                    break;
                case "MinLabelGap":
                    MinLabelGap = int.Parse(se.StringValue);
                    break;
                case "ShowLabels":
                    ShowLabels = bool.Parse(se.StringValue);
                    break;
                case "StaggerLabels":
                    StaggerLabels = bool.Parse(se.StringValue);
                    break;
                default:
                    base.ProcessValue(se);
                    break;
            }
        }
        #endregion
        #region ProcessCollection
        internal override void ProcessCollection(SerialElement se)
        {
            SerialElementCollection sec = se.Sec;
            switch (se.Name)
            {
                case "LabelVisualStyle":
                    sec.PutSerialData(LabelVisualStyle);
                    break;
                default:
                    base.ProcessCollection(se);
                    break;
            }
        }
        #endregion
        #endregion
        #region MajorStates
        [Flags]
        protected enum MajorStates : uint
        {
            AutoLayout = (1U << 0),
            ShowLabels = (1U << 1),
            StaggerLabels = (1U << 2),
            //--------
            LabelsAreStaggered = (1U << 3),
        }
        #region TestState
        protected bool TestState(MajorStates state)
        {
            return ((_MajorStates & state) == state);
        }
        #endregion
        #region SetState
        protected void SetState(MajorStates state, bool value)
        {
            if (value == true)
                _MajorStates |= state;
            else
                _MajorStates &= ~state;
        }
        #endregion
        #endregion
        #region IDisposable
        public override void Dispose()
        {
            LabelVisualStyle = null;
            base.Dispose();
        }
        #endregion
    }
    #endregion
    #endregion
    #region MinorTickmarks
    #region MinorTickmarksX
    /// 
    /// Represents a Minor tickmark on the X-Axis.
    /// 
    public class MinorTickmarksX : MinorTickmarks
    {
        public MinorTickmarksX()
            : base(AxisOrientation.X)
        {
        }
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            Rectangle bounds = Rectangle.Empty;
            if (TickmarkCount > 0)
            {
                bounds = layoutInfo.LayoutBounds;
                bounds.Height = Dpi.Height(GetMaxTickmarkLength(chartAxis, false));
            }
            BoundsRelative = bounds;
        }
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            TickmarkTick[] ticks = TickmarkLayout.Ticks;
            if (ticks.Length > 1)
            {
                ChartAxis chartAxis = Parent as ChartAxis;
                ChartTickmarkVisualStyle tstyle = EffectiveStyle;
                if (CanRenderTickmarks(tstyle) == true)
                {
                    Graphics g = renderInfo.Graphics;
                    Point pt = GetLocalAdjustedPoint(Point.Empty);
                    AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                    using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Width(tstyle.TickmarkThickness)))
                    {
                        int tlen = Dpi.Width(tstyle.TickmarkLength);
                        if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
                            (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
                            (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
                        {
                            // Bottom
                            RenderMarks(g, pen, chartAxis, pt, ticks, 0, tlen - 1);
                        }
                        if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
                            (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
                            (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
                        {
                            // Top
                            ChartXy chartXy = chartAxis.Parent as ChartXy;
                            if (axisAlignment == AxisAlignment.Near)
                            {
                                int n = 1;
                                if (chartAxis.EdgeAxis == true)
                                    n = chartXy.GetScBorderThickness(XyAlignment.Bottom);
                                RenderMarks(g, pen, chartAxis, pt, ticks, -(n + tlen), tlen - 1);
                            }
                            else
                            {
                                int n = 0;
                                RenderMarks(g, pen, chartAxis, pt, ticks, -(n + tlen), tlen - 1);
                            }
                        }
                    }
                }
            }
        }
        #region CanRenderTickmarks
        protected override bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
        {
            if (TickmarkCount <= 0)
                return (false);
            return (base.CanRenderTickmarks(tstyle));
        }
        #endregion
        #region RenderMarks
        private void RenderMarks(Graphics g,
            Pen pen, ChartAxis chartAxis, Point pt, TickmarkTick[] ticks, int voff, int len)
        {
            ChartAxis axis = Parent as ChartAxis;
            int minorTickCount = TickmarkLayout.MinorCount;
            for (int i = 0; i < ticks.Length - 1; i++)
            {
                TickmarkTick tick = ticks[i];
                Point pt1 = tick.TickPoint;
                pt1.Y += (pt.Y + voff);
                Point pt2 = pt1;
                pt2.Y += len;
                double dx = (double)(ticks[i + 1].TickPoint.X - tick.TickPoint.X) / (minorTickCount + 1);
                double ddx = dx;
                for (int j = 0; j < minorTickCount; j++)
                {
                    pt1.X = pt.X + (int)(tick.TickPoint.X + ddx);
                    pt2.X = pt1.X;
                    ddx += dx;
                    if (pt1.X >= chartAxis.AxisLineBounds.X - ScrollOffset.X &&
                        pt1.X < chartAxis.AxisLineBounds.Right - ScrollOffset.X)
                    {
                        if (pt1.Equals(pt2) == true)
                            pt1.Y--;
                        g.DrawLine(pen, pt1, pt2);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region Copy/CopyTo
        /// 
        /// Creates a copy of the chart element.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            MinorTickmarksX copy = new MinorTickmarksX();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MinorTickmarksX c = copy as MinorTickmarksX;
            if (c != null)
            {
                base.CopyTo(c);
            }
        }
        #endregion
    }
    #endregion
    #region MinorTickmarksY
    /// 
    /// Represents a Minor tickmark on the Y-Axis.
    /// 
    public class MinorTickmarksY : MinorTickmarks
    {
        public MinorTickmarksY()
            : base(AxisOrientation.Y)
        {
        }
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
            ChartAxis chartAxis = Parent as ChartAxis;
            Rectangle bounds = Rectangle.Empty;
            if (TickmarkCount > 0)
            {
                bounds = layoutInfo.LayoutBounds;
                bounds.Width = Dpi.Width(GetMaxTickmarkLength(chartAxis, false));
                if (chartAxis.AxisAlignment == AxisAlignment.Near)
                    bounds.X = layoutInfo.LayoutBounds.Right - bounds.Width;
            }
            BoundsRelative = bounds;
        }
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            TickmarkTick[] ticks = TickmarkLayout.Ticks;
            if (ticks.Length > 1)
            {
                ChartAxis chartAxis = Parent as ChartAxis;
                ChartTickmarkVisualStyle tstyle = EffectiveStyle;
                if (CanRenderTickmarks(tstyle) == true)
                {
                    Graphics g = renderInfo.Graphics;
                    AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
                    using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Height(tstyle.TickmarkThickness)))
                    {
                        int tlen = Dpi.Height(tstyle.TickmarkLength);
                        if (tstyle.TickmarkAlignment == LineAlignment.Center ||
                            (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
                            (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
                        {
                            // Right
                            RenderMarks(g, pen, chartAxis, ticks, 0, tlen - 1);
                        }
                        if (tstyle.TickmarkAlignment == LineAlignment.Center ||
                            (axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
                            (axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
                        {
                            // Left
                            ChartXy chartXy = chartAxis.Parent as ChartXy;
                            if (axisAlignment == AxisAlignment.Near)
                            {
                                int n = 1;
                                if (chartAxis.EdgeAxis == true)
                                    n = chartXy.GetScBorderThickness(XyAlignment.Right);
                                RenderMarks(g, pen, chartAxis, ticks, -(n + tlen), tlen - 1);
                            }
                            else
                            {
                                int n = 1;
                                RenderMarks(g, pen, chartAxis, ticks, -(n + tlen), tlen);
                            }
                        }
                    }
                }
            }
        }
        #region CanRenderTickmarks
        protected override bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
        {
            if (TickmarkCount <= 0)
                return (false);
            return (base.CanRenderTickmarks(tstyle));
        }
        #endregion
        #region RenderMarks
        private void RenderMarks(Graphics g,
            Pen pen, ChartAxis chartAxis, TickmarkTick[] ticks, int hoff, int len)
        {
            ChartAxis axis = Parent as ChartAxis;
            int minorTickCount = TickmarkLayout.MinorCount;
            Point pt = GetLocalAdjustedPoint(Point.Empty);
            for (int i = 0; i < ticks.Length - 1; i++)
            {
                TickmarkTick tick = ticks[i];
                Point pt1 = tick.TickPoint;
                pt1.X += (pt.X + hoff);
                Point pt2 = pt1;
                pt2.X += len;
                double dy = (double)(ticks[i + 1].TickPoint.Y - tick.TickPoint.Y) / (minorTickCount + 1);
                double ddy = dy;
                for (int j = 0; j < minorTickCount; j++)
                {
                    pt1.Y = pt.Y + (int)(tick.TickPoint.Y + ddy);
                    pt2.Y = pt1.Y;
                    ddy += dy;
                    if (pt1.Y >= chartAxis.AxisLineBounds.Y - ScrollOffset.Y &&
                        pt1.Y < chartAxis.AxisLineBounds.Bottom - ScrollOffset.Y)
                    {
                        g.DrawLine(pen, pt1, pt2);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region Copy/CopyTo
        /// 
        /// Creates a copy of the chart element.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            MinorTickmarksY copy = new MinorTickmarksY();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MinorTickmarksY c = copy as MinorTickmarksY;
            if (c != null)
            {
                base.CopyTo(c);
            }
        }
        #endregion
    }
    #endregion
    #region MinorTickmarks
    /// 
    /// Represents a Minor tickmark.
    /// 
    public class MinorTickmarks : ChartTickmarks
    {
        #region Private variables
        private int _TickmarkCount = 3;
        #endregion
        public MinorTickmarks(AxisOrientation orientation)
            : base(orientation)
        {
        }
        #region Public properties
        #region TickmarkCount
        ///
        /// Gets or sets the number of Tickmarks presented between Majortickmarks.
        ///
        [DefaultValue(3), Category("Layout")]
        [Description("Indicates the number of Tickmarks presented between Majortickmarks.")]
        public int TickmarkCount
        {
            get { return (_TickmarkCount); }
            set
            {
                if (value != _TickmarkCount)
                {
                    _TickmarkCount = value;
                    OnPropertyChangedEx("TickmarkCount", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region CopyTo
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            MinorTickmarks c = copy as MinorTickmarks;
            if (c != null)
            {
                base.CopyTo(c);
                c.TickmarkCount = TickmarkCount;
            }
        }
        #endregion
        #region GetSerialData
        internal override SerialElementCollection GetSerialData(string serialName)
        {
            SerialElementCollection sec = new SerialElementCollection();
            if (serialName != null)
            {
                if (serialName.Equals("") == true)
                    serialName = "MinorTickmarks";
                sec.AddStartElement(serialName);
            }
            sec.AddElement(base.GetSerialData(null));
            sec.AddValue("TickmarkCount", TickmarkCount, 3);
            if (serialName != null)
                sec.AddEndElement(serialName);
            return (sec);
        }
        #endregion
        #region PutSerialData
        #region ProcessValue
        internal override void ProcessValue(SerialElement se)
        {
            switch (se.Name)
            {
                case "TickmarkCount":
                    TickmarkCount = int.Parse(se.StringValue);
                    break;
                default:
                    base.ProcessValue(se);
                    break;
            }
        }
        #endregion
        #endregion
    }
    #endregion
    #endregion
    #region ChartTickmarks
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public abstract class ChartTickmarks : ChartVisualElement
    {
        #region Private variables
        private States _States;
        private AxisOrientation _AxisOrientation;
        private Rectangle _TickmarkBounds;
        private TickmarkLayout _TickmarkLayout;
        private ChartTickmarkVisualStyle _ChartTickmarkVisualStyle;
        private EffectiveStyle _EffectiveStyle;
        #endregion
        public ChartTickmarks(AxisOrientation orientation)
        {
            _AxisOrientation = orientation;
            InitDefaultStates();
            _EffectiveStyle = new EffectiveStyle(this);
            Visible = true;
        }
        #region InitDefaultStates
        private void InitDefaultStates()
        {
        }
        #endregion
        #region Public properties
        #region AxisOrientation
        ///
        /// Gets the axis orientation (X/Y).
        ///
        [Browsable(false)]
        [Description("Indicates the axis orientation (X/Y).")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public AxisOrientation AxisOrientation
        {
            get { return (_AxisOrientation); }
        }
        #endregion
        #region EffectiveStyle
        /// 
        /// Gets a reference to the Tickmark's Effective (cached, composite) style.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Indicates a reference to the Tickmark's Effective (cached, composite) style.")]
        public ChartTickmarkVisualStyle EffectiveStyle
        {
            get { return (_EffectiveStyle.Style); }
        }
        #endregion
        #region ChartTickmarkVisualStyle
        /// 
        /// Gets or sets the visual styles for the Tickmarks.
        /// 
        [Category("Style")]
        [Description("Indicates the visual styles for the Tickmarks.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartTickmarkVisualStyle ChartTickmarkVisualStyle
        {
            get
            {
                if (_ChartTickmarkVisualStyle == null)
                {
                    _ChartTickmarkVisualStyle = new ChartTickmarkVisualStyle();
                    StyleVisualChangeHandler(null, _ChartTickmarkVisualStyle);
                }
                return (_ChartTickmarkVisualStyle);
            }
            set
            {
                if (_ChartTickmarkVisualStyle != value)
                {
                    ChartTickmarkVisualStyle oldValue = _ChartTickmarkVisualStyle;
                    _ChartTickmarkVisualStyle = value;
                    OnVisualStyleChanged("ChartTickmarkVisualStyle", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region TickmarkBounds
        internal Rectangle TickmarkBounds
        {
            get { return (_TickmarkBounds); }
            set { _TickmarkBounds = value; }
        }
        #endregion
        #region TickmarkLayout
        internal TickmarkLayout TickmarkLayout
        {
            get { return (_TickmarkLayout); }
            set { _TickmarkLayout = value; }
        }
        #endregion
        #endregion
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
        }
        #endregion
        #region ArrangeOverride
        protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
        {
        }
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
        }
        #endregion
        #region CanRenderTickmarks
        protected virtual bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
        {
            if (Visible == false || tstyle.TickmarkThickness <= 0 || tstyle.TickmarkColor.IsEmpty == true)
                return (false);
            return (true);
        }
        #endregion
        #region Render
        internal override void Render(ChartRenderInfo renderInfo)
        {
            if (Displayed == true)
                RenderOverride(renderInfo);
        }
        #endregion
        #region GetMaxTickmarkLength
        internal int GetMaxTickmarkLength(ChartAxis chartAxis, bool inner)
        {
            int length = (inner == false) ? 4 : 0;
            if (Visible == true)
            {
                ChartTickmarkVisualStyle tstyle = EffectiveStyle;
                if (chartAxis.EdgeAxis == false)
                {
                    length = tstyle.TickmarkLength;
                }
                else
                {
                    switch (tstyle.TickmarkAlignment)
                    {
                        case LineAlignment.Near:
                            if (inner == true)
                                length = tstyle.TickmarkLength;
                            break;
                        case LineAlignment.Center:
                            length = tstyle.TickmarkLength;
                            break;
                        default:
                            if (inner == false)
                                length = tstyle.TickmarkLength;
                            break;
                    }
                }
            }
            return (length);
        }
        #endregion
        #region GetLocalAdjustedBounds
        internal Rectangle GetLocalAdjustedBounds(Rectangle bounds)
        {
            bounds.Location = GetLocalAdjustedPoint(bounds.Location);
            return (bounds);
        }
        #endregion
        #region GetLocalAdjustedPoint
        internal Point GetLocalAdjustedPoint(Point pt)
        {
            ChartAxis axis = Parent as ChartAxis;
            ChartXy chartXy = axis.Parent as ChartXy;
            if (chartXy != null)
            {
                pt.X -= ScrollOffset.X;
                pt.Y -= ScrollOffset.Y;
                if (_AxisOrientation == AxisOrientation.X)
                {
                    pt.X -= chartXy.HScrollOffset;
                }
                else
                {
                    if (chartXy.VScrollBar.Inverted == true)
                        pt.Y += chartXy.VScrollOffset;
                    else
                        pt.Y -= chartXy.VScrollOffset;
                }
            }
            return (pt);
        }
        #endregion
        #region Style handling
        #region ApplyStyles
        public override void ApplyStyles(BaseVisualStyle style)
        {
            ChartTickmarkVisualStyle tstyle = style as ChartTickmarkVisualStyle;
            if (tstyle != null)
            {
                ApplyParentStyles(tstyle, Parent as ChartContainer);
                tstyle.ApplyStyle(ChartTickmarkVisualStyle);
                if (tstyle.TickmarkColor.IsEmpty == true)
                    tstyle.TickmarkColor = Color.Gray;
                if (tstyle.TickmarkThickness < 0)
                    tstyle.TickmarkThickness = 1;
                if (tstyle.TickmarkLength < 0)
                {
                    if (this is MajorTickmarks)
                        tstyle.TickmarkLength = 5;
                    else
                        tstyle.TickmarkLength = 2;
                }
                if (tstyle.TickmarkAlignment == LineAlignment.NotSet)
                    tstyle.TickmarkAlignment = LineAlignment.Far;
            }
        }
        #region ApplyParentStyles
        private void ApplyParentStyles(
            ChartTickmarkVisualStyle pstyle, ChartContainer item)
        {
            if (item != null)
            {
                ApplyParentStyles(pstyle, item.Parent as ChartContainer);
                if (item is ChartPanel)
                {
                    pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartTickmarkVisualStyle);
                }
            }
            else
            {
                pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartTickmarkVisualStyle);
                pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartTickmarkVisualStyle);
            }
        }
        #endregion
        #endregion
        #region InvalidateStyle
        ///
        ///Invalidate the cached Style definition
        ///
        public void InvalidateStyle()
        {
            ClearEffectiveStyles();
        }
        #endregion
        #region ClearEffectiveStyles
        protected override void ClearEffectiveStyles()
        {
            if (_EffectiveStyle.InvalidateStyle() == true)
                InvalidateLayout();
        }
        #endregion
        #endregion
        #region CopyTo
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartTickmarks c = copy as ChartTickmarks;
            if (c != null)
            {
                base.CopyTo(c);
                c.ChartTickmarkVisualStyle = 
                    (_ChartTickmarkVisualStyle != null) ? ChartTickmarkVisualStyle.Copy() : null;
            }
        }
        #endregion
        #region GetSerialData
        internal override SerialElementCollection GetSerialData(string serialName)
        {
            SerialElementCollection sec = new SerialElementCollection();
            if (serialName != null)
            {
                if (serialName.Equals("") == true)
                    serialName = "ChartTickmarks";
                sec.AddStartElement(serialName);
            }
            if (_ChartTickmarkVisualStyle != null && _ChartTickmarkVisualStyle.IsEmpty == false)
                sec.AddElement(_ChartTickmarkVisualStyle.GetSerialData("ChartTickmarkVisualStyle"));
            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 "ChartTickmarkVisualStyle":
                    sec.PutSerialData(ChartTickmarkVisualStyle);
                    break;
                default:
                    base.ProcessCollection(se);
                    break;
            }
        }
        #endregion
        #endregion
        #region States
        [Flags]
        protected enum States : uint
        {
        }
        #region TestState
        protected bool TestState(States state)
        {
            return ((_States & state) == state);
        }
        #endregion
        #region SetState
        protected void SetState(States state, bool value)
        {
            if (value == true)
                _States |= state;
            else
                _States &= ~state;
        }
        #endregion
        #endregion
    }
    #endregion
}