File: Common\General\Selection.cs
Project: ndp\fx\src\DataVisualization\System.Windows.Forms.DataVisualization.csproj (System.Windows.Forms.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		Selection.cs
//
//  Namespace:	DataVisualization.Charting
//
//	Classes:	Selection, HitTestResult, ToolTipEventArgs, 
//				HotRegionElement, Hot Region
//
//  Purpose:	This file contains methods used for Win Form selection
//
//	Reviewed:	AG - Oct 21
//
//===================================================================
 
 
#region Used namespaces
 
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Text;
using System.Collections.ObjectModel;
 
#if Microsoft_CONTROL
    using System.Windows.Forms;
#endif
 
 
#endregion
 
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
	#region Enumerations
 
 
    // Plase keep the folowing enumaration in chart layering order - ex. ChartArea is under DataPoint 
	/// <summary>
    /// An enumeration of types of Chart Element.
	/// </summary>
	public enum ChartElementType
	{
		/// <summary>
		/// No chart element.
		/// </summary>
		Nothing,
 
        /// <summary>
        /// The title of a chart.
        /// </summary>
        Title,
 
        /// <summary>
        /// Plotting area (chart area excluding axes, labels, etc.).  
        /// Also excludes the regions that data points may occupy.
        /// </summary>
        PlottingArea,
 
        /// <summary>
        /// An Axis object.
        /// </summary>
        Axis,
 
        /// <summary>
        /// Any major or minor tick mark.
        /// </summary>
        TickMarks,
 
        /// <summary>
        /// Any major or minor grid line (both vertical or horizontal).
        /// </summary>
        Gridlines,
 
        /// <summary>
        /// A StripLine object.
        /// </summary>
        StripLines,
 
        /// <summary>
        /// Axis label Image.
        /// </summary>
        AxisLabelImage,
 
        /// <summary>
        /// Axis labels
        /// </summary>
        AxisLabels,
 
        /// <summary>
        /// Axis title
        /// </summary>
        AxisTitle,
 
 
#if Microsoft_CONTROL

		/// <summary>
		/// A scrollbar tracking thumb.
		/// </summary>
        ScrollBarThumbTracker,
 
		/// <summary>
		/// A scrollbar small decrement button.  A "down arrow" 
		/// button for a vertical scrollbar, or a "left arrow" 
		/// button for a horizontal scroll bar.
        /// </summary>
		ScrollBarSmallDecrement,
 
		/// <summary>
		/// A scrollbar small increment button.  An "up arrow" 
		/// button for a vertical scrollbar, or a "right arrow" 
		/// button for a horizontal scroll bar.
		/// </summary>
        ScrollBarSmallIncrement,
 
		/// <summary>
		/// The background of a scrollbar that will result in 
        /// a large decrement in the scale view size when clicked.  
		/// This is the background below the thumb for 
		/// a vertical scrollbar, and to the left of 
		/// the thumb for a horizontal scrollbar.
		/// </summary>
        ScrollBarLargeDecrement,
 
		/// <summary>
		/// The background of a scrollbar that will result in 
        /// a large increment in the scale view size when clicked.  
		/// This is the background above the thumb for 
		/// a vertical scrollbar, and to the right of 
		/// the thumb for a horizontal scrollbar.
		/// </summary>
        ScrollBarLargeIncrement,
 
		/// <summary>
		/// The zoom reset button of a scrollbar.
		/// </summary>
        ScrollBarZoomReset,
 
#endif // Microsoft_CONTROL
 
        /// <summary>
        /// A DataPoint object.
        /// </summary>
        DataPoint,
 
        /// <summary>
        /// Series data point label.
        /// </summary>
        DataPointLabel,
 
        /// <summary>
        /// The area inside a Legend object.  Does not include 
        /// the space occupied by legend items.
        /// </summary>
        LegendArea,
 
        /// <summary>
        /// Legend title.
        /// </summary>
        LegendTitle,
 
        /// <summary>
        /// Legend header.
        /// </summary>
        LegendHeader,
 
        /// <summary>
        /// A LegendItem object.
        /// </summary>
        LegendItem,
 
 
		/// <summary>
		/// Chart annotation object.
		/// </summary>
		Annotation,
 
 
	}
 
	/// <summary>
	/// Enumeration (Flag) used for processing chart types.
	/// </summary>
	[Flags]
	internal enum ProcessMode
	{
		/// <summary>
		/// Paint mode
		/// </summary>
		Paint = 1,
 
		/// <summary>
		/// Selection mode. Collection of hot regions has to be created.
		/// </summary>
		HotRegions = 2,
 
		/// <summary>
		/// Used for image maps
		/// </summary>
		ImageMaps = 4
	}
 
	#endregion
 
    /// <summary>
    /// This class presents item in
    /// the collection of hot regions.
    /// </summary>
	internal class HotRegion : IDisposable
	{
		#region Fields
 
		// Private data members, which store properties values
		private GraphicsPath		_path = null;
		private bool				_relativeCoordinates = true;
		private RectangleF			_boundingRectangle = RectangleF.Empty;
		private object				_selectedObject = null;
		private int					_pointIndex = -1;
		private string				_seriesName = "";
		private ChartElementType	_type = ChartElementType.Nothing;
 
 
		private object				_selectedSubObject = null;
 
 
		#endregion // Fields
 
		#region Properties
 
		/// <summary>
		/// Region is Graphics path
		/// </summary>
		internal GraphicsPath Path
		{
			get
			{
                return _path;
			}
			set
			{
                _path = value;
			}
		}
 
        /// <summary>
        /// Relative coordinates are used 
        /// to define region
        /// </summary>
        internal bool RelativeCoordinates
		{
			get
			{
				return _relativeCoordinates;
			}
			set
			{
				_relativeCoordinates = value;
			}
		}
 
		/// <summary>
		/// Bounding Rectangle of an shape
		/// </summary>
		internal RectangleF BoundingRectangle
		{
			get
			{
				return _boundingRectangle;
			}
			set
			{
                _boundingRectangle = value;
			}
		}
 
		/// <summary>
		/// Object which is presented with this region
		/// </summary>
		internal object SelectedObject
		{
			get
			{
				return _selectedObject;
			}
			set
			{
				_selectedObject = value;
			}
		}
 
 
 
		/// <summary>
		/// Sub-Object which is presented with this region
		/// </summary>
		internal object SelectedSubObject
		{
			get
			{
				return _selectedSubObject;
			}
			set
			{
				_selectedSubObject = value;
			}
		}
 
 
 
		/// <summary>
		/// Index of the data point which is presented with this region
		/// </summary>
		internal int PointIndex
		{
			get
			{
				return _pointIndex;
			}
			set
			{
				_pointIndex = value;
			}
		}
 
		/// <summary>
		/// Name of the series which is presented with the region
		/// </summary>
		internal string SeriesName
		{
			get
			{
				return _seriesName;
			}
			set
			{
				_seriesName = value;
			}
		}
 
		/// <summary>
		/// Chart Element AxisName
		/// </summary>
		internal ChartElementType Type
		{
			get
			{
				return _type;
			}
			set
			{
				_type = value;
			}
		}
 
		#endregion // Properties
 
        #region IDisposable members
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_path != null)
                {
                    _path.Dispose();
                    _path = null;
                }
            }
        }
 
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
 
        #region Methods
        
        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string  ToString()
        {
            string objectType = this.SelectedObject != null ? this.SelectedObject.ToString() : "null";
            if (this.SelectedObject == null && !String.IsNullOrEmpty(this.SeriesName))
            {
                objectType = this.SeriesName;
            }
            return String.Format(CultureInfo.CurrentCulture, "{0} of {1}", this.Type, objectType);
        }
 
        #endregion //Methods
    }
 
	/// <summary>
	/// This class is used to fill and 
	/// manage collection with Hot Regions
	/// </summary>
    internal class HotRegionsList : IDisposable
	{
		#region Fields
 
		/// <summary>
		/// Process chart mode Flag
		/// </summary>
		private ProcessMode _processChartMode = ProcessMode.Paint;
 
		/// <summary>
		/// Collection with Hor Region Elements
		/// </summary>
		private System.Collections.ArrayList _regionList = new ArrayList();
 
		/// <summary>
		/// Reference to the common elements object
		/// </summary>
		private CommonElements _common = null;
 
#if Microsoft_CONTROL
		
        /// <summary>
		/// True if hit test function is called
		/// </summary>
		internal bool					hitTestCalled = false;
 
#endif // Microsoft_CONTROL
        
        #endregion // Fields
 
        #region Properties
 
        /// <summary>
		/// Flag used for processing chart types. It could 
		/// be Paint, HotRegion or both mode.
		/// </summary>
		internal ProcessMode ProcessChartMode
		{
			get
			{
				return _processChartMode;
			}
			set
			{
				_processChartMode = value;
				if(this._common != null)
				{
					this._common.processModePaint = 
						(_processChartMode & ProcessMode.Paint ) == ProcessMode.Paint;
					this._common.processModeRegions = 
						( _processChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions ||
						( _processChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps;
				}
			}
		}
 
		/// <summary>
		/// Collection with Hor Region Elements
		/// </summary>
		internal ArrayList List
		{
			get
			{
				return _regionList;
			}
		}
 
		#endregion // Properties
 
		#region Methods
 
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="common">Reference to the CommonElements</param>
		internal HotRegionsList( CommonElements common )
		{
			this._common = common;
		}
 
		/// <summary>
		/// Add hot region to the collection.
		/// </summary>
		/// <param name="rectSize">Rectangle which presents an Hot Region</param>
		/// <param name="point">Data Point</param>
		/// <param name="seriesName">Data Series</param>
		/// <param name="pointIndex">Index of an Data Point in the series</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
        public void AddHotRegion( 
			RectangleF rectSize, 
			DataPoint point, 
			string seriesName, 
			int pointIndex 
			)
		{
			
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(point.ToolTip.Length > 0 || 
						point.Url.Length > 0 ||
                        point.MapAreaAttributes.Length > 0 ||
                        point.PostBackValue.Length > 0 
                        )
					{
                        MapArea area = new MapArea(
							    point.ReplaceKeywords(point.ToolTip), 
							    point.ReplaceKeywords(point.Url), 
							    point.ReplaceKeywords(point.MapAreaAttributes),
                                point.ReplaceKeywords(point.PostBackValue),
							    rectSize,
                                point.Tag);
                        area.IsCustom = false;
                        _common.ChartPicture.MapAreas.Insert(0, area);
                    }
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				HotRegion region = new HotRegion();
				
				region.BoundingRectangle = rectSize;
				region.SeriesName = seriesName;
				region.PointIndex = pointIndex;
				region.Type = ChartElementType.DataPoint;
				region.RelativeCoordinates = true;
 
 
 
				// Use index of the original data point
				if(point != null && point.IsCustomPropertySet("OriginalPointIndex"))
				{
					region.PointIndex = int.Parse(point["OriginalPointIndex"], CultureInfo.InvariantCulture);
				}
				
 
 
				_regionList.Add( region );
			}
		}
 
 
        /// <summary>
        /// Adds the hot region.
        /// </summary>
        /// <param name="path">Bounding GraphicsPath.</param>
        /// <param name="relativePath">if set to <c>true</c> the is relative path.</param>
        /// <param name="graph">Chart Graphics Object</param>
        /// <param name="point">Selected data point</param>
        /// <param name="seriesName">Name of the series.</param>
        /// <param name="pointIndex">Index of the point.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "graph")]
        internal void AddHotRegion(
			GraphicsPath path, 
			bool relativePath,
			ChartGraphics graph,
			DataPoint point, 
			string seriesName, 
			int pointIndex 
			) 
		{
			if( path == null )
			{
				return;
			}
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(point.ToolTip.Length > 0 || 
						point.Url.Length > 0 ||
                        point.MapAreaAttributes.Length > 0 ||
                        point.PostBackValue.Length > 0
                        )
					{
                        int prevMapAreaCount = _common.ChartPicture.MapAreas.Count;
                        _common.ChartPicture.MapAreas.InsertPath(
							0,
							point.ReplaceKeywords(point.ToolTip), 
							point.ReplaceKeywords(point.Url), 
							point.ReplaceKeywords(point.MapAreaAttributes),
                            point.ReplaceKeywords(point.PostBackValue),
							path,
							!relativePath,
							graph
							);
 
 
                        // Set map area type
                        for (int i = 0; i < _common.ChartPicture.MapAreas.Count - prevMapAreaCount; i++)
                            ((IChartMapArea)_common.ChartPicture.MapAreas[i]).Tag = ((IChartMapArea)point).Tag;
                    }
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
						
				HotRegion region = new HotRegion();
						
				region.SeriesName = seriesName;
				region.PointIndex = pointIndex;
				region.Type = ChartElementType.DataPoint;
				region.Path = (GraphicsPath)path.Clone();
				region.BoundingRectangle = path.GetBounds();
				region.RelativeCoordinates = relativePath;
 
 
 
				// Use index of the original data point
				if(point != null && point.IsCustomPropertySet("OriginalPointIndex"))
				{
					region.PointIndex = int.Parse(point["OriginalPointIndex"], CultureInfo.InvariantCulture);
				}
				
 
 
				_regionList.Add( region );
 
			}
		}
 
        /// <summary>
        /// Adds the hot region.
        /// </summary>
        /// <param name="insertIndex">Position where to insert element. Used for image maps only</param>
        /// <param name="path">Bounding GraphicsPath.</param>
        /// <param name="relativePath">if set to <c>true</c> the is relative path.</param>
        /// <param name="graph">Chart Graphics Object</param>
        /// <param name="point">Selected data point</param>
        /// <param name="seriesName">Name of the series.</param>
        /// <param name="pointIndex">Index of the point.</param>
        [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "graph"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "insertIndex")
        ]
        internal void AddHotRegion(
			int insertIndex,
			GraphicsPath path, 
			bool relativePath,
			ChartGraphics graph,
			DataPoint point, 
			string seriesName, 
			int pointIndex 
			) 
		{
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(point.ToolTip.Length > 0 || 
						point.Url.Length > 0 ||
                        point.MapAreaAttributes.Length > 0 ||
                        point.PostBackValue.Length > 0)
 
					{
                        int prevMapAreaCount = _common.ChartPicture.MapAreas.Count;
 
                        _common.ChartPicture.MapAreas.InsertPath(
							insertIndex,
							point.ReplaceKeywords(point.ToolTip), 
							point.ReplaceKeywords(point.Url), 
							point.ReplaceKeywords(point.MapAreaAttributes),
                            point.ReplaceKeywords(point.PostBackValue),
							path,
							!relativePath,
							graph
							);
 
                        // Set map area type
                        for (int i = insertIndex; i < _common.ChartPicture.MapAreas.Count - prevMapAreaCount; i++)
                            ((IChartMapArea)_common.ChartPicture.MapAreas[i]).Tag = ((IChartMapArea)point).Tag;
                    }
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
						
				HotRegion region = new HotRegion();
						
				region.SeriesName = seriesName;
				region.PointIndex = pointIndex;
				region.Type = ChartElementType.DataPoint;
				region.Path = (GraphicsPath)path.Clone();
				region.BoundingRectangle = path.GetBounds();
				region.RelativeCoordinates = relativePath;
 
 
 
				// Use index of the original data point
				if(point != null && point.IsCustomPropertySet("OriginalPointIndex"))
				{
					region.PointIndex = int.Parse(point["OriginalPointIndex"], CultureInfo.InvariantCulture);
				}
				
 
 
				_regionList.Add( region );
 
			}
		}
 
        /// <summary>
        /// Add hot region to the collection.
        /// </summary>
        /// <param name="path">Graphics path which presents hot region</param>
        /// <param name="relativePath">Graphics path uses relative or absolute coordinates</param>
        /// <param name="coord">Coordinates which defines polygon (Graphics Path). Used for image maps</param>
        /// <param name="point">Selected data point</param>
        /// <param name="seriesName">Data Series</param>
        /// <param name="pointIndex">Index of an Data Point in the series</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "coord")]
        internal void AddHotRegion( GraphicsPath path, bool relativePath, float [] coord, DataPoint point, string seriesName, int pointIndex )
		{
 
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(point.ToolTip.Length > 0 || 
						point.Url.Length > 0 ||
                        point.MapAreaAttributes.Length > 0 ||
                        point.PostBackValue.Length > 0)
					{
                        MapArea area = new MapArea(
                                MapAreaShape.Polygon,
                                point.ReplaceKeywords(point.ToolTip),
                                point.ReplaceKeywords(point.Url),
                                point.ReplaceKeywords(point.MapAreaAttributes),
                                point.ReplaceKeywords(point.PostBackValue),
                                coord,
                                point.Tag);
                        area.IsCustom = false;
                        _common.ChartPicture.MapAreas.Insert(0,area);
 
                    }
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				
				HotRegion region = new HotRegion();
				
				region.SeriesName = seriesName;
				region.PointIndex = pointIndex;
				region.Type = ChartElementType.DataPoint;
                region.Path = (GraphicsPath)path.Clone();
				region.BoundingRectangle = path.GetBounds();
				region.RelativeCoordinates = relativePath;
 
 
 
				// Use index of the original data point
				if(point != null && point.IsCustomPropertySet("OriginalPointIndex"))
				{
					region.PointIndex = int.Parse(point["OriginalPointIndex"], CultureInfo.InvariantCulture);
				}
				
 
 
				_regionList.Add( region );
 
			}
 
		}
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="insertIndex">Position where to insert element. Used for image maps only</param>
        /// <param name="graph">Chart Graphics Object</param>
        /// <param name="x">x coordinate.</param>
        /// <param name="y">y coordinate.</param>
        /// <param name="radius">The radius.</param>
        /// <param name="point">Selected data point</param>
        /// <param name="seriesName">Data Series</param>
        /// <param name="pointIndex">Index of an Data Point in the series</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "insertIndex")]
        internal void AddHotRegion( int insertIndex, ChartGraphics graph, float x, float y, float radius, DataPoint point, string seriesName, int pointIndex )
		{
 
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(point.ToolTip.Length > 0 || 
						point.Url.Length > 0 ||
                        point.MapAreaAttributes.Length > 0 ||
                        point.PostBackValue.Length > 0 )
					{
 
					float[]	circCoord = new float[3];
					circCoord[0] = x;
					circCoord[1] = y;
					circCoord[2] = radius;
 
        			MapArea area = new MapArea(
                			MapAreaShape.Circle,
                			point.ReplaceKeywords(point.ToolTip),
                			point.ReplaceKeywords(point.Url),
                			point.ReplaceKeywords(point.MapAreaAttributes),
                			point.ReplaceKeywords(point.PostBackValue),
                			circCoord,
                			point.Tag);
        			area.IsCustom = false;
					// Insert area
					_common.ChartPicture.MapAreas.Insert(insertIndex,area);
 
					}
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				HotRegion region = new HotRegion();
 
				PointF circleCenter = graph.GetAbsolutePoint( new PointF( x, y ) );
				SizeF circleRadius = graph.GetAbsoluteSize( new SizeF( radius, radius ) );
 
				GraphicsPath path = new GraphicsPath();
				path.AddEllipse( 
					circleCenter.X - circleRadius.Width, 
					circleCenter.Y - circleRadius.Width,
					2 *  circleRadius.Width, 
					2 *  circleRadius.Width 
					);
				region.BoundingRectangle = path.GetBounds();
				region.SeriesName = seriesName;
				region.Type = ChartElementType.DataPoint;
				region.PointIndex = pointIndex;
                region.Path = path;
				region.RelativeCoordinates = false;
 
 
 
				// Use index of the original data point
				if(point != null && point.IsCustomPropertySet("OriginalPointIndex"))
				{
					region.PointIndex = int.Parse(point["OriginalPointIndex"], CultureInfo.InvariantCulture);
				}
				
 
 
				_regionList.Add( region );
			}
		}
 
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="rectArea">Hot Region rectangle</param>
        /// <param name="toolTip">Tool Tip Text</param>
        /// <param name="hRef">HRef string</param>
        /// <param name="mapAreaAttributes">Map area Attribute string</param>
        /// <param name="postBackValue">The post back value associated with this item</param>
        /// <param name="selectedObject">Object which present hot region</param>
        /// <param name="type">AxisName of the object which present hot region</param>
        /// <param name="series">Selected series</param>
        [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "hRef"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mapAreaAttributes"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "postBackValue"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "toolTip")
        ]
        internal void AddHotRegion( RectangleF rectArea, string toolTip, string hRef, string mapAreaAttributes, string postBackValue, object selectedObject, ChartElementType type, string series )
		{
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
				// Add items to the image map collection
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(toolTip.Length > 0 || 
						hRef.Length > 0 ||
                        mapAreaAttributes.Length > 0 ||
                        postBackValue.Length > 0)
					{
                        		MapArea area = new MapArea(
                                                    toolTip,
                                                    hRef,
                                                    mapAreaAttributes,
                                                    postBackValue,
                                                    rectArea,
                                                    ((IChartMapArea)selectedObject).Tag);
                        		area.IsCustom = false;
                        		_common.ChartPicture.MapAreas.Add( area);
					}
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				HotRegion region = new HotRegion();
				
				region.BoundingRectangle = rectArea;
				region.RelativeCoordinates = true;
				region.Type = type;
				region.SelectedObject = selectedObject;
				if(!String.IsNullOrEmpty(series))
				{
					region.SeriesName = series;
				}
				_regionList.Add( region );
			}
		}
 
 
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="rectArea">Hot Region rectangle</param>
        /// <param name="toolTip">Tool Tip Text</param>
        /// <param name="hRef">HRef string</param>
        /// <param name="mapAreaAttributes">Map area Attribute string</param>
        /// <param name="postBackValue">The post back value associated with this item</param>
        /// <param name="selectedObject">Object which present hot region</param>
        /// <param name="selectedSubObject">Sub-Object which present hot region</param>
        /// <param name="type">AxisName of the object which present hot region</param>
        /// <param name="series">Selected series</param>
        [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "hRef"), 
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mapAreaAttributes"), 
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "postBackValue"), 
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "toolTip") 
        ]
        internal void AddHotRegion( 
			RectangleF rectArea, 
			string toolTip, 
			string hRef, 
			string mapAreaAttributes, 
            string postBackValue,
			object selectedObject, 
			object selectedSubObject, 
			ChartElementType type, 
			string series )
		{
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
				// Add items to the image map collection
                if (_common.ChartPicture.IsMapEnabled == true)
				{
					if(toolTip.Length > 0 || 
						hRef.Length > 0 ||
                        mapAreaAttributes.Length > 0 ||
                        postBackValue.Length > 0)
					{
                        MapArea area = new MapArea(
                                                    toolTip,
                                                    hRef,
                                                    mapAreaAttributes,
                                                    postBackValue,
                                                    rectArea,
                                                    ((IChartMapArea)selectedObject).Tag);
                        area.IsCustom = false;
                        _common.ChartPicture.MapAreas.Add( area);
					}
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				HotRegion region = new HotRegion();
				
				region.BoundingRectangle = rectArea;
				region.RelativeCoordinates = true;
				region.Type = type;
				region.SelectedObject = selectedObject;
				region.SelectedSubObject = selectedSubObject;
				if(!String.IsNullOrEmpty(series))
				{
					region.SeriesName = series;
				}
				_regionList.Add( region );
			}
		}
 
 
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="graph">Chart Graphics Object</param>
        /// <param name="path">Graphics path</param>
        /// <param name="relativePath">Used relative coordinates for graphics path.</param>
        /// <param name="toolTip">Tool Tip Text</param>
        /// <param name="hRef">HRef string</param>
        /// <param name="mapAreaAttributes">Map area Attribute string</param>
        /// <param name="postBackValue">The post back value associated with this item</param>
        /// <param name="selectedObject">Object which present hot region</param>
        /// <param name="type">AxisName of the object which present hot region</param>
        [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "graph"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "hRef"), 
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mapAreaAttributes"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "postBackValue"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "toolTip")
        ]
        internal void AddHotRegion( ChartGraphics graph, GraphicsPath path, bool relativePath, string toolTip, string hRef, string mapAreaAttributes, string postBackValue, object selectedObject, ChartElementType type )
		{
#if !Microsoft_CONTROL
			if( ( ProcessChartMode & ProcessMode.ImageMaps ) == ProcessMode.ImageMaps )
			{
                if (_common.ChartPicture.IsMapEnabled == true)
				{
 
                    if(toolTip.Length > 0 || 
						hRef.Length > 0 || 
						mapAreaAttributes.Length > 0 ||
                        postBackValue.Length > 0)
					{
                        _common.ChartPicture.MapAreas.InsertPath(
							0,
							toolTip, 
							hRef, 
							mapAreaAttributes,
                            postBackValue,
							path,
							!relativePath,
							graph
							);
					}
				}
			}
#endif // !Microsoft_CONTROL
 
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
						
				HotRegion region = new HotRegion();
						
				region.Type = type;
                region.Path = (GraphicsPath)path.Clone();
				region.SelectedObject = selectedObject;
				region.BoundingRectangle = path.GetBounds();
				region.RelativeCoordinates = relativePath;
 
				_regionList.Add( region );
 
			}
		}
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="rectArea">Hot Region rectangle</param>
        /// <param name="selectedObject">Object which present hot region</param>
        /// <param name="type">AxisName of the object which present hot region</param>
        /// <param name="relativeCoordinates">Coordinates for rectangle are relative</param>
		internal void AddHotRegion( RectangleF rectArea, object selectedObject, ChartElementType type, bool relativeCoordinates )
		{
			this.AddHotRegion( rectArea, selectedObject, type, relativeCoordinates, false );
		}
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="rectArea">Hot Region rectangle</param>
        /// <param name="selectedObject">Object which present hot region</param>
        /// <param name="type">AxisName of the object which present hot region</param>
        /// <param name="relativeCoordinates">Coordinates for rectangle are relative</param>
        /// <param name="insertAtBeginning">Insert the hot region at the beginning of the collection</param>
		internal void AddHotRegion( RectangleF rectArea, object selectedObject, ChartElementType type, bool relativeCoordinates, bool insertAtBeginning )
		{
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
				HotRegion region = new HotRegion();
				
				region.BoundingRectangle = rectArea;
				region.RelativeCoordinates = relativeCoordinates;
				region.Type = type;
				region.SelectedObject = selectedObject;
				
				if( insertAtBeginning )
				{
					_regionList.Insert( _regionList.Count - 1, region ); 
				}
				else
				{
					_regionList.Add( region );
				}
			}
		}
 
        /// <summary>
        /// Add Hot region to the collection.
        /// </summary>
        /// <param name="path">Graphics path</param>
        /// <param name="relativePath">Used relative coordinates for graphics path.</param>
        /// <param name="type">Type of the object which present hot region</param>
        /// <param name="selectedObject">Object which present hot region</param>
        internal void AddHotRegion(
			GraphicsPath path, 
			bool relativePath,
			ChartElementType type,
			object selectedObject
			) 
		{
			if( ( ProcessChartMode & ProcessMode.HotRegions ) == ProcessMode.HotRegions )
			{
						
				HotRegion region = new HotRegion();
						
				region.SelectedObject = selectedObject;
				region.Type = type;
                region.Path = (GraphicsPath)path.Clone();
				region.BoundingRectangle = path.GetBounds();
				region.RelativeCoordinates = relativePath;
 
				_regionList.Add( region );
 
			}
		}
 
        /// <summary>
        /// This method search for position in Map Areas which is the first 
        /// position after Custom areas.
        /// </summary>
        /// <returns>Insert Index</returns>
		internal int FindInsertIndex()
		{
			int insertIndex = 0;
#if !Microsoft_CONTROL
            foreach (MapArea mapArea in _common.ChartPicture.MapAreas)
			{
				if(!mapArea.IsCustom)
				{
					break;
				}
				++insertIndex;
			}
#endif // !Microsoft_CONTROL
 
			return insertIndex;
		}
 
        /// <summary>
        /// Clears this instance.
        /// </summary>
        public void Clear()
        {
            foreach (HotRegion hotRegion in this._regionList)
                hotRegion.Dispose();
            
            this._regionList.Clear();
        }
 
		#endregion // Methods
 
        #region IDisposable members
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this._regionList != null)
                {
                    foreach (HotRegion hotRegion in this._regionList)
                        hotRegion.Dispose();
 
                    this._regionList.Clear();
                }
            }
        }
 
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
 
	}
 
	/// <summary>
    /// The HitTestResult class contains the result of the hit test function.
	/// </summary>
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class HitTestResult
	{
        #region Fields
 
        // Private members
		private object _obj = null;
		private Series _series = null;
		private int _dataPoint = -1;
		private ChartArea _chartArea = null;
		private Axis _axis = null;
		private ChartElementType _type = ChartElementType.Nothing;
		private object _subObject = null;
 
		#endregion
 
		#region Properties
 
		/// <summary>
		/// Gets or sets the data series object.
		/// </summary>
		public Series Series
		{
			get
			{
                return _series;
			}
			set
			{
                _series = value;
			}
		}
 
		/// <summary>
        /// Gets or sets the data point index.
		/// </summary>
		public int PointIndex
		{
			get
			{
                return _dataPoint;
			}
			set
			{
                _dataPoint = value;
			}
		}
 
		/// <summary>
        /// Gets or sets the chart area object.
		/// </summary>
		public ChartArea ChartArea
		{
			get
			{
                return _chartArea;
			}
			set
			{
                _chartArea = value;
			}
		}
 
		/// <summary>
        /// Gets or sets the axis object.
		/// </summary>
		public Axis Axis
		{
			get
			{
                return _axis;
			}
			set
			{
                _axis = value;
			}
		}
 
		/// <summary>
        /// Gets or sets the chart element type.
		/// </summary>
		public ChartElementType ChartElementType
		{
			get
			{
                return _type;
			}
			set
			{
                _type = value;
			}
		}
 
        /// <summary>
        ///  Gets or sets the selected object.
        /// </summary>
		public object Object
		{
			get
			{
				return _obj;
			}
			set
			{
				_obj = value;
			}
		}
 
 
 
		/// <summary>
        ///  Gets or sets the selected sub object.
		/// </summary>
		public object SubObject
		{
			get
			{
                return _subObject;
			}
			set
			{
                _subObject = value;
			}
		}
 
		#endregion
	}
 
 
    /// <summary>
    /// This class represents an array of marker points and 
    /// the outline path used for visual object selection in the chart.
    /// </summary>
    /// <remarks>
    /// <see cref="OutlinePath"/> may be null for complex objects or objects with two points or fewer.
    /// </remarks>
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class ChartElementOutline : IDisposable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ChartElementOutline"/> class.
        /// </summary>
        internal ChartElementOutline()
        {
            this.Markers = new ReadOnlyCollection<PointF>( new PointF[] {});
        }
 
        /// <summary>
        /// Gets the markers.  
        /// </summary>
        /// <value>The markers.</value>
        public ReadOnlyCollection<PointF> Markers { get; internal set; }
 
        /// <summary>
        /// Gets or sets the outline path. The result could be null for complex objects and objects with two points or fewer.
        /// </summary>
        /// <value>The outline path.</value>
        public GraphicsPath OutlinePath { get; internal set; }
 
 
        #region IDisposable Members
 
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.OutlinePath != null)
                {
                    this.OutlinePath.Dispose();
                    this.OutlinePath = null;
                }
                this.Markers = null;
            }
        }
 
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]        
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        #endregion
    }
 
 
	/// <summary>
	/// This class contains methods used for Windows Forms selection.
	/// </summary>
	internal class Selection : IServiceProvider
