//-------------------------------------------------------------
// 
//   Copyright © Microsoft Corporation. All Rights Reserved.
// 
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		ChartElement.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
//
//	Classes:	ChartHelper
//
//  Purpose:	The chart element is base class for the big number 
//				of classes. It stores common methods and data.
//
//	Reviewed:	GS - August 2, 2002
//				AG - August 8, 2002
//              AG - Microsoft 16, 2007
//
//===================================================================
#region Used namespaces
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Collections.ObjectModel;
#endregion
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
	#region Enumerations
		/// 
		/// An enumeration that specifies a label alignment.
		/// 
		[
		Flags
		]
		public enum LabelAlignmentStyles
		{
			/// 
		        /// Label is aligned to the top of the data point.
			/// 
			Top = 1,
			/// 
                        /// Label is aligned to the bottom of the data point.
			/// 
			Bottom = 2,
			/// 
                        /// Label is aligned to the right of the data point.
			/// 
			Right = 4,
			/// 
                        /// Label is aligned to the left of the data point.
			/// 
			Left = 8,
			/// 
                        /// Label is aligned to the top-left corner of the data point.
			/// 
			TopLeft = 16,
			/// 
                        /// Label is aligned to the top-right corner of the data point.
			/// 
			TopRight = 32,
			/// 
                        /// Label is aligned to the bottom-left of the data point.
			/// 
			BottomLeft = 64,
			/// 
                        /// Label is aligned to the bottom-right of the data point.
			/// 
			BottomRight = 128,
			/// 
                        /// Label is aligned to the center of the data point.
			/// 
			Center = 256,
		}
	/// 
	/// An enumeration of chart types.
	/// 
	public enum SeriesChartType
	{	
		/// 
		/// Point chart type.
		/// 
		Point,
		/// 
		/// FastPoint chart type.
		/// 
		FastPoint,
		/// 
		/// Bubble chart type.
		/// 
		Bubble,
		/// 
		/// Line chart type.
		/// 
		Line,
		/// 
		/// Spline chart type.
		/// 
		Spline,
		/// 
		/// StepLine chart type.
		/// 
		StepLine,
		/// 
		/// FastLine chart type.
		/// 
		FastLine,
		/// 
		/// Bar chart type.
		/// 
		Bar,
		/// 
		/// Stacked bar chart type.
		/// 
		StackedBar,
		/// 
		/// Hundred percent stacked bar chart type.
		/// 
		StackedBar100,
		/// 
		/// Column chart type.
		/// 
		Column,
		/// 
		/// Stacked column chart type.
		/// 
		StackedColumn,
		/// 
		/// Hundred percent stacked column chart type.
		/// 
		StackedColumn100,
		/// 
		/// Area chart type.
		/// 
		Area,
		/// 
		/// Spline area chart type.
		/// 
		SplineArea,
		/// 
		/// Stacked area chart type.
		/// 
		StackedArea,
		/// 
		/// Hundred percent stacked area chart type.
		/// 
		StackedArea100,
		/// 
		/// Pie chart type.
		/// 
		Pie,
		/// 
		/// Doughnut chart type.
		/// 
		Doughnut,
		/// 
		/// Stock chart type.
		/// 
		Stock,
		/// 
		/// CandleStick chart type.
		/// 
		Candlestick,
		/// 
		/// Range chart type.
		/// 
		Range,
		/// 
		/// Spline range chart type.
		/// 
		SplineRange,
		/// 
		/// RangeBar chart type.
		/// 
		RangeBar,
		/// 
		/// Range column chart type.
		/// 
		RangeColumn,
		/// 
		/// Radar chart type.
		/// 
		Radar,
		/// 
		/// Polar chart type.
		/// 
		Polar,
		/// 
		/// Error bar chart type.
		/// 
		ErrorBar,
		/// 
		/// Box plot chart type.
		/// 
		BoxPlot,
		/// 
		/// Renko chart type.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Renko")]
        Renko,
		/// 
		/// ThreeLineBreak chart type.
		/// 
		ThreeLineBreak,
		/// 
		/// Kagi chart type.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Kagi")]
        Kagi,
		/// 
		/// PointAndFigure chart type.
		/// 
		PointAndFigure,
		/// 
		/// Funnel chart type.
		/// 
		Funnel,
		/// 
		/// Pyramid chart type.
		/// 
		Pyramid,
	}
	/// 
	/// Axis Arrow orientation
	/// 
	internal enum ArrowOrientation
	{
		/// 
		/// Arrow direction is Right - Left
		/// 
		Left, 
		/// 
		/// Arrow direction is Left - Right
		/// 
		Right, 
		/// 
		/// Arrow direction is Bottom - Top
		/// 
		Top,
		/// 
		/// Arrow direction is Top - Bottom
		/// 
		Bottom
	}
	/// 
	/// An enumeration of image alignment.
	/// 
	public enum ChartImageAlignmentStyle
	{
		/// 
        /// The mage is aligned to the top left corner of the chart element.
		/// 
		TopLeft,
		/// 
        /// The image is aligned to the top boundary of the chart element.
		/// 
		Top,
		/// 
        /// The image is aligned to the top right corner of the chart element.
		/// 
		TopRight,
		/// 
        /// The image is aligned to the right boundary of the chart element.
		/// 
		Right,
		/// 
        /// The image is aligned to the bottom right corner of the chart element.
		/// 
		BottomRight,
		/// 
        /// The image is aligned to the bottom boundary of the chart element.
		/// 
		Bottom,
		/// 
        /// The image is aligned to the bottom left corner of the chart element.
		/// 
		BottomLeft,
		/// 
        /// The image is aligned to the left boundary of the chart element.
		/// 
		Left,
		/// 
        /// The image is aligned in the center of the chart element.
		/// 
		Center
	};
	/// 
    /// An enumeration that specifies a background image drawing mode.
	/// 
	public enum ChartImageWrapMode
	{
		/// 
        /// Background image is scaled to fit the entire chart element.
		/// 		
		Scaled = WrapMode.Clamp,
		/// 
        /// Background image is tiled to fit the entire chart element.
		/// 
		Tile = WrapMode.Tile,
		/// 
        /// Every other tiled image is reversed around the X-axis.
		/// 
		TileFlipX = WrapMode.TileFlipX,
		/// 
        /// Every other tiled image is reversed around the X-axis and Y-axis.
		/// 
		TileFlipXY = WrapMode.TileFlipXY,
		/// 
        /// Every other tiled image is reversed around the Y-axis.
		/// 
		TileFlipY = WrapMode.TileFlipY,
		/// 
        /// Background image is not scaled.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unscaled")]
        Unscaled = 100
	};
	/// 
    /// An enumeration that specifies the state of an axis.
	/// 
	public enum AxisEnabled
	{
		/// 
        /// The axis is only enabled if it used to plot a Series.
		/// 
		Auto,
		
		/// 
		/// The axis is always enabled.
		/// 
		True,
		
		/// 
		/// The axis is never enabled.
		/// 
		False
	};
	/// 
	/// An enumeration of units of measurement of an interval.
	/// 
	public enum DateTimeIntervalType
	{
		/// 
        /// Automatically determined by the Chart control.
		/// 
		Auto, 
		
		/// 
		/// The interval is numerical.
		/// 
		Number, 
		
		/// 
		/// The interval is years.
		/// 
		Years, 
		
		/// 
		/// The interval is months.
		/// 
		Months, 
		
		/// 
        /// The interval is weeks.
		/// 
		Weeks, 
		
		/// 
		/// The interval is days.
		/// 
		Days, 
		
		/// 
		/// The interval is hours.
		/// 
		Hours, 
		
		/// 
		/// The interval is minutes.
		/// 
		Minutes,
		/// 
		/// The interval is seconds.
		/// 
		Seconds,
		
		/// 
		/// The interval is milliseconds.
		/// 
		Milliseconds,
		/// 
		/// The interval type is not defined.
		/// 
		NotSet, 
	}
	/// 
    /// An enumeration that specifies value types for various chart properties
	/// 
	public enum ChartValueType
	{ 
		/// 
        /// Property type is set automatically by the Chart control.
		/// 
		Auto, 
		
		/// 
		/// Double value.
		/// 
		Double, 
		
		/// 
		/// Single value.
		/// 
		Single, 
		
		/// 
		/// Int32 value.
		/// 
		Int32, 
		
		/// 
		/// Int64 value.
		/// 
		Int64, 
		
		/// 
		/// UInt32 value.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
            Justification = "These names are patterned after the standard CLR types for consistency")]
		UInt32, 
		
		/// 
		/// UInt64 value.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
            Justification = "These names are patterned after the standard CLR types for consistency")]
		UInt64, 
		
		/// 
		/// String value.
		/// 
		String, 
		
		/// 
		/// DateTime value.
		/// 
		DateTime,
		/// 
		/// Date portion of the DateTime value.
		/// 
		Date,
		/// 
		/// Time portion of the DateTime value.
		/// 
		Time,
        /// 
		/// DateTime with offset
		/// 
		DateTimeOffset
	};
	/// 
	/// An enumeration that specifies a hatching style.
	/// 
	public enum ChartHatchStyle 
	{ 
		/// 
		/// No hatching style.
		/// 
		None, 
		/// 
		/// Backward diagonal style.
		/// 
		BackwardDiagonal, 
		/// 
		/// Cross style.
		/// 
		Cross, 
		/// 
		/// Dark downward diagonal style.
		/// 
		DarkDownwardDiagonal, 
		/// 
		/// Dark horizontal style.
		/// 
		DarkHorizontal, 
		/// 
		/// Dark upward diagonal style.
		/// 
		DarkUpwardDiagonal, 
		/// 
		/// Dark vertical style.
		/// 
		DarkVertical, 
		/// 
		/// Dashed downward diagonal style.
		/// 
		DashedDownwardDiagonal,
		/// 
		/// Dashed horizontal style.
		/// 
		DashedHorizontal, 
		/// 
		/// Dashed upward diagonal style.
		/// 
		DashedUpwardDiagonal, 
		/// 
		/// Dashed vertical style.
		/// 
		DashedVertical, 
		/// 
		/// Diagonal brick style.
		/// 
		DiagonalBrick, 
		/// 
		/// Diagonal cross style.
		/// 
		DiagonalCross, 
		/// 
		/// Divot style.
		/// 
		Divot, 
		/// 
		/// Dotted diamond style.
		/// 
		DottedDiamond, 
		/// 
		/// Dotted grid style.
 		/// 
		DottedGrid, 
		/// 
		/// Forward diagonal style.
		/// 
		ForwardDiagonal, 
		/// 
		/// Horizontal style.
		/// 
		Horizontal, 
		/// 
		/// Horizontal brick style.
		/// 
		HorizontalBrick, 
		/// 
		/// Large checker board style.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
        LargeCheckerBoard, 
		/// 
		/// Large confetti style.
		/// 
		LargeConfetti, 
		/// 
		/// Large grid style.
		/// 
		LargeGrid, 
		/// 
		/// Light downward diagonal style.
		/// 
		LightDownwardDiagonal, 
		/// 
		/// Light horizontal style.
		/// 
		LightHorizontal, 
		/// 
		/// Light upward diagonal style.
		/// 
		LightUpwardDiagonal, 
		/// 
		/// Light vertical style.
		/// 
		LightVertical, 
		/// 
		/// Narrow horizontal style.
		/// 
		NarrowHorizontal, 
		/// 
		/// Narrow vertical style.
		/// 
		NarrowVertical, 
		/// 
		/// Outlined diamond style.
		/// 
		OutlinedDiamond, 
		/// 
		/// Percent05 style.
		/// 
		Percent05, 
		/// 
		/// Percent10 style.
		/// 
		Percent10, 
		/// 
		/// Percent20 style.
		/// 
		Percent20, 
		/// 
		/// Percent25 style.
		/// 
		Percent25, 
		/// 
		/// Percent30 style.
		/// 
		Percent30, 
		/// 
		/// Percent40 style.
		/// 
		Percent40, 
		/// 
		/// Percent50 style.
		/// 
		Percent50, 
		/// 
		/// Percent60 style.
		/// 
		Percent60, 
		/// 
		/// Percent70 style.
		/// 
		Percent70, 
		/// 
		/// Percent75 style.
		/// 
		Percent75, 
		/// 
		/// Percent80 style.
		/// 
		Percent80, 
		/// 
		/// Percent90 style.
		/// 
		Percent90, 
		/// 
		/// Plaid style.
		/// 
		Plaid, 
		/// 
		/// Shingle style.
		/// 
		Shingle, 
		/// 
		/// Small checker board style.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
        SmallCheckerBoard,
		/// 
		/// Small confetti style.
		/// 
		SmallConfetti, 
		/// 
		/// Small grid style.
		/// 
		SmallGrid, 
		/// 
		/// Solid diamond style.
		/// 
		SolidDiamond, 
		/// 
		/// Sphere style.
		/// 
		Sphere, 
		/// 
		/// Trellis style.
		/// 
		Trellis, 
		/// 
		/// Vertical style.
		/// 
		Vertical, 
		/// 
		/// Wave style.
		/// 
		Wave, 
		/// 
		/// Weave style.
		/// 
		Weave, 
		/// 
		/// Wide downward diagonal style.
		/// 
		WideDownwardDiagonal, 
		/// 
		/// Wide upward diagonal style.
		/// 
		WideUpwardDiagonal, 
		/// 
		/// ZigZag style.
		/// 
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ZigZag")]
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zig")]
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zag")]
        ZigZag
	};
	/// 
    /// An enumeration that specifies the level of anti-aliasing quality.
	/// 
	public enum TextAntiAliasingQuality
	{
		/// 
		/// Normal anti-aliasing quality.
		/// 
		Normal,
		/// 
		/// High anti-aliasing quality.
		/// 
		High,
		/// 
		/// System default anti-aliasing quality.
		/// 
		SystemDefault
	}
	/// 
	/// An enumeration of anti-aliasing flags.
	/// 
	[Flags]
	public enum AntiAliasingStyles
	{
		/// 
		/// No anti-aliasing.
		/// 
		None = 0,
		/// 
		/// Use anti-aliasing when drawing text.
		/// 
		Text = 1,
		/// 
		/// Use anti-aliasing when drawing grahics primitives (e.g. lines, rectangle)
		/// 
		Graphics = 2,
		/// 
		/// Use anti-alias for everything.
		/// 
		All = Text | Graphics
	};
	
	/// 
	/// An enumeration of marker styles.
	/// 
	public enum MarkerStyle
	{
		/// 
        /// No marker is displayed for the series/data point.
		/// 
		None = 0, 
		/// 
        /// A square marker is displayed.
		/// 
		Square = 1, 
		/// 
        /// A circle marker is displayed.
		/// 
		Circle = 2, 
		/// 
        /// A diamond-shaped marker is displayed.
		/// 
		Diamond = 3, 
		/// 
        /// A triangular marker is displayed.
		/// 
		Triangle = 4, 
		/// 
        /// A cross-shaped marker is displayed.
		/// 
		Cross = 5,
		/// 
        /// A 4-point star-shaped marker is displayed.
		/// 
		Star4 = 6,
		/// 
        /// A 5-point star-shaped marker is displayed.
		/// 
		Star5 = 7,
		/// 
        /// A 6-point star-shaped marker is displayed.
		/// 
		Star6 = 8,
		/// 
        /// A 10-point star-shaped marker is displayed.
		/// 
		Star10 = 9
	};
	/// 
	/// An enumeration of gradient styles.
	/// 
	public enum GradientStyle
	{
		/// 
        /// No gradient is used.
		/// 
		None, 
		
		/// 
        /// Gradient is applied from left to right.
		/// 
		LeftRight, 
		
		/// 
        /// Gradient is applied from top to bottom.
		/// 
		TopBottom, 
		
		/// 
        /// Gradient is applied from the center outwards.
		/// 
		Center, 
		
		/// 
        /// Gradient is applied diagonally from left to right.
		/// 
		DiagonalLeft, 
		
		/// 
        /// Gradient is applied diagonally from right to left.
		/// 
		DiagonalRight, 
		
		/// 
        /// Gradient is applied horizontally from the center outwards.
		/// 
		HorizontalCenter, 
		
		/// 
        /// Gradient is applied vertically from the center outwards.
		/// 
		VerticalCenter
	};
	#endregion
    
    #region ChartElement
    /// 
    /// Common chart helper methods used across different chart elements.
    /// 
    internal class ChartHelper
    {
        #region Fields
        /// 
        /// Maximum number of grid lines per Axis
        /// 
        internal const int MaxNumOfGridlines = 10000;
        #endregion // Fields
        #region Constructor
        /// 
        /// Private constructor to avoid instantiating the class
        /// 
        private ChartHelper() { }
        #endregion // Constructor
        #region Methods
        /// 
		/// Adjust the beginnin of the first interval depending on the type and size.
		/// 
		/// Original start point.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// Adjusted interval start position as double.
        internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type)
		{
			return AlignIntervalStart(start, intervalSize, type, null);
		}
		/// 
		/// Adjust the beginnin of the first interval depending on the type and size.
		/// 
		/// Original start point.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// First series connected to the axis.
		/// Adjusted interval start position as double.
        internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type, Series series)
		{
			return AlignIntervalStart( start, intervalSize, type, series, true );
		}
		/// 
		/// Adjust the beginnin of the first interval depending on the type and size.
		/// 
		/// Original start point.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// First series connected to the axis.
		/// Interval is used for major gridlines or tickmarks.
		/// Adjusted interval start position as double.
        internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type, Series series, bool majorInterval)
		{
			// Special case for indexed series
			if(series != null && series.IsXValueIndexed)
			{
				if(type == DateTimeIntervalType.Auto ||
					type == DateTimeIntervalType.Number)
				{
					if( majorInterval )
					{
						return 1;
					}
					else
					{
						return 0;
					}
				}
					
				return -(series.Points.Count + 1);
			}
			// Non indexed series
			else
			{
				// Do not adjust start position for these interval type
				if(type == DateTimeIntervalType.Auto ||
					type == DateTimeIntervalType.Number)
				{
					return start;
				}
				// Get the beginning of the interval depending on type
				DateTime	newStartDate = DateTime.FromOADate(start);
				// Adjust the months interval depending on size
				if(intervalSize > 0.0 && intervalSize != 1.0)
				{
					if(type == DateTimeIntervalType.Months && intervalSize <= 12.0 && intervalSize > 1)
					{
						// Make sure that the beginning is aligned correctly for cases
						// like quarters and half years
						DateTime	resultDate = newStartDate;
						DateTime	sizeAdjustedDate = new DateTime(newStartDate.Year, 1, 1, 0, 0, 0);
						while(sizeAdjustedDate < newStartDate)
						{
							resultDate = sizeAdjustedDate;
							sizeAdjustedDate = sizeAdjustedDate.AddMonths((int)intervalSize);
						}
						newStartDate = resultDate;
						return newStartDate.ToOADate();
					}
				}
				// Check interval type
				switch(type)
				{
					case(DateTimeIntervalType.Years):
						int year = (int)((int)(newStartDate.Year / intervalSize) * intervalSize);
						if(year <= 0)
						{
							year = 1;
						}
						newStartDate = new DateTime(year, 
							1, 1, 0, 0, 0);
						break;
					case(DateTimeIntervalType.Months):
						int month = (int)((int)(newStartDate.Month / intervalSize) * intervalSize);
						if(month <= 0)
						{
							month = 1;
						}
						newStartDate = new DateTime(newStartDate.Year, 
							month, 1, 0, 0, 0);
						break;
					case(DateTimeIntervalType.Days):
						int day = (int)((int)(newStartDate.Day / intervalSize) * intervalSize);
						if(day <= 0)
						{
							day = 1;
						}
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, day, 0, 0, 0);
						break;
					case(DateTimeIntervalType.Hours):
						int hour = (int)((int)(newStartDate.Hour / intervalSize) * intervalSize);
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, newStartDate.Day, hour, 0, 0);
						break;
					case(DateTimeIntervalType.Minutes):
						int minute = (int)((int)(newStartDate.Minute / intervalSize) * intervalSize);
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, 
							newStartDate.Day, 
							newStartDate.Hour, 
							minute, 
							0);
						break;
					case(DateTimeIntervalType.Seconds):
						int second = (int)((int)(newStartDate.Second / intervalSize) * intervalSize);
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, 
							newStartDate.Day, 
							newStartDate.Hour, 
							newStartDate.Minute, 
							second, 
							0);
						break;
					case(DateTimeIntervalType.Milliseconds):
						int milliseconds = (int)((int)(newStartDate.Millisecond / intervalSize) * intervalSize);
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, 
							newStartDate.Day, 
							newStartDate.Hour, 
							newStartDate.Minute, 
							newStartDate.Second, 
							milliseconds);
						break;
					case(DateTimeIntervalType.Weeks):
                        // NOTE: Code below was changed to fix issue #5962
                        // Elements that have interval set to weeks should be aligned to the 
                        // nearest Monday no matter how many weeks is the interval.
						//newStartDate = newStartDate.AddDays(-((int)newStartDate.DayOfWeek * intervalSize));
                        newStartDate = newStartDate.AddDays(-((int)newStartDate.DayOfWeek));
						newStartDate = new DateTime(newStartDate.Year, 
							newStartDate.Month, newStartDate.Day, 0, 0, 0);
						break;
				}
				return newStartDate.ToOADate();
			}
		}
		/// 
		/// Gets interval size as double number.
		/// 
		/// Current value.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// Interval size as double.
        internal static double GetIntervalSize(double current, double interval, DateTimeIntervalType type)
		{
			return GetIntervalSize(
				current, 
				interval, 
				type, 
				null, 
				0, 
				DateTimeIntervalType.Number, 
				true, 
				true);
		}
		/// 
		/// Gets interval size as double number.
		/// 
		/// Current value.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// First series connected to the axis.
		/// Offset size.
		/// Offset type(Month, Year, ...).
		/// Force Integer indexed
		/// Interval size as double.
        internal static double GetIntervalSize(
			double current, 
			double interval, 
			DateTimeIntervalType type, 
			Series series,
			double intervalOffset, 
			DateTimeIntervalType intervalOffsetType,
			bool forceIntIndex)
		{
			return GetIntervalSize(
				current, 
				interval, 
				type, 
				series,
				intervalOffset, 
				intervalOffsetType,
				forceIntIndex,
				true);
		}
		/// 
		/// Gets interval size as double number.
		/// 
		/// Current value.
		/// Interval size.
		/// AxisName of the interval (Month, Year, ...).
		/// First series connected to the axis.
		/// Offset size.
		/// Offset type(Month, Year, ...).
		/// Force Integer indexed
		/// Force Integer indexed
		/// Interval size as double.
        internal static double GetIntervalSize(
			double current, 
			double interval, 
			DateTimeIntervalType type, 
			Series series,
			double intervalOffset, 
			DateTimeIntervalType intervalOffsetType,
			bool forceIntIndex,
			bool forceAbsInterval)
		{
			// AxisName is not date.
			if( type == DateTimeIntervalType.Number || type == DateTimeIntervalType.Auto )
			{
				return interval;
			}
			// Special case for indexed series
			if(series != null && series.IsXValueIndexed)
			{
				// Check point index
				int pointIndex = (int)Math.Ceiling(current - 1);
				if(pointIndex < 0)
				{
					pointIndex = 0;
				}
				if(pointIndex >= series.Points.Count || series.Points.Count <= 1)
				{
					return interval;
				}
				// Get starting and ending values of the closest interval
				double		adjuster = 0;
				double		xValue = series.Points[pointIndex].XValue;
				xValue = AlignIntervalStart(xValue, 1, type, null);
				double		xEndValue = xValue + GetIntervalSize(xValue, interval, type);
				xEndValue += GetIntervalSize(xEndValue, intervalOffset, intervalOffsetType);
				xValue += GetIntervalSize(xValue, intervalOffset, intervalOffsetType);
				if(intervalOffset < 0)
				{
					xValue = xValue + GetIntervalSize(xValue, interval, type);
					xEndValue = xEndValue + GetIntervalSize(xEndValue, interval, type);
				}
				// The first point in the series
				if(pointIndex == 0 && current < 0)
				{
					// Round the first point value depending on the interval type
					DateTime	dateValue = DateTime.FromOADate(series.Points[pointIndex].XValue);
					DateTime	roundedDateValue = dateValue;
					switch(type)
					{
						case(DateTimeIntervalType.Years): // Ignore hours,...
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, dateValue.Day, 0, 0, 0);
							break;
						case(DateTimeIntervalType.Months): // Ignore hours,...
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, dateValue.Day, 0, 0, 0);
							break;
						case(DateTimeIntervalType.Days): // Ignore hours,...
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, dateValue.Day, 0, 0, 0);
							break;
						case(DateTimeIntervalType.Hours): //
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, dateValue.Day, dateValue.Hour, 
								dateValue.Minute, 0);
							break;
						case(DateTimeIntervalType.Minutes):
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, 
								dateValue.Day, 
								dateValue.Hour, 
								dateValue.Minute, 
								dateValue.Second);
							break;
						case(DateTimeIntervalType.Seconds):
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, 
								dateValue.Day, 
								dateValue.Hour, 
								dateValue.Minute, 
								dateValue.Second,
								0);
							break;
						case(DateTimeIntervalType.Weeks):
							roundedDateValue = new DateTime(dateValue.Year, 
								dateValue.Month, dateValue.Day, 0, 0, 0);
							break;
					}
					// The first point value is exactly on the interval boundaries
					if(roundedDateValue.ToOADate() == xValue || roundedDateValue.ToOADate() == xEndValue)
					{
						return - current + 1;
					}
				}
				// Adjuster of 0.5 means that position should be between points
				++pointIndex;
				while(pointIndex < series.Points.Count)
				{
					if(series.Points[pointIndex].XValue >= xEndValue)
					{
						if(series.Points[pointIndex].XValue > xEndValue && !forceIntIndex)
						{
							adjuster = -0.5;
						}
						break;
					}
					++pointIndex;
				}
				// If last point outside of the max series index
				if(pointIndex == series.Points.Count)
				{
					pointIndex += series.Points.Count/5 + 1;
				}
				double size = (pointIndex + 1) - current + adjuster;
		
				return (size != 0) ? size : interval;
			}
	
			// Non indexed series
			else
			{
				DateTime	date = DateTime.FromOADate(current);
				TimeSpan	span = new TimeSpan(0);
				if(type == DateTimeIntervalType.Days)
				{
					span = TimeSpan.FromDays(interval);
				}
				else if(type == DateTimeIntervalType.Hours)
				{
					span = TimeSpan.FromHours(interval);
				}
				else if(type == DateTimeIntervalType.Milliseconds)
				{
					span = TimeSpan.FromMilliseconds(interval);
				}
				else if(type == DateTimeIntervalType.Seconds)
				{
					span = TimeSpan.FromSeconds(interval);
				}
				else if(type == DateTimeIntervalType.Minutes)
				{
					span = TimeSpan.FromMinutes(interval);
				}
				else if(type == DateTimeIntervalType.Weeks)
				{
					span = TimeSpan.FromDays(7.0 * interval);
				}
				else if(type == DateTimeIntervalType.Months)
				{
					// Special case handling when current date points 
					// to the last day of the month
					bool lastMonthDay = false;
					if(date.Day == DateTime.DaysInMonth(date.Year, date.Month))
					{
						lastMonthDay = true;
					}
					// Add specified amount of months
					date = date.AddMonths((int)Math.Floor(interval));
					span = TimeSpan.FromDays(30.0 * ( interval - Math.Floor(interval) ));
					// Check if last month of the day was used
					if(lastMonthDay && span.Ticks == 0)
					{
						// Make sure the last day of the month is selected
						int daysInMobth = DateTime.DaysInMonth(date.Year, date.Month);
						date = date.AddDays(daysInMobth - date.Day);
					}
				}
				else if(type == DateTimeIntervalType.Years)
				{
					date = date.AddYears((int)Math.Floor(interval));
					span = TimeSpan.FromDays(365.0 * ( interval - Math.Floor(interval) ));
				}
				// Check if an absolute interval size must be returned
				double result = date.Add(span).ToOADate() - current;
				if(forceAbsInterval)
				{
					result = Math.Abs(result);
				}
				return result;
			}
		}
		/// 
		/// Check if series is indexed. IsXValueIndexed flag is set or all X values are zeros.
		/// 
		/// Data series to test.
		/// True if series is indexed.
		static internal bool IndexedSeries( Series series)
		{
            // X value indexed flag set
            if (series.IsXValueIndexed)
            {
                return true;
            }
            if (Utilities.CustomPropertyRegistry.IsXAxisQuantitativeChartTypes.Contains(series.ChartType) && 
                series.IsCustomPropertySet(Utilities.CustomPropertyName.IsXAxisQuantitative))
            {
                string attribValue = series[Utilities.CustomPropertyName.IsXAxisQuantitative];
                if (String.Compare(attribValue, "True", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return false;
                }
            }
            // Check if series has all X values set to zero
            return SeriesXValuesZeros(series);
		}
		/// 
		/// Check if all data points in the series have X value set to 0.
		/// 
		/// Data series to check.
		static private bool SeriesXValuesZeros( Series series )
		{
			// Check if X value zeros check was already done
			if(series.xValuesZerosChecked)
			{
				return series.xValuesZeros;
			}
			// Data point loop
            series.xValuesZerosChecked = true;
			series.xValuesZeros = true;
			foreach( DataPoint point in series.Points )
			{
				if( point.XValue != 0.0 )
				{
					// If any data point has value different than 0 return false
					series.xValuesZeros = false;
					break;
				}
			}
			return series.xValuesZeros;
		}
		/// 
		/// Check if any series is indexed. IsXValueIndexed flag is set or all X values are zeros.
		/// 
        /// Reference to common chart classes.
		/// Data series names.
		/// True if any series is indexed.
        static internal bool IndexedSeries(CommonElements common, params string[] series)
		{
			// Data series loop
			bool	zeroXValues = true;
            foreach (string ser in series)
            {
                Series localSeries = common.DataManager.Series[ser];
                // Check series indexed flag
                if (localSeries.IsXValueIndexed)
                {
                    // If flag set in at least one series - all series are indexed
                    return true;
                }
                // Check if series has all X values set to zero
                if (zeroXValues && !IndexedSeries(localSeries))
                {
                    zeroXValues = false;
                }
            }
            return zeroXValues;
		}
		/// 
		/// Check if all data points in many series have X value set to 0.
		/// 
        /// Reference to common chart classes.
		/// Data series.
		/// True if all data points have value 0.
        static internal bool SeriesXValuesZeros(CommonElements common, params string[] series)
		{
			// Data series loop
			foreach( string ser in series )
			{
				// Check one series X values
				if(!SeriesXValuesZeros(common.DataManager.Series[ ser ]))
				{
					return false;
				}
			}
			return true;
		}
		#endregion
    }
    #endregion //ChartElement
}