#if Microsoft_CONTROL
        , IDisposable
#endif //Microsoft_CONTROL
	{
		#region Fields
 
        /// <summary>
        /// The chart service container
        /// </summary>
        private IServiceContainer _service = null;
 
#if Microsoft_CONTROL

        /// <summary>
        /// Stores the tooltip of the control.
        /// </summary>
        private ToolTip _toolTip = new ToolTip();
 
        /// <summary>
        /// Used by the tooltip - stores the time when the tooltip is activated.
        /// </summary>
        private DateTime _toolTipActivationTime = DateTime.Now;
 
        /// <summary>
        /// Stores the last mouse move X and Y coordinates, so we can ignore false calls to
        /// OnMouseMove generated my the tooltip.
        /// </summary>
        private Point _lastMouseMove = new Point(int.MinValue, int.MinValue);
 
 
		// ToolTips enabled or disabled from series or legend
		private bool					_toolTipsEnabled = false;
 
		// Tool tips enabled flag checked
		internal bool					enabledChecked = false;
 
#endif //Microsoft_CONTROL
		#endregion
 
        #region Constructors 
        
        /// <summary>
        /// Initializes a new instance of the <see cref="Selection"/> class.
        /// </summary>
        /// <param name="service">The service.</param>
        internal Selection(IServiceContainer service)
        {
            this._service = service;
            this._chartControl = this.ChartControl;
#if Microsoft_CONTROL
            
            // Set up the tooltip
			this._toolTip.Active = true;
			this._toolTip.AutoPopDelay = 30000; // maximum delay possible
			this._toolTip.InitialDelay = 500;
			this._toolTip.ReshowDelay = 50;
			this._toolTip.ShowAlways = true;
			this._toolTip.Active = false;
#endif //Microsoft_CONTROL
 
        }
 
#if Microsoft_CONTROL
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_toolTip != null)
                {
                    _toolTip.Dispose();
                    _toolTip = null;
                }
            }
        }
 
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
#endif //Microsoft_CONTROL
 
        #endregion //Constructors
 
        #region Properties
 
        private Chart _chartControl = null;
        /// <summary>
        /// Returns the attached chart control
        /// </summary>
        internal Chart ChartControl
        {
            get
            {
                if (this._chartControl == null)
                {
                    if (this.ChartPicture != null)
                    {
                        this._chartControl = this.ChartPicture.Chart;
                    }
                }
                return this._chartControl;
            }
        }
 
        private ChartPicture _chartPicture = null;
        /// <summary>
        /// Returns the attached ChartPicture
        /// </summary>
        internal ChartPicture ChartPicture
        {
            get
            {
                if (this._chartPicture == null)
                {
                    this._chartPicture = ((IServiceProvider)this).GetService(typeof(ChartImage)) as ChartPicture;
                    if (this._chartPicture == null)
                    {
                        this._chartPicture = ((IServiceProvider)this).GetService(typeof(ChartPicture)) as ChartPicture;
                    }
                }
                return this._chartPicture;
            }
        }
 
        private Data.DataManager _dataManager = null;
        /// <summary>
        /// Gets the chart data manager ( for series access )
        /// </summary>
        internal Data.DataManager DataManager
        {
            get
            {
                if (this._dataManager == null)
                {
                    this._dataManager = ((IServiceProvider)this).GetService(typeof(Data.DataManager)) as Data.DataManager;
                }
                return this._dataManager;
            }
        }
 
        /// <summary>
        /// Gets the chart ChartGraphics
        /// </summary>
        internal ChartGraphics Graph
        {
            get
            {
                if (this.ChartPicture != null)
                {
                    return this.ChartPicture.Common.graph;
                }
                return null;
            }
        }
 
        #endregion //Private Properties
 
        #region Methods
 
        #region Tooltips
#if Microsoft_CONTROL
        /// <summary>
		/// Checks if tooltips are enabled
		/// </summary>
		/// <returns>true if tooltips enabled</returns>
		private bool IsToolTipsEnabled()
		{
			// Enabled checked. Don’t check every time series 
			// and data points for tooltips.
			if( enabledChecked )
			{
				return _toolTipsEnabled;
			}
 
			enabledChecked = true;
 
 
 
 
			// Annotations loop
			foreach( Annotation annotation in _chartControl.Annotations )
			{
				// ToolTip empty
				if( annotation.ToolTip.Length > 0 )
				{
					// ToolTips enabled
					_toolTipsEnabled = true;
					return true;
				}
			}
 
 
			// Data series loop
			foreach( Series series in _chartControl.Series )
			{
				// Check series tooltips
				if( series.ToolTip.Length > 0 || 
					series.LegendToolTip.Length > 0 ||
					series.LabelToolTip.Length > 0)
				{
					// ToolTips enabled
					_toolTipsEnabled = true;
					return true;
				}
 
 
				// Check if custom properties (Pie collected slice) that create tooltips are used
				if(series.IsCustomPropertySet(Utilities.CustomPropertyName.CollectedToolTip))
				{
					// ToolTips enabled
					_toolTipsEnabled = true;
					return true;
				}
 
 
				// Check point tooltips only for "non-Fast" chart types
				if( !series.IsFastChartType() )
				{
					// Data point loop
					foreach( DataPoint point in series.Points )
					{
						// ToolTip empty
						if( point.ToolTip.Length > 0 || 
							point.LegendToolTip.Length > 0 ||
							point.LabelToolTip.Length > 0)
						{
							// ToolTips enabled
							_toolTipsEnabled = true;
							return true;
						}
					}
				}
			}
 
			// Legend items loop
			foreach( Legend legend in _chartControl.Legends )
			{
				// Check custom legend items
				foreach( LegendItem legendItem in legend.CustomItems )
				{
					// ToolTip empty
					if( legendItem.ToolTip.Length > 0 )
					{
						_toolTipsEnabled = true;
						return true;
					}
 
 
					// Check all custom cells in the legend item
					foreach(LegendCell legendCell in legendItem.Cells)
					{
						if(legendCell.ToolTip.Length > 0)
						{
							_toolTipsEnabled = true;
							return true;
						}
					}
 
				}
 
 
				// Iterate through legend columns
				foreach(LegendCellColumn legendColumn in legend.CellColumns)
				{
					if(legendColumn.ToolTip.Length > 0)
					{
						_toolTipsEnabled = true;
						return true;
					}
				}
 
			}
 
			// Title items loop
			foreach( Title title in _chartControl.Titles )
			{
				// ToolTip empty
				if( title.ToolTip.Length > 0 )
				{
					_toolTipsEnabled = true;
					return true;
				}
			}
 
			// Chart areas loop
			foreach( ChartArea area in _chartControl.ChartAreas )
			{
 
				// Check if chart area is visible
				if(area.Visible)
 
				{
					// Axis loop
					foreach(Axis axis in area.Axes)
					{
 
						// Check ToolTip
						if( axis.ToolTip.Length > 0 )
						{
							_toolTipsEnabled = true;
							return true;
						}
 
 
						// Strip lines loop
						foreach(StripLine stripLine in axis.StripLines)
						{
							// Check ToolTip
							if( stripLine.ToolTip.Length > 0 )
							{
								_toolTipsEnabled = true;
								return true;
							}
						}
						// Check custom labels
						foreach(CustomLabel customLabel in axis.CustomLabels)
						{
							if( customLabel.ToolTip.Length > 0 )
							{
								_toolTipsEnabled = true;
								return true;
							}
						}
					}
				}
			}
 
			// ToolTips disabled
			_toolTipsEnabled = false;
			return false;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
            Justification = "Too large of a code change to justify making this change")]
        internal string EvaluateToolTip(System.Windows.Forms.MouseEventArgs e)
        {
            object obj;
            object subObj;
            ChartElementType type;
            int dataPointIndex;
            string seriesName;
            string toolTipText = " ";
 
            HitTestResult hitTest = this.HitTest(e.X, e.Y, true);
 
            type = hitTest.ChartElementType;
            dataPointIndex = hitTest.PointIndex;
            seriesName = hitTest.Series != null ? hitTest.Series.Name : String.Empty;
            obj = hitTest.Object;
            subObj = hitTest.SubObject;
 
 
            // Get tooltips from data points
            if (type == ChartElementType.DataPoint)
            {
                if (_chartControl.Series.IndexOf(seriesName) >= 0 &&
                    dataPointIndex >= 0 &&
                    dataPointIndex < _chartControl.Series[seriesName].Points.Count)
                {
                    // Take tool tip from data point
                    toolTipText = _chartControl.Series[seriesName].Points[dataPointIndex].ReplaceKeywords(_chartControl.Series[seriesName].Points[dataPointIndex].ToolTip);
                }
                else
                {
                    DataPoint dataPoint = obj as DataPoint;
                    if (dataPoint != null)
                    {
                        // Take tool tip from data point
                        toolTipText = dataPoint.ReplaceKeywords(dataPoint.ToolTip);
                    }
                }
            }
 
 
 
            // Get tooltips from data points
            if (type == ChartElementType.DataPointLabel)
            {
                if (_chartControl.Series.IndexOf(seriesName) >= 0 &&
                    dataPointIndex >= 0 &&
                    dataPointIndex < _chartControl.Series[seriesName].Points.Count)
                {
                    // Take tool tip from data point
                    toolTipText = _chartControl.Series[seriesName].Points[dataPointIndex].ReplaceKeywords(_chartControl.Series[seriesName].Points[dataPointIndex].LabelToolTip);
                }
            }
 
 
            // Get tooltips from custom label
            if (type == ChartElementType.AxisLabels &&
                obj is CustomLabel)
            {
                toolTipText = ((CustomLabel)obj).ToolTip;
            }
 
 
 
 
            // Get tooltips from data points
            else if (type == ChartElementType.Annotation && obj != null && obj is Annotation)
            {
                // Take tool tip from data point
                toolTipText = ((Annotation)obj).ReplaceKeywords(((Annotation)obj).ToolTip);
 
            }
            // Get tooltips from axis
            else if (type == ChartElementType.Axis && obj != null && obj is Axis)
            {
                // Take tool tip from strip line
                toolTipText = ((Axis)obj).ToolTip;
            }
 
            // Get tooltips from strip lines
            else if (type == ChartElementType.StripLines && obj != null && obj is StripLine)
            {
                // Take tool tip from strip line
                toolTipText = ((StripLine)obj).ToolTip;
 
            }
            // Get tooltips from data points
            else if (type == ChartElementType.Title && obj != null && obj is Title)
            {
                // Take tool tip from data point
                toolTipText = ((Title)obj).ToolTip;
 
            } // Get tooltips for legend items
 
            // Get tooltips for legend items
            else if (type == ChartElementType.LegendItem)
            {
                // Take tool tip from legend item
                toolTipText = ((LegendItem)obj).ToolTip;
 
 
                // Check if cell has it's own tooltip
                LegendCell legendCell = subObj as LegendCell;
                if (legendCell != null && legendCell.ToolTip.Length > 0)
                {
                    toolTipText = legendCell.ToolTip;
                }
 
 
                // Check if series is associated with legend item
                if (toolTipText.Length == 0 &&
                    seriesName.Length > 0 &&
                    _chartControl.Series.IndexOf(seriesName) >= 0)
                {
                    // Take tool tip from data point
                    if (dataPointIndex == -1)
                    {
                        if (seriesName.Length > 0)
                        {
                            // Take tool tip from series
                            toolTipText = _chartControl.Series[seriesName].ReplaceKeywords(_chartControl.Series[seriesName].LegendToolTip);
                        }
                    }
                    else
                    {
                        if (dataPointIndex >= 0 &&
                            dataPointIndex < _chartControl.Series[seriesName].Points.Count)
                        {
                            // Take tool tip from data point
                            toolTipText = _chartControl.Series[seriesName].Points[dataPointIndex].ReplaceKeywords(_chartControl.Series[seriesName].Points[dataPointIndex].LegendToolTip);
                        }
                    }
                }
            }
 
            // Set event arguments
            ToolTipEventArgs args = new ToolTipEventArgs(e.X, e.Y, toolTipText, hitTest);
 
            // Event
            _chartControl.OnGetToolTipText(args);
 
            return args.Text.Trim();
 
        }
 
 
        /// <summary>
        /// Mouse move event handler.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Arguments</param>
        internal void Selection_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
 
            // Ignore false calls to OnMouseMove caused by the tootip control.
            if (e.X == this._lastMouseMove.X && e.Y == this._lastMouseMove.Y)
            {
                return;
            }
            else
            {
                this._lastMouseMove.X = e.X;
                this._lastMouseMove.Y = e.Y;
            }
 
            // Event is not active and tooltip properties are nor set.
            if (!IsToolTipsEnabled() && !_chartControl.IsToolTipEventUsed())
            {
                return;
            }
 
            string newToolTipText = this.EvaluateToolTip(e);
 
            if (!String.IsNullOrEmpty(newToolTipText))
            {
                string oldToolTipText = this._toolTip.GetToolTip(this._chartControl);
                TimeSpan timeSpan = DateTime.Now.Subtract(this._toolTipActivationTime);
                if (oldToolTipText != newToolTipText || timeSpan.Milliseconds > 600)
                {
                    // Activate the tooltip
                    this._toolTip.Active = false;
                    this._toolTip.SetToolTip(this._chartControl, newToolTipText);
                    this._toolTip.Active = true;
                    this._toolTipActivationTime = DateTime.Now;
                }
            }
            else
            {
                // We do not have a tooltip, so deactivate it
                this._toolTip.Active = false;
                this._toolTip.SetToolTip(this._chartControl, string.Empty);
            }
        }
 
#endif //Microsoft_CONTROL
 
        #endregion //Tooltips
 
        #region HitTest
 
 
        /// <summary>
        /// Call this method to determine the  chart element,
        /// if any, that is located at a point defined by the given X and Y 
        /// coordinates.
        /// <seealso cref="HitTestResult"/></summary>
        /// <param name="x">The X coordinate for the point in question.
        /// Often obtained from a parameter in an event
        /// (e.g. the X parameter value in the MouseDown event).</param>
        /// <param name="y">The Y coordinate for the point in question.
        /// Often obtained from a parameter in an event
        /// (e.g. the Y parameter value in the MouseDown event).</param>
        /// <param name="requestedElementTypes">
        /// An array of type which specify the types                  
        /// to test for, on order to filter the result. If omitted checking for                 
        /// elementTypes will be ignored and all kind of elementTypes will be 
        /// valid.
        ///  </param>
        /// <param name="ignoreTransparent">Indicates that transparent 
        /// elements should be ignored.</param>
        /// <returns>
        /// A array of <see cref="HitTestResult"/> objects,
        /// which provides information concerning the  chart element
        /// (if any) that is at the specified location. Result contains at least
        /// one element, which could be ChartElementType.Nothing. 
        /// The objects in the result are sorted in from top to bottom of 
        /// different layers of control. </returns>
        /// <remarks>Call this method to determine the  gauge element
        /// (if any) that is located at a specified point. Often this method is used in
        /// some mouse-related event (e.g. MouseDown)
        /// to determine what  gauge element the end-user clicked on.
        /// The X and Y mouse coordinates obtained from the
        /// event parameters are then used for the X and Y parameter              
        /// values of this method call.   The returned 
        /// <see cref="HitTestResult"/> object's properties
        /// can then be used to determine what  chart element was clicked on,
        /// and also provides a reference to the actual object selected (if 
        /// any).</remarks>
        internal HitTestResult[] HitTest(int x, int y, bool ignoreTransparent, params ChartElementType[] requestedElementTypes)
        {
            List<HitTestResult> result = new List<HitTestResult>();
            ArrayList regionList = this.ChartPicture.Common.HotRegionsList.List;
 
            if (regionList.Count == 0)
            {
                this.ChartPicture.PaintOffScreen();
            }
 
            string alowedElements = String.Empty;
            if (requestedElementTypes.Length > 0)
            {
                StringBuilder builder = new StringBuilder();
                foreach (ChartElementType elementType in requestedElementTypes)
                {
                    builder.Append(elementType.ToString() + ";");
                }
                alowedElements = builder.ToString();
            }
 
            float newX;
            float newY;
            float relativeX;
            float relativeY;
            RectangleF newMouseRect;
 
            // Find mouse position in relative and absolute coordinates
            RectangleF mouseRect = new RectangleF(x - 1, y - 1, 2, 2);
            relativeX = this.Graph.GetRelativePoint(new PointF(x, y)).X;
            relativeY = this.Graph.GetRelativePoint(new PointF(x, y)).Y;
            RectangleF relativeMouseRect = this.Graph.GetRelativeRectangle(mouseRect);
 
            // Try to pass through series object in design time.
            // The series ussualy contain autogenerated points with short lifetime - during painting;
            // This hit test result will be used in VS2005 desing time click.
            for (int index = regionList.Count - 1; index >= 0; index--)
            {
                HotRegion region = (HotRegion)regionList[index];
 
                // Check if only looking for specific chart element type
                if (!String.IsNullOrEmpty(alowedElements) && alowedElements.IndexOf(region.Type.ToString() + ";", StringComparison.Ordinal) == -1)
                {
                    continue;
                }
 
 
                // Change coordinates if relative path is used
                if (region.RelativeCoordinates)
                {
                    newX = relativeX;
                    newY = relativeY;
                    newMouseRect = relativeMouseRect;
                }
                else
                {
                    newX = (float)x;
                    newY = (float)y;
                    newMouseRect = mouseRect;
                }
 
 
                // Check if series name and point index are valid
                if (region.SeriesName.Length > 0 &&
                   (this.ChartControl.Series.IndexOf(region.SeriesName) < 0 || region.PointIndex >= this.ChartControl.Series[region.SeriesName].Points.Count)
                    )
                {
                    continue;
                }
 
                // Check if transparent chart elements should be ignored
                if (ignoreTransparent && IsElementTransparent(region))
                {
                    continue;
                }
                // Check intersection with bounding rectangle
                if (region.BoundingRectangle.IntersectsWith(newMouseRect))
                {
                    bool pointVisible = false;
 
                    if (region.Path != null)
                    {
                        // If there is more then one graphical path split them and create 
                        // image maps for every graphical path separately.
                        GraphicsPathIterator iterator = new GraphicsPathIterator(region.Path);
 
                        // There is more then one path.
                        if (iterator.SubpathCount > 1)
                        {
                            GraphicsPath subPath = new GraphicsPath();
                            while (iterator.NextMarker(subPath) > 0 && pointVisible == false)
                            {
                                if (subPath.IsVisible(newX, newY))
                                {
                                    pointVisible = true;
                                }
                                subPath.Reset();
                            }
                        }
 
                        // There is only one path
                        else if (region.Path.IsVisible(newX, newY))
                        {
                            pointVisible = true;
                        }
                    }
                    else
                    {
                        // Point is inside bounding rectangle and path is not specified
                        pointVisible = true;
                    }
 
                    // Check if point is inside the hot region
                    if (pointVisible)
                    {
                        HitTestResult hitTestToAdd = this.GetHitTestResult(
                            region.SeriesName,
                            region.PointIndex,
                            region.Type,
                            region.SelectedObject,
                            region.SelectedSubObject
                        );
 
                        int elementIndex = result.FindIndex(
                                    delegate(HitTestResult test)
                                    {
                                        if (
                                            (test.ChartElementType == hitTestToAdd.ChartElementType) &&
                                            (test.Object == hitTestToAdd.Object) &&
                                            (test.SubObject == hitTestToAdd.SubObject) &&
                                            (test.Series == hitTestToAdd.Series) &&
                                            (test.PointIndex == hitTestToAdd.PointIndex)
                                           )
                                        {
                                            return true;
                                        }
                                        return false;
                                    }
                                );
 
                        if (elementIndex == -1)
                        {
                            result.Add(hitTestToAdd);
                        }
                    }
                }
            }
            if (result.Count == 0)
            {
                result.Add(this.GetHitTestResult(String.Empty, 0, ChartElementType.Nothing, null, null));
            }
            return result.ToArray();
        }
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult objects.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
        internal HitTestResult HitTest(int x, int y)
        {
            return this.HitTest(x, y, false, new ChartElementType[] {})[0];
        }
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult object.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="ignoreTransparent">Indicates that transparent elements should be ignored.</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
        public HitTestResult HitTest(int x, int y, bool ignoreTransparent)
        {
            return this.HitTest(x, y, ignoreTransparent, new ChartElementType[] { })[0];
        }
 
        /// <summary>
        /// This method performs the hit test and returns a HitTestResult object.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="requestedElement">Only this chart element will be hit tested.</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
        public HitTestResult HitTest(int x, int y, ChartElementType requestedElement)
        {
            return this.HitTest(x, y, false, requestedElement)[0];
        }
 
        /// <summary>
        /// Checks if chart element associated with hot region has transparent background.
        /// </summary>
        /// <param name="region">Element hot region.</param>
        /// <returns>True if chart element is transparent.</returns>
        private bool IsElementTransparent(HotRegion region)
        {
            bool isTransparent = false;
 
            if (region.Type == ChartElementType.DataPoint)
            {
                if (this.ChartControl != null)
                {
                    DataPoint dataPoint = region.SelectedObject as DataPoint;
                    if (region.SeriesName.Length > 0)
                    {
                        dataPoint = this.ChartControl.Series[region.SeriesName].Points[region.PointIndex];
                    }
                    if (dataPoint != null && dataPoint.Color == Color.Transparent)
                    {
                        isTransparent = true;
                    }
                }
            }
            else if (region.SelectedObject is Axis)
            {
                if (((Axis)region.SelectedObject).LineColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is ChartArea)
            {
                if (((ChartArea)region.SelectedObject).BackColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is Legend)
            {
                if (((Legend)region.SelectedObject).BackColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is Grid)
            {
                if (((Grid)region.SelectedObject).LineColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is StripLine)
            {
                if (((StripLine)region.SelectedObject).BackColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is TickMark)
            {
                if (((TickMark)region.SelectedObject).LineColor == Color.Transparent)
                {
                    isTransparent = true;
                }
            }
            else if (region.SelectedObject is Title)
            {
                Title title = (Title)region.SelectedObject;
                if ((title.Text.Length == 0 || title.ForeColor == Color.Transparent) &&
                    (title.BackColor == Color.Transparent || title.BackColor.IsEmpty))
                {
                    isTransparent = true;
                }
            }
 
            return isTransparent;
        }
 
        /// <summary>
        /// Returns Hit Test Result object
        /// </summary>
        /// <param name="seriesName">Data series Name</param>
        /// <param name="pointIndex">Data point index</param>
        /// <param name="type">Selected Chart element type</param>
        /// <param name="obj">Selected object</param>
        /// <param name="subObject">Selected sub object</param>
        /// <returns>Hit test result object</returns>
        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
            Justification = "Too large of a code change to justify making this change")]
        internal HitTestResult GetHitTestResult(
            string seriesName,
            int pointIndex,
            ChartElementType type,
            object obj,
            object subObject)
        {
            HitTestResult result = new HitTestResult();
            Chart chart = this.ChartControl;
            // If data point is selected convert series 
            // name to series object.
            if (seriesName.Length > 0)
            {
                result.Series = chart.Series[seriesName];
            }
 
            // Selected Object
            result.Object = obj;
 
            result.SubObject = subObject;
 
            result.PointIndex = pointIndex;
            result.ChartElementType = type;
 
#if Microsoft_CONTROL
            AxisScrollBar scrollBar;
#endif // Microsoft_CONTROL
 
            switch (type)
            {
                case ChartElementType.Axis:
                    Axis axis = (Axis)obj;
                    result.Axis = axis;
                    if (axis != null)
                    {
                        result.ChartArea = axis.ChartArea;
                    }
                    break;
                case ChartElementType.DataPoint:
                    {
                        if (chart.Series.IndexOf(seriesName) >= 0 &&
                            pointIndex < chart.Series[seriesName].Points.Count)
                        {
                            DataPoint dataPoint = chart.Series[seriesName].Points[pointIndex];
                            result.Axis = null;
                            result.ChartArea = chart.ChartAreas[dataPoint.series.ChartArea];
                            result.Object = dataPoint;
                        }
                        break;
                    }
 
                case ChartElementType.DataPointLabel:
                    {
                        if (chart.Series.IndexOf(seriesName) >= 0 &&
                            pointIndex < chart.Series[seriesName].Points.Count)
                        {
                            DataPoint dataPoint = chart.Series[seriesName].Points[pointIndex];
                            result.Axis = null;
                            result.ChartArea = chart.ChartAreas[dataPoint.series.ChartArea];
                            result.Object = dataPoint;
                        }
                        break;
                    }
 
                case ChartElementType.Gridlines:
                    Grid gridLines = (Grid)obj;
                    result.Axis = gridLines.Axis;
                    if (gridLines.Axis != null)
                    {
                        result.ChartArea = gridLines.Axis.ChartArea;
                    }
                    break;
                case ChartElementType.LegendArea:
                    result.Axis = null;
                    result.ChartArea = null;
                    break;
                case ChartElementType.LegendItem:
                    result.PointIndex = ((LegendItem)obj).SeriesPointIndex;
                    result.Axis = null;
                    result.ChartArea = null;
                    break;
                case ChartElementType.PlottingArea:
                    ChartArea area = (ChartArea)obj;
                    result.Axis = null;
                    result.ChartArea = area;
                    break;
                case ChartElementType.StripLines:
                    StripLine stripLines = (StripLine)obj;
                    result.Axis = stripLines.Axis;
                    if (stripLines.Axis != null)
                    {
                        result.ChartArea = stripLines.Axis.ChartArea;
                    }
                    break;
                case ChartElementType.TickMarks:
                    TickMark tickMarks = (TickMark)obj;
                    result.Axis = tickMarks.Axis;
                    if (tickMarks.Axis != null)
                    {
                        result.ChartArea = tickMarks.Axis.ChartArea;
                    }
                    break;
                case ChartElementType.Title:
                    result.Axis = null;
                    result.ChartArea = null;
                    break;
                case ChartElementType.AxisLabels:
                    if (obj is CustomLabel)
                    {
                        CustomLabel label = (CustomLabel)obj;
                        result.Axis = label.Axis;
                        result.ChartArea = label.Axis!=null ? label.Axis.ChartArea : null;
                    }
                    break;
                case ChartElementType.AxisLabelImage:
                    if (obj is CustomLabel)
                    {
                        CustomLabel label = (CustomLabel)obj;
                        result.Axis = label.Axis;
                        result.ChartArea = label.Axis!=null ? label.Axis.ChartArea : null;
                    }
                    break;
                case ChartElementType.AxisTitle:
                    if (obj is Axis)
                    {
                        result.Axis = (Axis)obj;
                        result.ChartArea = result.Axis.ChartArea;
                    }
                    break;
#if Microsoft_CONTROL
                case ChartElementType.ScrollBarLargeDecrement:
                    scrollBar = (AxisScrollBar)obj;
                    result.Axis = scrollBar.axis;
                    if (scrollBar.axis != null)
                    {
                        result.ChartArea = scrollBar.axis.ChartArea;
                    }
                    break;
                case ChartElementType.ScrollBarLargeIncrement:
                    scrollBar = (AxisScrollBar)obj;
                    result.Axis = scrollBar.axis;
                    if (scrollBar.axis != null)
                    {
                        result.ChartArea = scrollBar.axis.ChartArea;
                    }
                    break;
                case ChartElementType.ScrollBarSmallDecrement:
                    scrollBar = (AxisScrollBar)obj;
                    result.Axis = scrollBar.axis;
                    if (scrollBar.axis != null)
                    {
                        result.ChartArea = scrollBar.axis.ChartArea;
                    }
                    break;
                case ChartElementType.ScrollBarSmallIncrement:
                    scrollBar = (AxisScrollBar)obj;
                    result.Axis = scrollBar.axis;
                    if (scrollBar.axis != null)
                    {
                        result.ChartArea = scrollBar.axis.ChartArea;
                    }
                    break;
                case ChartElementType.ScrollBarThumbTracker:
                    scrollBar = (AxisScrollBar)obj;
                    result.Axis = scrollBar.axis;
                    if (scrollBar.axis != null)
                    {
                        result.ChartArea = scrollBar.axis.ChartArea;
                    }
                    break;
#endif // Microsoft_CONTROL
 
                case ChartElementType.Annotation:
                    result.Axis = null;
                    result.ChartArea = null;
                    break;
            }
            return result;
        }
 
        #endregion //HitTest
 
        #region Outline
 
        /// <summary>
        /// Gets the chart element outline.
        /// </summary>
        /// <param name="chartObject">The chart object.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns></returns>
        internal ChartElementOutline GetChartElementOutline(object chartObject, ChartElementType elementType)
        {
            // Check arguments
            if (chartObject == null)
                throw new ArgumentNullException("chartObject");
 
            // Get outline
            ChartElementOutline result = new ChartElementOutline();
            chartObject = this.GetAutoGeneratedObject(chartObject);
            ArrayList list = this.GetMarkers(chartObject, elementType);
            result.Markers = new ReadOnlyCollection<PointF>((PointF[])list.ToArray(typeof(PointF)));
            result.OutlinePath = GetGraphicsPath(list, chartObject, elementType);
            return result;
        }
 
        #endregion //Outline
 
        #region Selection
 
        /// <summary>
        /// Gets the graphics path.
        /// </summary>
        /// <param name="markers">The markers.</param>
        /// <param name="chartObject">The chart object.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns></returns>
        private GraphicsPath GetGraphicsPath(IList markers, object chartObject, ChartElementType elementType)
        {
            bool chartArea3D = false;
            ChartArea chartArea = chartObject as ChartArea;
            if (chartArea != null && elementType == ChartElementType.PlottingArea)
            {
                chartArea3D = IsArea3D(chartArea);
            }
            if (elementType != ChartElementType.DataPoint &&
                elementType != ChartElementType.Gridlines &&
                elementType != ChartElementType.StripLines &&
                elementType != ChartElementType.TickMarks &&
                !chartArea3D
                )
            {
                GraphicsPath path = new GraphicsPath();
                PointF[] points = new PointF[markers.Count];
                markers.CopyTo(points, 0);
                if (points.Length > 3)
                {
                    if (elementType == ChartElementType.DataPointLabel)
                    {
                        for (int i = 0; i < points.Length; i += 4)
                        {
                            RectangleF rect = RectangleF.FromLTRB(points[i].X, points[i].Y, points[i + 2].X, points[i + 2].Y);
                            path.Reset();
                            path.AddRectangle(Rectangle.Round(rect));
                        }
                    }
                    else
                    {
                        if (points.Length == 4)
                        {
                            Point[] pointsAlligned = new Point[points.Length];
                            for (int i = 0; i < points.Length; i++)
                            {
                                pointsAlligned[i] = Point.Round(points[i]);
                            }
                            path.AddPolygon(pointsAlligned);
                        }
                        else
                        {
                            path.AddPolygon(points);
                        }
                    }
                }
                return path;
            }
            return null;
        }
 
        private static Int32 GetDataPointIndex(DataPoint dataPoint)
        {
            int pointIndex = -1;
            if (dataPoint != null && dataPoint.series != null)
            {
                pointIndex = dataPoint.series.Points.IndexOf(dataPoint);
                if (pointIndex == -1 && dataPoint.IsCustomPropertySet("OriginalPointIndex"))
                {
                    if (!Int32.TryParse(dataPoint.GetCustomProperty("OriginalPointIndex"), out pointIndex))
                        return -1;
                }
            }
            return pointIndex;
        }
 
        /// <summary>
        /// Gets the auto generated object.
        /// </summary>
        /// <param name="chartObject">The chart object.</param>
        /// <returns></returns>
        private object GetAutoGeneratedObject(object chartObject)
        {
            DataPoint dataPoint = chartObject as DataPoint;
            if (dataPoint != null)
            {
                if (dataPoint.series != null)
                {
                    string seriesName = dataPoint.series.Name;
                    int pointIndex = dataPoint.series.Points.IndexOf(dataPoint);
                    if (this.ChartControl.Series.IndexOf(seriesName) != -1)
                    {
                        Series series = this.ChartControl.Series[seriesName];
                        if (series.Points.Contains(dataPoint))
                        {
                            return chartObject;
                        }
                        if (pointIndex >= 0)
                        {
                            if (series.Points.Count > pointIndex)
                            {
                                return series.Points[pointIndex];
                            }
                        }
                    }
                }
            }
 
            Series asSeries = chartObject as Series;
            if (asSeries != null)
            {
                if (this.ChartControl.Series.Contains(asSeries))
                {
                    return chartObject;
                }
                if (this.ChartControl.Series.IndexOf(asSeries.Name) != -1)
                {
                    return this.ChartControl.Series[asSeries.Name];
                }
            }
            return chartObject;
        }
 
        /// <summary>
        /// Gets the hot regions.
        /// </summary>
        /// <param name="cntxObj">The CNTX obj.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns></returns>
        private HotRegion[] GetHotRegions(object cntxObj, ChartElementType elementType)
        {
            ArrayList result = new ArrayList();
            HotRegionsList hrList = this.ChartPicture.Common.HotRegionsList;
            string dataPointSeries = String.Empty;
            int dataPointIndex = -1;
 
            for (int i = hrList.List.Count - 1; i >= 0; i--)
            {
                HotRegion rgn = (HotRegion)hrList.List[i];
                if (rgn.Type == elementType)
                {
                    switch (rgn.Type)
                    {
                        case ChartElementType.LegendItem:
                            LegendItem legendItem = cntxObj as LegendItem;
                            if (legendItem != null)
                            {
                                if (((LegendItem)rgn.SelectedObject).Name == legendItem.Name)
                                {
                                    result.Add(rgn);
                                }
                            }
                            break;
                        case ChartElementType.AxisLabelImage:
                        case ChartElementType.AxisLabels:
                            CustomLabel label1 = cntxObj as CustomLabel;
                            CustomLabel label2 = rgn.SelectedObject as CustomLabel;
                            if (label1 != null)
                            {
                                if (label1 != null && label2 != null)
                                {
                                    if (label1.Axis == label2.Axis)
                                    {
                                        if (label1.FromPosition == label2.FromPosition &&
                                            label1.ToPosition == label2.ToPosition &&
                                            label1.RowIndex == label2.RowIndex)
                                        {
                                            if (rgn.Path == null)
                                            {
                                                result.Add(rgn);
                                            }
                                        }
                                    }
                                }
                            }
                            else 
                            {
                                Axis axis = cntxObj as Axis;
                                if (axis != null)
                                {
                                    if (axis == label2.Axis)
                                    {
                                        if (rgn.Path == null)
                                        {
                                            result.Add(rgn);
                                        }
                                    }
                                }
                            }
                            break;
                        case ChartElementType.DataPointLabel:
                        case ChartElementType.DataPoint:
                            DataPoint dataPoint = cntxObj as DataPoint;
                            if (dataPoint != null)
                            {
                                if (String.IsNullOrEmpty(dataPointSeries) || dataPointIndex == -1)
                                {
                                    dataPointSeries = dataPoint.series.Name;
                                    dataPointIndex = GetDataPointIndex(dataPoint);
                                }
                                if (rgn.PointIndex == dataPointIndex && rgn.SeriesName == dataPointSeries)
                                {
                                    result.Add(rgn);
                                }
                            }
                            else
                            {
                                DataPointCollection dataPointCollection = cntxObj as DataPointCollection;
                                if (dataPointCollection != null)
                                {
                                    cntxObj = dataPointCollection.series;
                                }
                                Series series = cntxObj as Series;
                                if (series != null)
                                {
                                    if (String.IsNullOrEmpty(dataPointSeries) || dataPointIndex == -1)
                                    {
                                        dataPointSeries = series.Name;
                                    }
                                    if (rgn.SeriesName == dataPointSeries)
                                    {
                                        result.Add(rgn);
                                    }
                                }
                            }
                            break;
 
                        default:
                            if (rgn.SelectedObject == cntxObj)
                            {
                                result.Add(rgn);
                            }
                            break;
                    }
                }
            }
            return (HotRegion[])result.ToArray(typeof(HotRegion));
        }
 
 
 
        /// <summary>
        /// Gets the markers from regions.
        /// </summary>
        /// <param name="chartObject">The chart object.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private ArrayList GetMarkersFromRegions(object chartObject, ChartElementType elementType)
        {
            ArrayList list = new ArrayList();
            HotRegion[] regions = this.GetHotRegions(chartObject, elementType);
            ChartGraphics graph = this.Graph;
            RectangleF rect;
 
            Grid grid = chartObject as Grid;
            if (grid != null)
            {
                foreach (HotRegion rgn in regions)
                {
                    if (!IsArea3D(grid.Axis.ChartArea))
                    {
                        if (IsChartAreaCircular(grid.Axis.ChartArea))
                        {
                            GraphicsPathIterator iterator = new GraphicsPathIterator(rgn.Path);
 
                            // There is more then one path.
                            if (iterator.SubpathCount > 1)
                            {
                                GraphicsPath subPath = new GraphicsPath();
                                while (iterator.NextMarker(subPath) > 0)
                                {
                                    rect = subPath.GetBounds();
                                    list.Add(new PointF(rect.Left + rect.Width / 2, rect.Top));
                                    list.Add(new PointF(rect.Right, rect.Top + rect.Height / 2));
                                    list.Add(new PointF(rect.Right - rect.Width / 2, rect.Bottom));
                                    list.Add(new PointF(rect.Left, rect.Bottom - rect.Height / 2));
                                    subPath.Reset();
                                }
                            }
                        }
                        else
                        {
                            // 2D
                            rect = this.GetHotRegionRectangle(rgn, RectangleF.Empty, elementType);
                            if (grid != null)
                            {
                                if (grid.GetAxis().AxisPosition == AxisPosition.Bottom ||
                                    grid.GetAxis().AxisPosition == AxisPosition.Top)
                                {
                                    rect.Offset(rect.Width / 2, 0);
                                    rect.Width = 0;
                                }
                                else
                                {
                                    rect.Offset(0, rect.Height / 2);
                                    rect.Height = 0;
                                }
                            }
                            list.AddRange(this.GetMarkers(rect, false));
                        }
                    }
                    else
                    {   // 3D
                        PointF[] points = rgn.Path.PathPoints;
                        for (int i = 0; i < points.Length - 3; i = i + 4)
                        {   //Each gridline has a corresponding set of 4 points in the path
                            //One of  the ends of a gridline is in the middle the line between points #0 and #3
                            //Another ends of a gridline is in the middle the line between points #1 and #2
                            //So we find those middles and put a marks to the ends of the gridline.
                            PointF middleP0P3 = new PointF((points[i].X + points[i + 3].X) / 2f, (points[i].Y + points[i + 3].Y) / 2f);
                            PointF middleP1P2 = new PointF((points[i + 1].X + points[i + 2].X) / 2f, (points[i + 1].Y + points[i + 2].Y) / 2f);
                            list.Add(graph.GetAbsolutePoint(middleP0P3));
                            list.Add(graph.GetAbsolutePoint(middleP1P2));
                        }
                    }
                }
                return list;
            }
 
            DataPoint dataPoint = chartObject as DataPoint;
            if (dataPoint != null && elementType != ChartElementType.DataPointLabel)
            {
                rect = Rectangle.Empty;
                Series series = dataPoint.series;
                if (this.ChartControl.ChartAreas.IndexOf(series.ChartArea) == -1)
                {
                    return list;
                }
                ChartArea area = this.ChartControl.ChartAreas[series.ChartArea];
                PointF pp = this.Transform3D(area, dataPoint);
                if (!(float.IsNaN(pp.X) || float.IsNaN(pp.Y)))
                {
                    list.Add(graph.GetAbsolutePoint(pp));
                }
                return list;
            }
 
            Axis axis = chartObject as Axis;
            if (axis != null && elementType == ChartElementType.AxisTitle)
            {
                foreach (HotRegion rgn in regions)
                {
                    if (!IsArea3D(axis.ChartArea))
                    {   // 2D
                        rect = this.GetHotRegionRectangle(rgn, RectangleF.Empty, elementType);
                        list.AddRange(this.GetMarkers(rect, elementType));
                    }
                    else
                    {   // 3D
                        PointF[] points = rgn.Path.PathPoints;
                        list.AddRange(points);
                    }
                }
                return list;
            }
 
            LegendItem legendItem = chartObject as LegendItem;
            if (legendItem != null)
            {
                rect = Rectangle.Empty;
                foreach (HotRegion rgn in regions)
                {
                    rect = this.GetHotRegionRectangle(rgn, rect, elementType);
                }
                if (!rect.IsEmpty)
                {
                    list.AddRange(this.GetMarkers(rect, elementType));
                }
                return list;
            }
            else if (chartObject is Annotation)
            {
                rect = Rectangle.Empty;
                foreach (HotRegion rgn in regions)
                {
                    rect = this.GetHotRegionRectangle(rgn, rect, elementType);
                }
                if (!rect.IsEmpty)
                {
                    list.AddRange(this.GetMarkers(rect, elementType));
                }
                return list;
            }
            foreach (HotRegion rgn in regions)
            {
                rect = this.GetHotRegionRectangle(rgn, RectangleF.Empty, elementType);
                list.AddRange(this.GetMarkers(rect, elementType));
            }
            return list;
 
        }
 
 
        /// <summary>
        /// Gets the markers.
        /// </summary>
        /// <param name="chartObject">The chart object.</param>
        /// <param name="elementType">Type of the element.</param>
        /// <returns></returns>
        private ArrayList GetMarkers(object chartObject, ChartElementType elementType)
        {
            ChartArea chartArea = chartObject as ChartArea;
            if (chartArea != null)
            {
                return this.GetAreaMarkers(this.Graph, chartArea);
            }
 
 
            Axis axis = chartObject as Axis;
            if (axis != null)
            {
                if (
                    elementType == ChartElementType.AxisLabelImage ||
                    elementType == ChartElementType.AxisLabels ||
                    elementType == ChartElementType.AxisTitle
                    )
                {
                    return this.GetMarkersFromRegions(chartObject, elementType);
                }
                return this.GetAxisMarkers(this.Graph, axis);
            }
 
            DataPoint dataPoint = chartObject as DataPoint;
            if (dataPoint != null)
            {
                return this.GetMarkersFromRegions(chartObject, elementType);
            }
 
            Series series = chartObject as Series;
            if (series != null)
            {
                if (elementType == ChartElementType.DataPointLabel)
                {
                    return this.GetMarkersFromRegions(chartObject, elementType);
                }
                return this.GetSeriesMarkers(series);
            }
 
            return this.GetMarkersFromRegions(chartObject, elementType);
        }
 
        /// <summary>
        /// Determines whether specified chart area is circular or not have axes. These chart areas contain pie, doughnut, polar, radar
        /// </summary>
        /// <param name="area">The area.</param>
        /// <returns>
        /// 	<c>true</c> if specified chart area is circular; otherwise, <c>false</c>.
        /// </returns>
        private Boolean IsChartAreaCircular(ChartArea area)
        {
            foreach (object o in area.ChartTypes)
            {
                ChartTypes.IChartType chartType = area.Common.ChartTypeRegistry.GetChartType(o.ToString());
                if (chartType != null && (chartType.CircularChartArea || !chartType.RequireAxes))
                {
                    return true;
                }
            }
            return false;
        }
 
        /// <summary>
        /// Determines whether the chart area is in 3D mode.
        /// </summary>
        /// <param name="area">The area.</param>
        /// <returns>
        /// 	<c>true</c> if the chart area is in 3D mode; otherwise, <c>false</c>.
        /// </returns>
        private Boolean IsArea3D(ChartArea area)
        {
            return area.Area3DStyle.Enable3D && !this.IsChartAreaCircular(area) && area.matrix3D != null && area.matrix3D.IsInitialized();
        }
 
        /// <summary>
        /// Gets the series markers.
        /// </summary>
        /// <param name="series">The series.</param>
        /// <returns>List of PointF.</returns>
        private ArrayList GetSeriesMarkers(Series series)
        {
            ArrayList list = new ArrayList();
            if (series != null)
            {
                String areaName = series.ChartArea;
 
                if (String.IsNullOrEmpty(areaName))
                {
                    areaName = ChartPicture.ChartAreas.DefaultNameReference;
                }
 
                if (ChartPicture.ChartAreas.IndexOf(areaName) != -1 && series.Enabled)
                {
 
                    ChartArea chartArea = ChartPicture.ChartAreas[areaName];
 
                    if (ChartControl.Series.IndexOf(series.Name) != -1)
                    {
                        series = ChartControl.Series[series.Name];
                    }
 
                    DataPointCollection points = series.Points;
                    // in design mode we have usually fake points
                    if (points.Count == 0)
                    {
                        points = series.fakeDataPoints;
                    }
                    // transform points in 3D
                    foreach (DataPoint point in points)
                    {
                        PointF pp = this.Transform3D(chartArea, point);
                        if (float.IsNaN(pp.X) || float.IsNaN(pp.Y))
                        {
                            continue;
                        }
                        list.Add(this.Graph.GetAbsolutePoint(pp));
                    }
                }
            }
            return list;
        }
 
        /// <summary>
        /// Gets the axis markers - list of points where markers are drawn.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="axis">The axis.</param>
        /// <returns>List of PointF.</returns>
        private ArrayList GetAxisMarkers(ChartGraphics graph, Axis axis)
        {
            ArrayList list = new ArrayList();
            if (axis == null)
            {
                return list;
            }
            PointF first = PointF.Empty;
            PointF second = PointF.Empty;
 
            // Set the position of axis
            switch (axis.AxisPosition)
            {
 
                case AxisPosition.Left:
 
                    first.X = (float)axis.GetAxisPosition();
                    first.Y = axis.PlotAreaPosition.Y;
                    second.X = (float)axis.GetAxisPosition();
                    second.Y = axis.PlotAreaPosition.Bottom;
                    first.X -= axis.labelSize + axis.markSize;
                    break;
 
                case AxisPosition.Right:
 
                    first.X = (float)axis.GetAxisPosition();
                    first.Y = axis.PlotAreaPosition.Y;
                    second.X = (float)axis.GetAxisPosition();
                    second.Y = axis.PlotAreaPosition.Bottom;
                    second.X += axis.labelSize + axis.markSize;
                    break;
 
                case AxisPosition.Bottom:
 
                    first.X = axis.PlotAreaPosition.X;
                    first.Y = (float)axis.GetAxisPosition();
                    second.X = axis.PlotAreaPosition.Right;
                    second.Y = (float)axis.GetAxisPosition();
                    second.Y += axis.labelSize + axis.markSize;
                    break;
 
                case AxisPosition.Top:
 
                    first.X = axis.PlotAreaPosition.X;
                    first.Y = (float)axis.GetAxisPosition();
                    second.X = axis.PlotAreaPosition.Right;
                    second.Y = (float)axis.GetAxisPosition();
                    first.Y -= axis.labelSize + axis.markSize;
                    break;
            }
 
            // Update axis line position for circular area
            if (axis.ChartArea.chartAreaIsCurcular)
            {
                second.Y = axis.PlotAreaPosition.Y + axis.PlotAreaPosition.Height / 2f;
            }
 
            RectangleF rect1 = new RectangleF(first.X, first.Y, second.X - first.X, second.Y - first.Y);
 
            SizeF size = graph.GetRelativeSize(new SizeF(3, 3));
            if (axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom)
            {
                rect1.Inflate(2, size.Height);
            }
            else
            {
                rect1.Inflate(size.Width, 2);
            }
            IList list1 = this.GetMarkers(rect1, ChartElementType.Axis);
            ChartArea area = axis.ChartArea;
            if (this.IsArea3D(area))
            {
 
                Boolean axisOnEdge = false;
                float zPositon = axis.GetMarksZPosition(out axisOnEdge);
 
                // Transform coordinates
                Point3D[] points = new Point3D[list1.Count];
                for (int i = 0; i < list1.Count; i++)
                {
                    points[i] = new Point3D(((PointF)list1[i]).X, ((PointF)list1[i]).Y, zPositon);
                }
                axis.ChartArea.matrix3D.TransformPoints(points);
                for (int i = 0; i < list1.Count; i++)
                {
                    list1[i] = points[i].PointF;
                }
            }
            foreach (PointF p in list1)
            {
                list.Add(graph.GetAbsolutePoint(p));
            }
            return list;
        }
 
        /// <summary>
        /// Gets the area markers.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="area">The area.</param>
        /// <returns>List of PointF.</returns>
        private ArrayList GetAreaMarkers(ChartGraphics graph, ChartArea area)
        {
            ArrayList list = new ArrayList();
            if (area == null)
            {
                return list;
            }
            IList list1 = this.GetMarkers(area.PlotAreaPosition.ToRectangleF(), ChartElementType.PlottingArea);
            if (this.IsChartAreaCircular(area))
            {
                list1 = this.GetMarkers(area.lastAreaPosition, ChartElementType.PlottingArea);
            }
            if (IsArea3D(area))
            {
                float zPositon = 0; // area.areaSceneDepth;
                // Transform coordinates
                Point3D[] points = new Point3D[list1.Count];
                for (int i = 0; i < list1.Count; i++)
                {
                    points[i] = new Point3D(((PointF)list1[i]).X, ((PointF)list1[i]).Y, zPositon);
                }
                area.matrix3D.TransformPoints(points);
                for (int i = 0; i < list1.Count; i++)
                {
                    list1[i] = points[i].PointF;
                }
            }
            foreach (PointF p in list1)
            {
                list.Add(graph.GetAbsolutePoint(p));
            }
            return list;
        }
 
        /// <summary>
        /// Builds list of markers (PointF) based on rectangle
        /// </summary>
        /// <param name="rect">The rectangle</param>
        /// <param name="elementType">The type of chart elements to retrieve.</param>
        /// <returns>List of PointF</returns>
        private ArrayList GetMarkers(RectangleF rect, ChartElementType elementType)
        {
            if (elementType.ToString().StartsWith("Legend", StringComparison.Ordinal) || elementType.ToString().StartsWith("Title", StringComparison.Ordinal))
            {
                rect.Inflate(4f, 4f);
            }
            if (elementType.ToString().StartsWith("PlottingArea", StringComparison.Ordinal))
            {
                SizeF relSize = this.Graph.GetRelativeSize(new SizeF(4f, 4f));
                rect.Inflate(relSize.Width, relSize.Height);
            }
 
            if ((elementType != ChartElementType.Nothing) && (elementType != ChartElementType.PlottingArea))
            {
                return this.GetMarkers(rect, false);
            }
            return this.GetMarkers(rect, true);
        }
 
 
        /// <summary>
        /// Builds list of markers (PointF) based on rectangle
        /// </summary>
        /// <param name="rect">The rectangle</param>
        /// <param name="addAdditionalMarkers">Add additional markers to the rectangle.</param>
        /// <returns>List of PointF</returns>
        private ArrayList GetMarkers(RectangleF rect, Boolean addAdditionalMarkers)
        {
            ArrayList list = new ArrayList();
            if (!addAdditionalMarkers)
            {
                if (rect.Width > 0 && rect.Height > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Top));
                    list.Add(new PointF(rect.Right, rect.Top));
                    list.Add(new PointF(rect.Right, rect.Bottom));
                    list.Add(new PointF(rect.Left, rect.Bottom));
                }
                else if (rect.Width > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Top));
                    list.Add(new PointF(rect.Right, rect.Top));
                }
                else if (rect.Height > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Top));
                    list.Add(new PointF(rect.Left, rect.Bottom));
                }
            }
            else
            {
                if (rect.Width > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Top));
 
                    if (rect.Width > 30)
                    {
                        list.Add(new PointF(rect.Left + rect.Width / 2, rect.Top));
                    }
 
                    list.Add(new PointF(rect.Right, rect.Top));
 
                    if (rect.Height > 30)
                    {
                        list.Add(new PointF(rect.Right, rect.Top + rect.Height / 2));
                    }
 
                    list.Add(new PointF(rect.Right, rect.Bottom));
                    if (rect.Width > 30)
                    {
                        list.Add(new PointF(rect.Left + rect.Width / 2, rect.Bottom));
                    }
 
                    list.Add(new PointF(rect.Left, rect.Bottom));
                    if (rect.Height > 30)
                    {
                        list.Add(new PointF(rect.Left, rect.Top + rect.Height / 2));
                    }
                }
 
                else if (rect.Width > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Top));
 
                    if (rect.Width > 30)
                    {
                        list.Add(new PointF(rect.Left + rect.Width / 2, rect.Top));
                    }
 
                    list.Add(new PointF(rect.Right, rect.Top));
                }
                else if (rect.Height > 0)
                {
                    list.Add(new PointF(rect.Left, rect.Bottom));
                    if (rect.Height > 30)
                    {
                        list.Add(new PointF(rect.Left, rect.Top + rect.Height / 2));
                    }
                    list.Add(new PointF(rect.Left, rect.Top));
                }
            }
            return list;
        }
 
        /// <summary>
        /// Gets the region markers from graphics path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>List of PointF.</returns>
        private ArrayList GetRegionMarkers(GraphicsPath path)
        {
            return new ArrayList(path.PathPoints);
        }
 
        /// <summary>
        /// Calculates a DataPoint of 3D area into PointF to draw.
        /// </summary>
        /// <param name="chartArea">3D chart area</param>
        /// <param name="point">The DataPoint</param>
        /// <returns>Calculated PointF</returns>
        private PointF Transform3D(ChartArea chartArea, DataPoint point)
        {
            if (chartArea is ChartArea && IsArea3D(chartArea))
            {
                // Get anotation Z coordinate (use scene depth or anchored point Z position)
                float positionZ = chartArea.areaSceneDepth;
                if (point != null && point.series != null)
                {
                    float depth = 0f;
                    chartArea.GetSeriesZPositionAndDepth(
                        point.series,
                        out depth,
                        out positionZ);
                    positionZ += depth / 2f;
                }
 
                PointF pf = point.positionRel;
 
                // Define 3D points of annotation object
                Point3D[] annot3DPoints = new Point3D[1];
                annot3DPoints[0] = new Point3D(pf.X, pf.Y, positionZ);
 
                // Tranform cube coordinates
                chartArea.matrix3D.TransformPoints(annot3DPoints);
 
                return annot3DPoints[0].PointF;
            }
            return point.positionRel;
        }
 
        /// <summary>
        /// Gets the hot region rectangle.
        /// </summary>
        /// <param name="rgn">The hot region.</param>
        /// <param name="unionWith">The rectangle to union with.</param>
        /// <param name="elementType">The type of the element.</param>
        /// <returns>Returns the rectangle around the hot region.</returns>
        private RectangleF GetHotRegionRectangle(HotRegion rgn, RectangleF unionWith, ChartElementType elementType)
        {
            RectangleF rect;
            if (rgn.Path != null)
            {
                rect = rgn.Path.GetBounds();
            }
            else
            {
                rect = rgn.BoundingRectangle;
            }
            if (rgn.RelativeCoordinates)
            {
                rect = this.Graph.GetAbsoluteRectangle(rect);
            }
            if (elementType == ChartElementType.AxisLabels)
            {
                if (rect.Width > rect.Height)
                {
                    rect.Inflate(-5, -2);
                }
                else if (rect.Width < rect.Height)
                {
                    rect.Inflate(-2, -5);
                }
            }
            if (!unionWith.IsEmpty)
            {
                return RectangleF.Union(unionWith, rect);
            }
            return rect;
        }
 
        #endregion //Selection
 
        #endregion //Tooltips
 
        #region IServiceProvider Members
 
        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <param name="serviceType">An object that specifies the type of service object to get.</param>
        /// <returns>
        /// A service object of type <paramref name="serviceType"/>.  It returns null 
        /// if there is no service object of type <paramref name="serviceType"/>.
        /// </returns>
        object IServiceProvider.GetService(Type serviceType)
        {
            if (serviceType == typeof(Selection))
            {
                return this;
            }
            if (_service != null)
            {
                return _service.GetService(serviceType);
            }
            return null;
        }
 
        #endregion
 
	}
 
 
#if Microsoft_CONTROL
	/// <summary>
    /// The ToolTipEventArgs class stores the tool tips event arguments.
	/// </summary>
	public class ToolTipEventArgs : EventArgs
	{
    #region Private fields

		// Private fields for properties values storage
		private		int					x = 0;
		private		int					y = 0;
		private		string				text = "";
		private		HitTestResult		result = new HitTestResult();
		
        #endregion

    #region Constructors
				
		/// <summary>
        /// ToolTipEventArgs constructor.  Creates ToolTip event arguments.
		/// </summary>
		/// <param name="x">X-coordinate of mouse.</param>
		/// <param name="y">Y-coordinate of mouse.</param>
		/// <param name="text">Tooltip text.</param>
		/// <param name="result">Hit test result object.</param>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification = "X and Y are cartesian coordinates and well understood")]
        public ToolTipEventArgs(int x, int y, string text, HitTestResult result)
		{
			this.x = x;
			this.y = y;
			this.text = text;
			this.result = result;
		}
 
        #endregion

    #region Properties

		/// <summary>
        /// Gets the x-coordinate of the mouse.
		/// </summary>
		[
		SRDescription("DescriptionAttributeToolTipEventArgs_X"),
		]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
        public int X
		{
			get
			{
				return x;
			}
		}
 
		/// <summary>
        /// Gets the result of the hit test.
		/// </summary>
		[
		SRDescription("DescriptionAttributeToolTipEventArgs_HitTestResult"),
		]
		public HitTestResult HitTestResult
		{
			get
			{
				return result;
			}
		}
 
		/// <summary>
        /// Gets the y-coordinate of the mouse.
		/// </summary>
		[
		SRDescription("DescriptionAttributeToolTipEventArgs_Y"),
		]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
        public int Y
		{
			get
			{
				return y;
			}
		}
 
		/// <summary>
        /// Gets the text of the tooltip.
		/// </summary>
		[
		SRDescription("DescriptionAttributeToolTipEventArgs_Text"),
		]
		public string Text
		{
			get
			{
				return text;
			}
			set
			{
				text = value;
			}
		}
 
        #endregion	
	}
 
#endif // #if Microsoft_CONTROL
}