File: Common\General\Legend.cs
Project: ndp\fx\src\DataVisualization\System.Web.DataVisualization.csproj (System.Web.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		Legend.cs
//
//  Namespace:	DataVisualization.Charting
//
//	Classes:	Legend, LegendCollection, LegendItemsCollection, 
//              LegendItem
//
//  Purpose:	Chart Legend consist of default and custom legend 
//              items. Default items are automatically added based
//              on the data series and custom items are added by
//              the user. Each item usually consist of 2 cells; 
//              series color marker and series name. Legend item 
//              cells form vertical columns in the legend.
//  
//              Please refer to the Chart documentation which 
//              contains images and samples describing legend features.
//
//  NOTE: In early versions of the Chart control only 1 legend was 
//  exposed through the Legend property of the root chart object. 
//  Due to the customer requests, support for unlimited number of 
//  legends was added through the LegendCollection exposed as a 
//  Legends property in the root chart object. Old propertys was 
//  deprecated and marked as non-browsable. 
//
//	Reviewed:	AG - Jul 31, 2002; 
//              GS - Aug 7, 2002
//              AG - Microsoft 14, 2007
//
//===================================================================
 
#region Used namespaces
 
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
 
#if Microsoft_CONTROL
	using System.Windows.Forms.DataVisualization.Charting.Data;
	using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
	using System.Windows.Forms.DataVisualization.Charting.Utilities;
	using System.Windows.Forms.DataVisualization.Charting.Borders3D;
	using System.Windows.Forms.DataVisualization.Charting;
	using System.ComponentModel.Design.Serialization;
	using System.Reflection;
	using System.Windows.Forms.Design;
#else
	using System.Web;
	using System.Web.UI;
	using System.Web.UI.DataVisualization.Charting;
	using System.Web.UI.DataVisualization.Charting.Data;
	using System.Web.UI.DataVisualization.Charting.Utilities;
	using System.Web.UI.DataVisualization.Charting.ChartTypes;
#endif
 
 
#endregion
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
 
#endif
{
	#region Legend enumerations
 
    /// <summary>
    /// An enumeration of legend item orderings.
    /// </summary>
    public enum LegendItemOrder
    {
        /// <summary>
        /// Items will be added into the legend in an order automatically determined by the chart.
        /// </summary>
        Auto,
 
        /// <summary>
        /// Items will be added into the legend in the same order as the chart series.
        /// </summary>
        SameAsSeriesOrder,
 
        /// <summary>
        /// Items will be added into the legend in the same order as the chart series.
        /// </summary>
        ReversedSeriesOrder
 
    };
 
	/// <summary>
	/// An enumeration of legend separator styles.
	/// </summary>
	public enum LegendSeparatorStyle
	{
		/// <summary>
		/// No separator will be shown.
		/// </summary>
		None,
 
        /// <summary>
        /// Single solid line separator.
        /// </summary>
		Line,
 
        /// <summary>
        /// Single solid thick line separator.
        /// </summary>
		ThickLine,
 
		/// <summary>
		/// Double solid line separator.
		/// </summary>
		DoubleLine,
 
		/// <summary>
		/// Single dash line separator.
		/// </summary>
		DashLine,
 
		/// <summary>
		/// Single dot line separator.
		/// </summary>
		DotLine,
 
		/// <summary>
		/// Gradient solid line separator.
		/// </summary>
		GradientLine,
 
		/// <summary>
		/// Thick gradient solid line separator.
		/// </summary>
		ThickGradientLine,
	}
 
 
 
	/// <summary>
    /// An enumeration that specifies a style for a legend item's symbol.
	/// </summary>
	public enum LegendImageStyle
	{
		/// <summary>
        /// The symbol will be a rectangle.
		/// </summary>
		Rectangle, 
 
		/// <summary>
        /// The symbol will be a line.
		/// </summary>
		Line, 
 
		/// <summary>
        /// The symbol will be a marker.
		/// </summary>
		Marker
	}
 
	/// <summary>
	/// An enumeration of legend styles.
	/// </summary>
	public enum LegendStyle
	{
		/// <summary>
		/// One column, many rows.
		/// </summary>
		Column, 
 
		/// <summary>
		/// One row, many columns.
		/// </summary>
		Row, 
 
		/// <summary>
		/// Many column, many rows.
		/// </summary>
		Table
	};
 
	/// <summary>
	/// An enumeration of legend table styles.
	/// </summary>
	public enum LegendTableStyle
	{
		/// <summary>
        /// The legend table style is automatically determined by the chart.
		/// </summary>
		Auto, 
 
		/// <summary>
        /// The legend items will be fit horizontally within the legend.  
        /// It is preferred to use this style when the docking is set to top or bottom.
		/// </summary>
		Wide, 
 
		/// <summary>
        /// The legend items will be fit vertically within the legend.  
        /// It is preferred to use this style when docking is set to left or right.
		/// </summary>
		Tall
	};
	
	#endregion
 
    /// <summary>
    /// The legend class represents a single chart legend. It contains visual
    /// appearance, position and content properties. This class is also 
    /// responsible for drawing and positioning of the legend.
    /// </summary>
	[
	SRDescription("DescriptionAttributeLegend_Legend"),
	DefaultProperty("Enabled"),
	]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class Legend : ChartNamedElement
	{
	    #region Fields
 
        //***********************************************************
		//** Private data members, which store properties values
		//***********************************************************
		private ElementPosition			_position = null;
		private bool					_enabled = true;
 
		private LegendStyle				_legendStyle = LegendStyle.Table;
 
		private	LegendTableStyle		_legendTableStyle = LegendTableStyle.Auto;
		private LegendItemsCollection	_customLegends = null;
		private ChartHatchStyle			_backHatchStyle = ChartHatchStyle.None;
		private string					_backImage = "";
		private ChartImageWrapMode		_backImageWrapMode = ChartImageWrapMode.Tile;
		private Color					_backImageTransparentColor = Color.Empty;
		private ChartImageAlignmentStyle	_backImageAlignment = ChartImageAlignmentStyle.TopLeft;
		private GradientStyle			_backGradientStyle = GradientStyle.None;
		private Color					_backSecondaryColor = Color.Empty;
		private Color					_borderColor = Color.Empty;
		private Color					_backColor = Color.Empty;
		private int						_borderWidth = 1;
		private ChartDashStyle			_borderDashStyle = ChartDashStyle.Solid;
        private FontCache               _fontCache = new FontCache();
        private Font                    _font = null;
		private Color					_foreColor = Color.Black;
		private StringAlignment			_legendAlignment = StringAlignment.Near;
		private Docking			        _legendDocking = Docking.Right;
		private int						_shadowOffset = 0;
		private Color					_shadowColor = Color.FromArgb(128, 0, 0, 0);
		private bool					_isTextAutoFit = true;
        private string                  _dockedToChartArea = Constants.NotSetValue;
		private bool					_isDockedInsideChartArea = true;
 
		//***********************************************************
		//** Private data members
		//***********************************************************
 
		// Collection of custom and series legend items
		internal LegendItemsCollection	legendItems = null;
 
		// Number of rows and columns
		private int		_itemColumns = 0;
 
 
		// Font calculated by auto fitting
		internal Font	autofitFont = null;
 
		// Indicates that all items in the legend should be equally spaced
		private	bool	_isEquallySpacedItems = false;
 
 
		// Indicate that legend rows should be drawn with isInterlaced background color.
		private bool		_interlacedRows = false;
 
		// Legend isInterlaced rows color
		private Color		_interlacedRowsColor = Color.Empty;
 
		// Legend offsets
		private Size		_offset = Size.Empty;
 
		// Adjustment point used for legend animation
		private float		_maximumLegendAutoSize = 50f;
 
		// Text length after which the legend item text will be wrapped on the next whitespace.
		private int			_textWrapThreshold = 25;
 
		// Value used to calculate auto-fit font size from the legend Font.
		private int			_autoFitFontSizeAdjustment = 0;
 
		// Legend column collection
		private LegendCellColumnCollection _cellColumns = null;
 
		// Indicates that legend items automatically added based on the exsisting 
		// series in reversed order.
        private LegendItemOrder _legendItemOrder = LegendItemOrder.Auto;
 
		// Legend title text
		private	string		_title = String.Empty;
 
		// Legend title color
		private Color		_titleForeColor = Color.Black;
 
		// Legend title back color
		private Color		_titleBackColor = Color.Empty;
 
		// Legend title font
		private Font		_titleFont = null;
 
		// Legend title alignment
		private StringAlignment		_titleAlignment = StringAlignment.Center;
 
		// Legend title visual separator
		private LegendSeparatorStyle	_titleSeparator = LegendSeparatorStyle.None;
 
		// Legend title visual separator color
		private Color		_titleSeparatorColor = Color.Black;
 
		// Legend header visual separator
		private LegendSeparatorStyle	_headerSeparator = LegendSeparatorStyle.None;
 
		// Legend header visual separator color
		private Color		_headerSeparatorColor = Color.Black;
 
		// Legend table columns visual separator
		private LegendSeparatorStyle	_itemColumnSeparator = LegendSeparatorStyle.None;
 
		// Legend table columns visual separator color
		private Color		_itemColumnSeparatorColor = Color.Black;
 
		// Legend table column spacing calculated as a percentage of the font
		private int			_itemColumnSpacing = 50;
 
		// Legend table column spacing calculated in relative coordinates
		private int		_itemColumnSpacingRel = 0;
 
		// Legend title position in pixelcoordinates.
		// Note that legend title always docked to the top of the legend.
		private	Rectangle	_titlePosition = Rectangle.Empty;
 
		// Legend header position in pixel coordinates.
		private	Rectangle	_headerPosition = Rectangle.Empty;
 
		// Minimum font size that can be used by the legend auto-fitting algorithm
		private int			_autoFitMinFontSize = 7;
 
		// Horizontal space left after fitting legend items
		private int		_horizontalSpaceLeft = 0;
 
		// Vertical space left after fitting legend items
		private int		_verticalSpaceLeft = 0;
 
		// Sub-columns sizes calculated during the fitting process
		private int[,]	_subColumnSizes = null;
 
		// Legend item heigts
		private int[,]	_cellHeights = null;
 
		// Number of rows per each legend table column
		private int[]		_numberOfRowsPerColumn = null;
 
		// Number of items from the collection that should be processed
		private int			_numberOfLegendItemsToProcess = -1;
 
		// Legend items area position in pixels
		private Rectangle	_legendItemsAreaPosition = Rectangle.Empty;
 
		// Indicates that not all legend items were able to fit the legend
		private bool		_legendItemsTruncated = false;
 
		// Size of the dots (pixels) that will drawn on the bottom of the legend when it is truncated
		private	int			_truncatedDotsSize = 3;
 
		// Maximum number of cells in the legend item
		private	int			_numberOfCells = -1;
 
		// Pixel size of the 'W' character
		internal Size		singleWCharacterSize = Size.Empty;
 
 
		#endregion
 
		#region Constructors
 
		/// <summary>
		/// Legend constructor
		/// </summary>
		public Legend()
		{
            _position = new ElementPosition(this);
            // Initialize custom items collection
			_customLegends = new LegendItemsCollection(this);
			legendItems = new LegendItemsCollection(this);
			_cellColumns = new LegendCellColumnCollection(this);
            _font = _fontCache.DefaultFont;
            _titleFont = _fontCache.DefaultBoldFont;
		}
 
        /// <summary>
        /// Legend constructor
        /// </summary>
        /// <param name="name">The legend name.</param>
        public Legend(string name) : base (name)
        {
            _position = new ElementPosition(this);
            // Initialize custom items collection
            _customLegends = new LegendItemsCollection(this);
            legendItems = new LegendItemsCollection(this);
            _cellColumns = new LegendCellColumnCollection(this);
            _font = _fontCache.DefaultFont;
            _titleFont = _fontCache.DefaultBoldFont;
        }
 
		#endregion
 
		#region Legend position & size methods
 
		/// <summary>
		/// Recalculates legend information:
		///   - legend items collection
		///   - maximum text rectangle
		/// </summary>
		/// <param name="chartGraph">Reference to the chart graphics.</param>
		private void RecalcLegendInfo(ChartGraphics chartGraph)
		{
			// Reset some values
			RectangleF	legendPositionRel = _position.ToRectangleF();
			Rectangle	legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(legendPositionRel));
 
			//***********************************************************
			//** Use size of the "W" characters in current font to 
			//** calculate legend spacing
			//***********************************************************
			this.singleWCharacterSize =  chartGraph.MeasureStringAbs("W", this.Font);
			Size doubleCharacterSize =  chartGraph.MeasureStringAbs("WW", this.Font);
			this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
			
			// Calculate left, top offset and column spacing
			this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
			this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
 
			// Calculate item column spacing and make sure it is dividable by 2
			this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
			if(this._itemColumnSpacingRel % 2 == 1)
			{
				this._itemColumnSpacingRel += 1;
			}
 
			//***********************************************************
			//** Calculate how much space required for the title.
			//***********************************************************
			this._titlePosition = Rectangle.Empty;
			if(this.Title.Length > 0)
			{
				// Measure title text size
				Size titleSize = this.GetTitleSize(chartGraph, legendPosition.Size);
 
				// Set legend title position
				this._titlePosition = new Rectangle(
					legendPosition.Location.X,
					legendPosition.Location.Y,
					legendPosition.Width,
					Math.Min(legendPosition.Height, titleSize.Height));
 
				// Adjust legend items position height
				legendPosition.Height -= this._titlePosition.Height;
 
				// Increase title top location by border height
				this._titlePosition.Y += this.GetBorderSize();
			}
 
 
			//***********************************************************
			//** Calculate how much space required for the header.
			//***********************************************************
			this._headerPosition = Rectangle.Empty;
 
			// Find the largest (height only) header
			Size highestHeader = Size.Empty;
			foreach(LegendCellColumn legendColumn in this.CellColumns)
			{
				if(legendColumn.HeaderText.Length > 0)
				{
					// Measure header text size
					Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
 
					// Get header with maximum height
					highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
				}
			}
 
			// Check if any headers where found
			if(!highestHeader.IsEmpty)
			{
				// Set legend header position
				this._headerPosition = new Rectangle(
					legendPosition.Location.X + this.GetBorderSize() + this._offset.Width,
					legendPosition.Location.Y + this._titlePosition.Height,
					legendPosition.Width - (this.GetBorderSize() + this._offset.Width) * 2,
					Math.Min(legendPosition.Height - this._titlePosition.Height, highestHeader.Height));
				this._headerPosition.Height = Math.Max(this._headerPosition.Height, 0);
 
				// Adjust legend items position height
				legendPosition.Height -= this._headerPosition.Height;
 
				// Increase header top location by border height
				this._headerPosition.Y += this.GetBorderSize();
			}
 
 
			//***********************************************************
			//** Calculate size available for all legend items
			//***********************************************************
			this._legendItemsAreaPosition = new Rectangle(
				legendPosition.X + this._offset.Width + this.GetBorderSize(),
				legendPosition.Y + this._offset.Height + this.GetBorderSize() + this._titlePosition.Height + this._headerPosition.Height,
				legendPosition.Width - 2 * (this._offset.Width + this.GetBorderSize()),
				legendPosition.Height - 2 * (this._offset.Height + this.GetBorderSize()) );
 
			//***********************************************************
			//** Calculate number of rows and columns depending on
			//** the legend style
			//***********************************************************
			this.GetNumberOfRowsAndColumns(
				chartGraph, 
				this._legendItemsAreaPosition.Size,
				-1,
				out this._numberOfRowsPerColumn, 
				out this._itemColumns,
				out this._horizontalSpaceLeft,
				out this._verticalSpaceLeft);
 
			//***********************************************************
			//** Try to fit all legend item cells reducing the font size
			//***********************************************************
 
			// Reset auto-fit font adjustment value and truncated legend flag
			this._autoFitFontSizeAdjustment = 0;
			this._legendItemsTruncated = false;
 
			// Check if legend items fit into the legend area
			bool autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
 
			// Calculate total number of items fit and make sure we fit all of them
			this._numberOfLegendItemsToProcess = this.legendItems.Count;
			int itemsFit = 0;
			for(int index = 0; index < this._itemColumns; index++)
			{
				itemsFit += this._numberOfRowsPerColumn[index];
			}
			if(itemsFit < this._numberOfLegendItemsToProcess)
			{
				autoFitDone = false;
			}
 
            // If items do not fit try reducing font or number of legend items
            this.autofitFont = this.Font;
			if(!autoFitDone)
			{
				do
				{
					// Check if legend item font size can be reduced
					if(this.IsTextAutoFit && 
						(this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
					{
						// Reduce font size by one 
						++this._autoFitFontSizeAdjustment;
 
						// Calculate new font size
						int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
						if(newFontSize < 1)
						{
							// Font can't be less than size 1
							newFontSize = 1;
						}
 
                        // Create new font
                        this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
							this.Font.FontFamily, 
							newFontSize, 
							this.Font.Style, 
							this.Font.Unit);
 
						// Calculate number of rows and columns 
						this.GetNumberOfRowsAndColumns(
							chartGraph, 
							this._legendItemsAreaPosition.Size,
							-1,
							out this._numberOfRowsPerColumn, 
							out this._itemColumns,
							out this._horizontalSpaceLeft,
							out this._verticalSpaceLeft);
 
						autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
 
						// Calculate total number of items fit and make sure we fit all of them
						itemsFit = 0;
						for(int index = 0; index < this._itemColumns; index++)
						{
							itemsFit += this._numberOfRowsPerColumn[index];
						}
						if(itemsFit < this._numberOfLegendItemsToProcess)
						{
							autoFitDone = false;
						}
 
					}
					else
					{
						// If font size cannot be reduced start removing legend items
						if(this._numberOfLegendItemsToProcess > 2)
						{
							// Handle case of 1 column that do not fit horizontally
							if(this._itemColumns == 1 && (this._horizontalSpaceLeft < 0 && this._verticalSpaceLeft >= 0))
							{
								autoFitDone = true;
								this._numberOfLegendItemsToProcess = 
									Math.Min(this._numberOfLegendItemsToProcess, this._numberOfRowsPerColumn[0]);
							}
							// Handle case of 1 row that do not fit vertically
							else if(this.GetMaximumNumberOfRows() == 1 && (this._verticalSpaceLeft < 0  && this._horizontalSpaceLeft >= 0))
							{
								autoFitDone = true;
								this._numberOfLegendItemsToProcess = 
									Math.Min(this._numberOfLegendItemsToProcess, this._itemColumns);
							}
							else
							{
								// Adjust legend items area height by size required to show
								// visually (dots) that legend is truncated
								if(!this._legendItemsTruncated)
								{
									this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
								}
 
								// Remove last legend item
								this._legendItemsTruncated = true;
								--this._numberOfLegendItemsToProcess;
 
								// RecalculateAxesScale number of rows and columns
								this.GetNumberOfRowsAndColumns(
									chartGraph, 
									this._legendItemsAreaPosition.Size,
									this._numberOfLegendItemsToProcess,
									out this._numberOfRowsPerColumn, 
									out this._itemColumns);
							}
 
							// Make sure we show truncated legend symbols when not all items shown
							if(autoFitDone && 
								!this._legendItemsTruncated &&
								this._numberOfLegendItemsToProcess < this.legendItems.Count)
							{
								// Adjust legend items area height by size required to show
								// visually (dots) that legend is truncated
								this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
 
								// Legend is truncated
								this._legendItemsTruncated = true;
							}
						}
						else
						{
							autoFitDone = true;
						}
					
						// Check if legend items fit into the legend area
						if(!autoFitDone)
						{
							autoFitDone = this.CheckLegendItemsFit(
								chartGraph,
								this._legendItemsAreaPosition.Size,
								this._numberOfLegendItemsToProcess,
								this._autoFitFontSizeAdjustment,
								this._itemColumns,
								this._numberOfRowsPerColumn,
								out this._subColumnSizes,
								out this._cellHeights,
								out this._horizontalSpaceLeft,
								out this._verticalSpaceLeft);
 
						}
					}
				} while(!autoFitDone);
			}
 
		
			//***********************************************************
			//** Calculate position of all cells
			//***********************************************************
 
			// Calculate item vertical spacing in relative coordinates but rounded on pixel boundary
			Size itemHalfSpacing = Size.Empty;
			if(this._verticalSpaceLeft > 0)
			{
				itemHalfSpacing.Height = (int)(this._verticalSpaceLeft / this.GetMaximumNumberOfRows() / 2);
			}
			if(this._horizontalSpaceLeft > 0)
			{
				itemHalfSpacing.Width = (int)(_horizontalSpaceLeft / 2);
			}
 
			// Iterate through all legend items
			int currentColumn = 0;
			int currentRow = 0;
			if(this._numberOfLegendItemsToProcess < 0)
			{
				this._numberOfLegendItemsToProcess = this.legendItems.Count;
			}
			for(int legendItemIndex = 0; legendItemIndex < this._numberOfLegendItemsToProcess; legendItemIndex++)
			{
				LegendItem legendItem = this.legendItems[legendItemIndex];
 
				// Iterate through legend item cells
				for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
				{
					// Get legend cell
					LegendCell legendCell = legendItem.Cells[cellIndex];
 
					// Calculate cell position
					Rectangle cellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex, itemHalfSpacing);
 
					// Check if current cell spans through more than 1 cell
					int overlappedCellsNumber = 0;
					if(legendCell.CellSpan > 1)
					{
						for(int spanIndex = 1; spanIndex < legendCell.CellSpan && (cellIndex + spanIndex) < legendItem.Cells.Count; spanIndex++)
						{
							// Calculate overlapped cell position
							Rectangle overlappedCellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex + spanIndex, itemHalfSpacing);
 
							// Adjust current cell right position
							if(cellPosition.Right < overlappedCellPosition.Right)
							{
								cellPosition.Width += overlappedCellPosition.Right - cellPosition.Right;
							}
 
							// Increase number of overlapped cells
							++overlappedCellsNumber;
 
							// Set empty size for the overlapped cells
							LegendCell overlappedLegendCell = legendItem.Cells[cellIndex + spanIndex];
							overlappedLegendCell.SetCellPosition( 
								currentRow,
								Rectangle.Empty, 
								this.singleWCharacterSize);
						}
					}
 
					// Make sure cell is drawn inside the legend
					cellPosition.Intersect(this._legendItemsAreaPosition);
 
					// Set cell object position
					legendCell.SetCellPosition(
						currentRow,
						cellPosition, 
						this.singleWCharacterSize);
 
					// Skip overlapped cells
					cellIndex += overlappedCellsNumber;
				}
 
				// Advance to the next row/column. Break if number of legend items exceed
				// number of availabale rows/columns.
				++currentRow;
				if(currentRow >= this._numberOfRowsPerColumn[currentColumn])
				{
					++currentColumn;
					currentRow = 0;
					if(currentColumn >= this._itemColumns)
					{
						break;
					}
				}
			}
		}
 
		/// <summary>
		/// Gets single cell position in relative coordinates.
		/// </summary>
		/// <param name="columnIndex">Cell column index.</param>
		/// <param name="rowIndex">Cell row index.</param>
		/// <param name="cellIndex">Index of the cell in the legend item.</param>
		/// <param name="itemHalfSpacing">Half legend item spacing in relative coordinates.</param>
		/// <returns></returns>
		private Rectangle GetCellPosition( 
			int columnIndex, 
			int rowIndex, 
			int cellIndex,
			Size itemHalfSpacing)
		{
			Rectangle cellPosition = this._legendItemsAreaPosition;
 
			//*****************************************************************
			//** Get cell Top location
			//*****************************************************************
			for(int index = 0; index < rowIndex; index++)
			{
				cellPosition.Y += this._cellHeights[columnIndex, index];
			}
			if(itemHalfSpacing.Height > 0)
			{
				cellPosition.Y += itemHalfSpacing.Height * rowIndex * 2 + itemHalfSpacing.Height;
			}
 
			//*****************************************************************
			//** Get cell Left location
			//*****************************************************************
 
			// Add extar space left after auto fitting
			if(this._horizontalSpaceLeft > 0)
			{
				cellPosition.X += itemHalfSpacing.Width;
			}
 
			// Calculate how many sub-columns (cells) this legend has
			int numberOfSubColumns = this.GetNumberOfCells();
 
			// Iterate through all prev. columns
			for(int index = 0; index < columnIndex; index++)
			{
				// Add width of previous columns
				for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++)
				{
					cellPosition.X += this._subColumnSizes[index, subColumnIndex];
				}
 
				// Add width of separator for the previous columns
				cellPosition.X += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
			}
			// Add width of current column cells
			for(int subColumnIndex = 0; subColumnIndex < cellIndex; subColumnIndex++)
			{
				cellPosition.X += this._subColumnSizes[columnIndex, subColumnIndex];
			}
 
			//*****************************************************************
			//** Get cell Height
			//*****************************************************************
			cellPosition.Height = this._cellHeights[columnIndex, rowIndex];
			
			//*****************************************************************
			//** Get cell Width
			//*****************************************************************
			cellPosition.Width = this._subColumnSizes[columnIndex, cellIndex];
 
			return cellPosition;
		}
 
		/// <summary>
		/// Calculates the optimal size of the legend.
		/// </summary>
		/// <param name="chartGraph">Chart graphics object.</param>
		/// <param name="maxSizeRel">Max size for the legend.</param>
		/// <returns>Legend optimal size.</returns>
		private SizeF GetOptimalSize(ChartGraphics chartGraph, SizeF maxSizeRel)
		{
			// Reset some values
			this._offset = Size.Empty;
			this._itemColumns = 0;
			this._horizontalSpaceLeft = 0;
			this._verticalSpaceLeft = 0;
			this._subColumnSizes = null;
			this._numberOfRowsPerColumn = null;
			this._cellHeights = null;
			this.autofitFont = null;
			this._autoFitFontSizeAdjustment = 0;
			this._numberOfCells = -1;
			this._numberOfLegendItemsToProcess = -1;
			Size	optimalSize = Size.Empty;
 
			// Convert to pixels
			SizeF maxSizeAbs = chartGraph.GetAbsoluteSize(maxSizeRel);
			Size maxSize = new Size((int)maxSizeAbs.Width, (int)maxSizeAbs.Height);
 
			// Clear all legend item cells cached information
			foreach(LegendItem legendItem in this.legendItems)
			{
				foreach(LegendCell cell in legendItem.Cells)
				{
					cell.ResetCache();
				}
			}
 
			// Check if legend is enabled
			if(this.IsEnabled())
			{
				// Add all series legend into items collection and then add custom legend items
				FillLegendItemsCollection();
 
				// Call a notification event, so that legend items collection can be modified by user
                this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
 
				// Check if there are any items in the legend
				if(this.legendItems.Count > 0)
				{
					//***********************************************************
					//** Use size of the "W" character in current font to 
					//** calculate legend spacing
					//***********************************************************
					this.singleWCharacterSize =  chartGraph.MeasureStringAbs("W", this.Font);
					Size doubleCharacterSize =  chartGraph.MeasureStringAbs("WW", this.Font);
					this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
			
					// Calculate left, top offset and column spacing
					this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
					this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
					this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
					if(this._itemColumnSpacingRel % 2 == 1)
					{
						this._itemColumnSpacingRel += 1;
					}
 
 
					//***********************************************************
					//** Add size required for the legend tile
					//***********************************************************
					
					Size titleSize = Size.Empty;
					if(this.Title.Length > 0)
					{
						titleSize = this.GetTitleSize(chartGraph, maxSize);
					}
 
					//***********************************************************
					//** Add size required for the legend header
					//***********************************************************
 
					Size highestHeader = Size.Empty;
					foreach(LegendCellColumn legendColumn in this.CellColumns)
					{
						if(legendColumn.HeaderText.Length > 0)
						{
							// Measure header text size
							Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
 
							// Get header with maximum height
							highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
						}
					}
 
					//***********************************************************
					//** Calculate size available for legend items
					//***********************************************************
					Size legenItemsMaxSize = maxSize;
					legenItemsMaxSize.Width -= 2 * (this._offset.Width + this.GetBorderSize());
					legenItemsMaxSize.Height -= 2 * (this._offset.Height + this.GetBorderSize());
					legenItemsMaxSize.Height -= titleSize.Height;
					legenItemsMaxSize.Height -= highestHeader.Height;
 
					//***********************************************************
					//** Calculate number of rows and columns depending on
					//** the legend style
					//***********************************************************
                    this._autoFitFontSizeAdjustment = 0;
 
					this.autofitFont = this.Font;
					int vertSpaceLeft = 0;
					int horizSpaceLeft = 0;
					bool reduceFont = this.IsTextAutoFit;
					bool autoFit = false;
					do
					{
						// Get number of columns and rows that we can fit in the legend
						this.GetNumberOfRowsAndColumns(
							chartGraph, 
							legenItemsMaxSize,
							-1,
							out this._numberOfRowsPerColumn, 
							out this._itemColumns,
							out horizSpaceLeft,
							out vertSpaceLeft);
 
						// Calculate total number of items fit and make sure we fit all of them
						int itemsFit = 0;
						for(int index = 0; index < this._itemColumns; index++)
						{
							itemsFit += this._numberOfRowsPerColumn[index];
						}
						autoFit = (horizSpaceLeft >= 0 && vertSpaceLeft >= 0 && itemsFit >= this.legendItems.Count);
 
						// Check if items fit
						if(reduceFont && !autoFit)
						{
							if((this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
							{
								// Reduce font size by one 
								++this._autoFitFontSizeAdjustment;
 
								// Calculate new font size
								int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
								if(newFontSize < 1)
								{
									// Font can't be less than size 1
									newFontSize = 1;
								}
 
								// Create new font
                                this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
									this.Font.FontFamily, 
									newFontSize, 
									this.Font.Style, 
									this.Font.Unit);
							}
							else
							{
								reduceFont = false;
							}
						}
					} while(reduceFont && !autoFit);
 
					// Slightly reduce used space 
					horizSpaceLeft -= Math.Min(4, horizSpaceLeft);
					vertSpaceLeft -= Math.Min(2, vertSpaceLeft);
 
	
					//***********************************************************
					//** Calculate legend size
					//***********************************************************
					optimalSize.Width = (legenItemsMaxSize.Width - horizSpaceLeft);
					optimalSize.Width = Math.Max(optimalSize.Width, titleSize.Width);
					optimalSize.Width += 2 * (this._offset.Width + this.GetBorderSize());
 
					optimalSize.Height = (legenItemsMaxSize.Height - vertSpaceLeft) + titleSize.Height + highestHeader.Height;
					optimalSize.Height += 2 * (this._offset.Height + this.GetBorderSize());
 
					// Adjust legend items area height by size required to show
					// visually (dots) that legend is truncated
					if(horizSpaceLeft < 0 || vertSpaceLeft < 0)
					{
						optimalSize.Height += this._truncatedDotsSize;
					}
 
					//***********************************************************
					//** Make sure legend size do not exceed max. value
					//***********************************************************
					if(optimalSize.Width > maxSize.Width)
					{
						optimalSize.Width = maxSize.Width;
					}
					if(optimalSize.Height > maxSize.Height)
					{
						optimalSize.Height = maxSize.Height;
					}
					if(optimalSize.Width < 0)
					{
						optimalSize.Width = 0;
					}
					if(optimalSize.Height < 0)
					{
						optimalSize.Height = 0;
					}
				}
			}
 
			// Convert result size from pixel to relative coordinates
			return chartGraph.GetRelativeSize(optimalSize);
		}
 
 
 
		/// <summary>
		/// Recalculates legend position.
		/// </summary>
		/// <param name="chartGraph">Chart graphics used.</param>
		/// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
		/// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
		internal void CalcLegendPosition(
			ChartGraphics chartGraph, 
			ref RectangleF chartAreasRectangle, 
			float elementSpacing)
		{
			RectangleF	legendPosition = new RectangleF();
 
			// Get optimal legend size
			SizeF maxSize = new SizeF(chartAreasRectangle.Width - 2*elementSpacing, chartAreasRectangle.Height - 2*elementSpacing);
            if (this.DockedToChartArea == Constants.NotSetValue)
			{
 
                // Note: 'maxLegendSize' parameter is ignored. New legend property 
                // 'maximumLegendAutoSize' is used instead.
				if(this.Docking == Docking.Top || this.Docking == Docking.Bottom)
				{
                    maxSize.Height = (maxSize.Height / 100F) * this._maximumLegendAutoSize;
				}
				else
				{
                    maxSize.Width = (maxSize.Width / 100F) * this._maximumLegendAutoSize;
				}
			}
 
			if(maxSize.Width <= 0 || maxSize.Height <= 0)
			{
				return;
			}
				
			SizeF legendSize = this.GetOptimalSize(chartGraph, maxSize);
			legendPosition.Height = legendSize.Height;
			legendPosition.Width = legendSize.Width;
			if(float.IsNaN(legendSize.Height) || float.IsNaN(legendSize.Width))
			{
				return;
			}
 
			// Calculate legend position
			if(this.Docking == Docking.Top)
			{
				legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
				if(this.Alignment == StringAlignment.Near)
				{
					legendPosition.X = chartAreasRectangle.X + elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Far)
				{
					legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Center)
				{
					legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
				}
 
				// Adjust position of the chart area(s)
				chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
				chartAreasRectangle.Y = legendPosition.Bottom;
			}
			else if(this.Docking == Docking.Bottom)
			{
				legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
				if(this.Alignment == StringAlignment.Near)
				{
					legendPosition.X = chartAreasRectangle.X + elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Far)
				{
					legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Center)
				{
					legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
				}
 
				// Adjust position of the chart area(s)
				chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
			}
			if(this.Docking == Docking.Left)
			{
				legendPosition.X = chartAreasRectangle.X + elementSpacing;
				if(this.Alignment == StringAlignment.Near)
				{
					legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Far)
				{
					legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Center)
				{
					legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
				}
 
				// Adjust position of the chart area(s)
				chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
				chartAreasRectangle.X = legendPosition.Right;
			}
			if(this.Docking == Docking.Right)
			{
				legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
				if(this.Alignment == StringAlignment.Near)
				{
					legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Far)
				{
					legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
				}
				else if(this.Alignment == StringAlignment.Center)
				{
					legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
				}
 
				// Adjust position of the chart area(s)
				chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
			}
 
			this.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
		}
 
 
 
		/// <summary>
		/// Get number of columns and rows that can be fit in specified size.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="legendSize">Legend size.</param>
		/// <param name="numberOfItemsToCheck">Number of legend items to check.</param>
		/// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
		/// <param name="columnNumber">Returns number of columns.</param>
		private void GetNumberOfRowsAndColumns(
			ChartGraphics chartGraph, 
			Size legendSize,
			int numberOfItemsToCheck,
			out int[] numberOfRowsPerColumn, 
			out int columnNumber)
		{
			int horSpaceLeft = 0;
			int vertSpaceLeft = 0;
			this.GetNumberOfRowsAndColumns(
				chartGraph, 
				legendSize,
				numberOfItemsToCheck,
				out numberOfRowsPerColumn, 
				out columnNumber,
				out horSpaceLeft,
				out vertSpaceLeft);
		}
 
		/// <summary>
		/// Get number of columns and rows that can be fit in specified size.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="legendSize">Legend size.</param>
		/// <param name="numberOfItemsToCheck">Legend items number to check.</param>
		/// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
		/// <param name="columnNumber">Returns number of columns.</param>
		/// <param name="horSpaceLeft">Returns horizontal spacing left.</param>
		/// <param name="vertSpaceLeft">Returns vertical spacing left.</param>
		private void GetNumberOfRowsAndColumns(
			ChartGraphics chartGraph, 
			Size legendSize,
			int numberOfItemsToCheck,
			out int[] numberOfRowsPerColumn, 
			out int columnNumber,
			out int horSpaceLeft,
			out int vertSpaceLeft)
		{
			// Initialize output parameters
			numberOfRowsPerColumn = null;
			columnNumber = 1;
			horSpaceLeft = 0;
			vertSpaceLeft = 0;
 
			// If number of items to check is nor set use total number of items in the collection
			if(numberOfItemsToCheck < 0)
			{
				numberOfItemsToCheck = legendItems.Count;
			}
 
			// Check legend style
			if(this.LegendStyle == LegendStyle.Column || numberOfItemsToCheck <= 1)
			{
				columnNumber = 1;
				numberOfRowsPerColumn = new int[] { numberOfItemsToCheck };
			}
			else if(this.LegendStyle == LegendStyle.Row)
			{
				columnNumber = numberOfItemsToCheck;
				numberOfRowsPerColumn = new int[columnNumber];
				for(int index = 0; index < columnNumber; index++)
				{
					numberOfRowsPerColumn[index] = 1;
				}
			}
			else if(this.LegendStyle == LegendStyle.Table)
			{
				// Start with 1 column and 1 row
				columnNumber = 1;
				numberOfRowsPerColumn = new int[] { 1 };
 
				// Get legend table style and adjust number of columns and rows accordinly
				LegendTableStyle tableStyle = this.GetLegendTableStyle(chartGraph);
				
				//*********************************************************************************
				//** Tall table layout
				//*********************************************************************************
				if(tableStyle == LegendTableStyle.Tall)
				{
					// Iterate from second item trying to add them and check if their fit
					bool exitLoop = false;
					int legendItemIndex = 1;
					for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
					{
						// Try to increase number of rows in the current column
						++numberOfRowsPerColumn[columnNumber - 1];
 
						// Check if legend items fit into the legend area
						bool autoFitDone = this.CheckLegendItemsFit(
							chartGraph,
							legendSize,
							legendItemIndex + 1,
							this._autoFitFontSizeAdjustment,
							columnNumber,
							numberOfRowsPerColumn,
							out this._subColumnSizes,
							out this._cellHeights,
							out horSpaceLeft,
							out vertSpaceLeft);
 
						// Check if we fit or if we have just one column that do not fit
						// horizontally but still have vertical space.
						if(autoFitDone || 
							( (columnNumber == 1 || horSpaceLeft < 0) && vertSpaceLeft > 0) )
						{
							// Continue adding rows to the current column
							continue;
						}
						else
						{
							// Reduce number of rows in the current column
							if(numberOfRowsPerColumn[columnNumber - 1] > 1)
							{
								--numberOfRowsPerColumn[columnNumber - 1];
							}
 
							// Get half of average column width
							int averageColumnWidth = 0;
							if(horSpaceLeft > 0)
							{
								averageColumnWidth = (int)Math.Round((double)(legendSize.Width - horSpaceLeft) / columnNumber) / 2;
							}
 
							 // Check if number of columns can be increased
							if(columnNumber < 50 && horSpaceLeft >= averageColumnWidth)
							{
								// Add new column
								++columnNumber;
 
								// Resize array that stores number of rows per column
								int[] tempArray = numberOfRowsPerColumn;
								numberOfRowsPerColumn = new int[columnNumber];
								for(int index = 0; index < tempArray.Length; index++)
								{
									numberOfRowsPerColumn[index] = tempArray[index];
								}
								numberOfRowsPerColumn[columnNumber - 1] = 1;
 
								// If last legend item is moved into a new column
								// call the auto fitting method before leaving the loop
								if(legendItemIndex == numberOfItemsToCheck - 1)
								{
									this.CheckLegendItemsFit(
										chartGraph,
										legendSize,
										legendItemIndex + 1,
										this._autoFitFontSizeAdjustment,
										columnNumber,
										numberOfRowsPerColumn,
										out this._subColumnSizes,
										out this._cellHeights,
										out horSpaceLeft,
										out vertSpaceLeft);
								}
							}
							else
							{
								exitLoop = true;
							}
						}
					}
 
					// Check if we end up with legend with multiple columns
					// where last column has sinificantly lower height of all rows
					if(columnNumber > 1)
					{
						// Try reducing number of rows in the "tall" calumns and move them 
						// into the last column.
						bool done = false;
						while(!done)
						{
							// By default no more iterations required
							done = true;
 
							// Find maximum column height not taking the last row in consideration
							int maxColumnHeight = -1;
							for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
							{
								// Calculate current column height not taking the last row in consideration
								int columnHeight = 0;
								for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex] - 1; rowIndex++)
								{
									columnHeight += this._cellHeights[columnIndex, rowIndex];
								}
 
								// Find maximum height
								maxColumnHeight = Math.Max(maxColumnHeight, columnHeight);
							}
 
							// Calculate total height of items in the last row
							int totalHieghtOfItemInLastRow = 0;
							for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
							{
								if(this._numberOfRowsPerColumn[columnIndex] > 1)
								{
									totalHieghtOfItemInLastRow += this._cellHeights[columnIndex, this._numberOfRowsPerColumn[columnIndex] - 1];
								}
							}
 
							// Check if rows are available for removal
							if(totalHieghtOfItemInLastRow > 0)
							{
								// Get last column height
								int lastColumnHeight = this.GetColumnHeight(columnNumber - 1);
 
								// Check if all items in the last row can vertically fit in last column
								if( (lastColumnHeight + totalHieghtOfItemInLastRow) <= maxColumnHeight )
								{
									// Reduce number of rows in all columns except last
									int itemsToAdd = 0;
									for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
									{
										if(this._numberOfRowsPerColumn[columnIndex] > 1)
										{
											--this._numberOfRowsPerColumn[columnIndex];
											++itemsToAdd;
										}
									}
 
									// Add rows to last column
									if(itemsToAdd > 0)
									{
										// Add roes into the last column
										this._numberOfRowsPerColumn[columnNumber - 1] += itemsToAdd;
 
										// Check if legend items fit into the legend area
										bool autoFitDone = this.CheckLegendItemsFit(
											chartGraph,
											legendSize,
											legendItemIndex + 1,
											this._autoFitFontSizeAdjustment,
											columnNumber,
											numberOfRowsPerColumn,
											out this._subColumnSizes,
											out this._cellHeights,
											out horSpaceLeft,
											out vertSpaceLeft);
 
										// Try doing one more time
										done = false;
									}
								}
							}
						}
					}
				}
					//*********************************************************************************
					//** Wide table layout
					//*********************************************************************************
				else if(tableStyle == LegendTableStyle.Wide)
				{
					// Iterate from second item trying to add them and check if they fit
					bool exitLoop = false;
					int legendItemIndex = 1;
					for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
					{
						// Try to increase number of columns
						++columnNumber;
 
						// Resize array that stores number of rows per column
						int[] tempArray = numberOfRowsPerColumn;
						numberOfRowsPerColumn = new int[columnNumber];
						for(int index = 0; index < tempArray.Length; index++)
						{
							numberOfRowsPerColumn[index] = tempArray[index];
						}
						numberOfRowsPerColumn[columnNumber - 1] = 1;
 
						// Check if legend items fit into the legend area
						bool autoFitDone = this.CheckLegendItemsFit(
							chartGraph,
							legendSize,
							legendItemIndex + 1,
							this._autoFitFontSizeAdjustment,
							columnNumber,
							numberOfRowsPerColumn,
							out this._subColumnSizes,
							out this._cellHeights,
							out horSpaceLeft,
							out vertSpaceLeft);
 
						// Check if we fit or if we have just one row that do not fit
						// vertically but still have horizontal space.
						if(autoFitDone || 
							( (this.GetMaximumNumberOfRows(numberOfRowsPerColumn) == 1 || vertSpaceLeft < 0) && horSpaceLeft > 0) )
						{
							// Continue adding columns
							continue;
						}
						else
						{
							// Remove columns and increase number of rows
							bool columnFitting = true;
							while(columnFitting)
							{
								columnFitting = false;
 
								// If we can't fit current number of columns reduce current column number
								int rowsToAdd = 0;
								if(columnNumber > 1)
								{
									rowsToAdd = numberOfRowsPerColumn[columnNumber - 1];
									--columnNumber;
 
									// Resize array that stores number of rows per column
									tempArray = numberOfRowsPerColumn;
									numberOfRowsPerColumn = new int[columnNumber];
									for(int index = 0; index < columnNumber; index++)
									{
										numberOfRowsPerColumn[index] = tempArray[index];
									}
								}
 
								// We may need to add more than 1 row
								for(int indexRowToAdd = 0; indexRowToAdd < rowsToAdd; indexRowToAdd++)
								{
									// Find first column with smallest height
									int smallestColumnIndex = -1;
									int columnMinHeight = int.MaxValue;
									for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
									{
										int columnHeight = this.GetColumnHeight(columnIndex);
										int nextColumnFirstItemHeight = 0;
										if(columnIndex < columnNumber - 1)
										{
											nextColumnFirstItemHeight = this._cellHeights[columnIndex + 1, 0];
										}
										if(columnHeight < columnMinHeight && 
											(columnHeight + nextColumnFirstItemHeight) < legendSize.Height)
										{
											// Remember column index and height
											columnMinHeight = columnHeight;
											smallestColumnIndex = columnIndex;
										}
									}
 
									// No more items can fit
									if(smallestColumnIndex < 0)
									{
										// Check if legend items fit into the legend area
										autoFitDone = this.CheckLegendItemsFit(
											chartGraph,
											legendSize,
											legendItemIndex + 1,
											this._autoFitFontSizeAdjustment,
											columnNumber,
											numberOfRowsPerColumn,
											out this._subColumnSizes,
											out this._cellHeights,
											out horSpaceLeft,
											out vertSpaceLeft);
 
										exitLoop = true;
										break;
									}
 
									// Add new row to the smallest column
									++numberOfRowsPerColumn[smallestColumnIndex];
 
									// Check if next column will be removed if it contains only 1 row
									if(smallestColumnIndex < (columnNumber - 1))
									{
										if(numberOfRowsPerColumn[smallestColumnIndex + 1] == 1)
										{
											// Shift number of rows per column
											tempArray = numberOfRowsPerColumn;
											for(int index = smallestColumnIndex + 1; index < tempArray.Length - 1; index++)
											{
												numberOfRowsPerColumn[index] = tempArray[index + 1];
											}
											numberOfRowsPerColumn[columnNumber - 1] = 1;
										}
									}
 
									// Check if legend items fit into the legend area
									autoFitDone = this.CheckLegendItemsFit(
										chartGraph,
										legendSize,
										legendItemIndex + 1,
										this._autoFitFontSizeAdjustment,
										columnNumber,
										numberOfRowsPerColumn,
										out this._subColumnSizes,
										out this._cellHeights,
										out horSpaceLeft,
										out vertSpaceLeft);
 
								}
 
								// If there is more than 1 column and items do not fit
								// horizontally - reduce number of columns.
								if(!autoFitDone && 
									horSpaceLeft < 0f && 
									columnNumber > 1)
								{
									columnFitting = true;
								}
							}
						}
					}
				}
			}
 
			// Check if items fit and how much empty space left
			this.CheckLegendItemsFit(
				chartGraph,
				legendSize,
				-1,
				this._autoFitFontSizeAdjustment,
				columnNumber,
				numberOfRowsPerColumn,
				out this._subColumnSizes,
				out this._cellHeights,
				out horSpaceLeft,
				out vertSpaceLeft);
		}
		
        /// <summary>
		/// Gets column height.
		/// </summary>
		/// <param name="columnIndex">Index of the column to get the height for.</param>
		/// <returns>Column height in relative coordinates.</returns>
		private int GetColumnHeight(int columnIndex)
		{
			// Calculate current column height
			int columnHeight = 0;
			for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex]; rowIndex++)
			{
				columnHeight += this._cellHeights[columnIndex, rowIndex];
			}
 
			return columnHeight;
		}
 
        /// <summary>
        /// Checks if legend background is selected.
        /// </summary>
        internal void SelectLegendBackground()
        {
            Common.HotRegionsList.AddHotRegion(this.Position.ToRectangleF(), this, ChartElementType.LegendArea, true);
        }
 
		#endregion Legend position & size methods
 
		#region Legend Items Fitting Methods
 
		/// <summary>
		/// Gets maximum number of rows in all columns.
		/// </summary>
		/// <returns>Maximum number of rows.</returns>
		private int GetMaximumNumberOfRows()
		{
			return this.GetMaximumNumberOfRows(this._numberOfRowsPerColumn);
		}
 
		/// <summary>
		/// Gets maximum number of rows in all columns.
		/// </summary>
		/// <param name="rowsPerColumn">Array that stores number of rows per column.</param>
		/// <returns>Maximum number of rows.</returns>
		private int GetMaximumNumberOfRows(int[] rowsPerColumn)
		{
			// Find column with maximum number of rows
			int maxNumberOfColumns = 0;
			if(rowsPerColumn != null)
			{
				for(int columnIndex = 0; columnIndex < rowsPerColumn.Length; columnIndex++)
				{
					maxNumberOfColumns = Math.Max(maxNumberOfColumns, rowsPerColumn[columnIndex]);
				}
			}
			return maxNumberOfColumns;
		}
 
		/// <summary>
		/// Checks if specified legend will fit the specified size.
		/// </summary>
		/// <param name="graph">Chart graphics.</param>
		/// <param name="legendItemsAreaSize">Area that legend items must fit.</param>
		/// <param name="numberOfItemsToCheck">Number of items that should be fitted.</param>
		/// <param name="fontSizeReducedBy">Number of points the standard legend font is reduced by auto-fitting algorithm.</param>
		/// <param name="numberOfColumns">Legend column number.</param>
		/// <param name="numberOfRowsPerColumn">Array of number of rows per column.</param>
		/// <param name="subColumnSizes">Returns array of sub-column size.</param>
		/// <param name="cellHeights">Returns array of cell heights.</param>
		/// <param name="horizontalSpaceLeft">Returns horizontal space left.</param>
		/// <param name="verticalSpaceLeft">Returns vertical space left.</param>
		/// <returns>True if items fit.</returns>
		private bool CheckLegendItemsFit(
			ChartGraphics graph, 
			Size legendItemsAreaSize,
			int numberOfItemsToCheck,
			int fontSizeReducedBy,
			int numberOfColumns,
			int[] numberOfRowsPerColumn,
			out int[,] subColumnSizes,
			out int[,] cellHeights,
			out int horizontalSpaceLeft,
			out int verticalSpaceLeft)
		{
			bool fitFlag = true;
 
			// Initialize output values
			horizontalSpaceLeft = 0;
			verticalSpaceLeft = 0;
 
			// Use current legend item count if number of items to check is not specified
			if(numberOfItemsToCheck < 0)
			{
				numberOfItemsToCheck = this.legendItems.Count;
			}
 
			// Calculate how many sub-columns (cells) this legend has
			int numberOfSubColumns = this.GetNumberOfCells();
 
			// Each column may have its own number of rows. Calculate the maximum number of rows.
			int maxNumberOfRows = this.GetMaximumNumberOfRows(numberOfRowsPerColumn);
 
			// Create multidimensional arrays that will be holding the widths and heightsof all 
			// individual cells. First dimension will be the legend column index, second dimension 
			// is row index and the third is sub-column (cell) index.
			int[,,] cellWidths = new int[numberOfColumns, maxNumberOfRows, numberOfSubColumns];
			cellHeights = new int[numberOfColumns, maxNumberOfRows];
 
 
			//*************************************************************************
			//** Measure legend font single character
			//*************************************************************************
			this.singleWCharacterSize =  graph.MeasureStringAbs("W", (this.autofitFont == null) ? this.Font : this.autofitFont);
			Size doubleCharacterSize =  graph.MeasureStringAbs("WW", (this.autofitFont == null) ? this.Font : this.autofitFont);
			this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
 
 
			//*************************************************************************
			//** Iterate through all legend items and measure each individual cell
			//*************************************************************************
			int currentColumn = 0;
			int currentRow = 0;
			for(int legendItemIndex = 0; legendItemIndex < numberOfItemsToCheck; legendItemIndex++)
			{
				LegendItem legendItem = this.legendItems[legendItemIndex];
 
				// Iterate through legend item cells
				int numberOfCellsToSkip = 0;
				for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
				{
					// Get legend cell
					LegendCell legendCell = legendItem.Cells[cellIndex];
 
					// Get assocated legend column object (may be NULL)
					LegendCellColumn legendColumn = null;
					if(cellIndex < this.CellColumns.Count)
					{
						legendColumn = this.CellColumns[cellIndex];
					}
 
					// Check if current cell should be skipped becuse it's overlapped 
					// by the previous sell that uses CellSpan.
					if(numberOfCellsToSkip > 0)
					{
						// Put size (-1) for the cells that follow a cell using ColumnSpan
						cellWidths[currentColumn, currentRow, cellIndex] = -1;
						--numberOfCellsToSkip;
						continue;
					}
 
					// Check if current cell uses CellSpan
					if(legendCell.CellSpan > 1)
					{
						numberOfCellsToSkip = legendCell.CellSpan - 1;
					}
 
					// Measure cell and store the value in the array
					Size cellSize = legendCell.MeasureCell(
						graph, 
						fontSizeReducedBy,
						(this.autofitFont == null) ? this.Font : this.autofitFont,
						this.singleWCharacterSize);
 
					// Check for column maximum/minimum cell width restrictions
					if(legendColumn != null)
					{
						if(legendColumn.MinimumWidth >= 0)
						{
							cellSize.Width = (int)Math.Max(cellSize.Width, legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
						}
						if(legendColumn.MaximumWidth >= 0)
						{
							cellSize.Width = (int)Math.Min(cellSize.Width, legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
						}
					}
 
					// Store cell size in arrays
					cellWidths[currentColumn, currentRow, cellIndex] = cellSize.Width;
					if(cellIndex == 0)
					{
						cellHeights[currentColumn, currentRow] = cellSize.Height;
					}
					else
					{
						cellHeights[currentColumn, currentRow] = 
							Math.Max(cellHeights[currentColumn, currentRow], cellSize.Height);
					}
				}
 
				// Advance to the next row/column. Break if number of legend items exceed
				// number of availabale rows/columns.
				++currentRow;
				if(currentRow >= numberOfRowsPerColumn[currentColumn])
				{
					++currentColumn;
					currentRow = 0;
					if(currentColumn >= numberOfColumns)
					{
						// Check if we were able to fit all the items
						if(legendItemIndex < numberOfItemsToCheck - 1)
						{
							fitFlag = false;
						}
						break;
					}
				}
			}
 
			//*************************************************************************
			//** For each sub-column get the maximum cell width
			//*************************************************************************
			subColumnSizes = new int[numberOfColumns, numberOfSubColumns];
			bool secondIterationRequired = false;
			for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
			{
				for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
				{
					int width = 0;
					for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
					{
						// Get current cell size
						int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
 
						// Skip overlapped cells and cells that use ColumnSpan during the 
						// first iteration. Their size will be determined during the 
						// second iteration.
						if(cellWidth < 0)
						{
							secondIterationRequired = true;
							continue;
						}
						if(currentSubColumn + 1 < numberOfSubColumns)
						{
							int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + 1];
							if(nextCellWidth < 0)
							{
								continue;
							}
						}
 
						// Get maximum width
						width = Math.Max(width, cellWidth );
					}
 
					// Store maximum width in the array
					subColumnSizes[currentColumn, currentSubColumn] = width;
				}
			}
 
			//*************************************************************************
			//** If leagend header text is used check if it fits into the currenly
			//** calculated sub-column sizes.
			//*************************************************************************
 
			for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
			{
				for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
				{
					if(currentSubColumn < this.CellColumns.Count)
					{
						LegendCellColumn legendColumn = this.CellColumns[currentSubColumn];
						if(legendColumn.HeaderText.Length > 0)
						{
							// Note that extra "I" character added to add more horizontal spacing
							Size headerTextSize =  graph.MeasureStringAbs(legendColumn.HeaderText + "I", legendColumn.HeaderFont);
							if(headerTextSize.Width > subColumnSizes[currentColumn, currentSubColumn])
							{
								// Set new width
								subColumnSizes[currentColumn, currentSubColumn] = headerTextSize.Width;
 
								// Check for column maximum/minimum cell width restrictions
								if(legendColumn.MinimumWidth >= 0)
								{
									subColumnSizes[currentColumn, currentSubColumn] = 
										(int)Math.Max(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
								}
								if(legendColumn.MaximumWidth >= 0)
								{
									subColumnSizes[currentColumn, currentSubColumn] = 
										(int)Math.Min(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
								}
							}
						}
					}
				}
			}
 
			//*************************************************************************
			//** Adjust width of the cells to fit cell content displayed across 
			//** several cells (CellSpanning).
			//*************************************************************************
			if(secondIterationRequired)
			{
				for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
				{
					for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
					{
						for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
						{
							// Get current cell size
							int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
 
							// Second iteration used to adjust width of the cells that are used to
							// draw content across several horizontal cells (CellSpanning)
							// Check if current cell will be spanned to the next ones
							int cellSpan = 0;
							while(currentSubColumn + cellSpan + 1 < numberOfSubColumns)
							{
								int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + cellSpan + 1];
								if(nextCellWidth >= 0)
								{
									break;	
								}
								++cellSpan;
							}
							
 
							// Cell span was detected
							if(cellSpan > 0)
							{
								// Calculate total width of current cell and all overlapped cells
								int spanWidth = 0;
								for(int index = 0; index <= cellSpan; index++)
								{
									spanWidth += subColumnSizes[currentColumn, currentSubColumn + index];
								}
 
								// Check if current cell fits into the cell span
								if(cellWidth > spanWidth)
								{
									// Adjust last span cell width to fit all curent cell content
									subColumnSizes[currentColumn, currentSubColumn + cellSpan] += cellWidth - spanWidth;
								}
							}
						}
					}
				}
			}
		
 
			//*************************************************************************
			//** Check if equally spaced legend columns are used
			//*************************************************************************
			if(this.IsEquallySpacedItems)
			{
				// Makre sure that same sub-colimn width are used in all columns
				for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
				{
					int width = 0;
					for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)	
					{
						width = Math.Max(width, subColumnSizes[currentColumn, currentSubColumn]);
					}
 
					// Set new sub-column width for each column
					for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)	
					{
						subColumnSizes[currentColumn, currentSubColumn] = width;
					}
				}
			}
 
			//*************************************************************************
			//** Calculate total width and height occupied by all cells
			//*************************************************************************
			int totalWidth = 0;
			int totalTableColumnSpacingWidth = 0;
			for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)	
			{
				// Add up all sub-columns
				for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
				{
					totalWidth += subColumnSizes[currentColumn, currentSubColumn];
				}
 
				// Add spacer between columns
				if(currentColumn < numberOfColumns - 1)
				{
					totalTableColumnSpacingWidth += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
				}
			}
 
			int totalHeight = 0;
			for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)	
			{
				int columnHeight = 0;
				for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
				{
					columnHeight += cellHeights[currentColumn, currentRow];
				}
 
				totalHeight = Math.Max(totalHeight, columnHeight);
			}
 
			//*************************************************************************
			//** Check if everything fits
			//*************************************************************************
			horizontalSpaceLeft = legendItemsAreaSize.Width - totalWidth - totalTableColumnSpacingWidth;
			if(horizontalSpaceLeft < 0)
			{
				fitFlag = false;
			}
			
			verticalSpaceLeft = legendItemsAreaSize.Height - totalHeight;
			if(verticalSpaceLeft < 0)
			{
				fitFlag = false;
			}
 
			return fitFlag;
		}
 
		/// <summary>
		/// Gets maximum number of legend cells defined as Column objects
		/// or Cells in the custom legend items.
		/// </summary>
		/// <returns>Maximum number of cells.</returns>
		private int GetNumberOfCells()
		{
			// Calculate cell number if it was not previously cached
			if(this._numberOfCells < 0)
			{
				// Initialize with number of defined columns
				this._numberOfCells = this.CellColumns.Count;
 
				// Check if number of cells in legend items exceed number of defined columns
				foreach(LegendItem legendItem in this.legendItems)
				{
					this._numberOfCells = Math.Max(this._numberOfCells, legendItem.Cells.Count);
				}
			}		
			return this._numberOfCells;
		}
 
		#endregion // Legend Items Fitting Methods
 
		#region Legend items collection filling methods
 
		/// <summary>
		/// Add all series legend into items collection and then
		/// add custom legend items.
		/// </summary>
		private void FillLegendItemsCollection()
		{
			// Clear all items
			legendItems.Clear();
 
			// Check that there is no invalid legend names in the series
			foreach(Series series in this.Common.DataManager.Series)
			{
                if (this.Common.ChartPicture.Legends.IndexOf(series.Legend)<0)
                {
                    throw (new InvalidOperationException(SR.ExceptionLegendReferencedInSeriesNotFound(series.Name, series.Legend)));
                }
			}
 
			// Flag which indicates that series requires legend items to be reversed
			bool	seriesWithReversedLegendItemsPresent = false;
 
			// Add legend items based on the exsisting chart series
			foreach(Series series in this.Common.DataManager.Series)
			{
                // Check if series uses this legend
                // VSTS issue #140694 fix: support of series.Legend = "Default";
                if (this.Common.ChartPicture.Legends[series.Legend] != this)
				{
					continue;
				}
 
				// Make sure series is assigned to the chart area
				if(series.ChartArea.Length > 0)
				{
					// Check if chart area name is valid
					bool areaNameFound = false;
					foreach(ChartArea area in this.Common.ChartPicture.ChartAreas)
					{
						if(area.Name == series.ChartArea)
						{
							areaNameFound = true;
							break;
						}
					}
 
					// Check if series is visible and valid chart area name was used
					if(series.IsVisible() && areaNameFound)
					{
						// Check if we should add all data points into the legend
						IChartType chartType = this.Common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
 
 
						// Check if series legend items should be reversed
                        if (this.LegendItemOrder == LegendItemOrder.Auto)
						{
							if(series.ChartType == SeriesChartType.StackedArea || 
								series.ChartType == SeriesChartType.StackedArea100 || 
								series.ChartType == SeriesChartType.Pyramid || 
								series.ChartType == SeriesChartType.StackedColumn || 
								series.ChartType == SeriesChartType.StackedColumn100 )
							{
								seriesWithReversedLegendItemsPresent = true;
							}
						}
						// Add item(s) based on series points label and fore color
						if(chartType.DataPointsInLegend)
						{
							// Check if data points have X values set
							bool	xValuesSet = false;
							foreach(DataPoint point in series.Points)
							{
								if(point.XValue != 0.0)
								{
									xValuesSet = true;
									break;
								}
							}
 
							// Add legend items for each point
							int index = 0;
							foreach(DataPoint point in series.Points)
							{
								// Do not show empty data points in the legend
								if(point.IsEmpty)
								{
									++index;
									continue;
								}
 
								// Point should not be shown in the legend
								if(!point.IsVisibleInLegend)
								{
									++index;
									continue;
								}
 
								// Create new legend item
								LegendItem	item = new LegendItem(point.Label, point.Color, "");
 
								// Check if series is drawn in 3D chart area
								bool area3D = this.Common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
 
								// Set legend item appearance properties
								item.SetAttributes(this.Common, series);
								item.SetAttributes(point, area3D);
 
								// Set chart image map properties
								item.ToolTip = point.ReplaceKeywords(point.LegendToolTip);
#if !Microsoft_CONTROL
								item.MapAreaAttributes = point.ReplaceKeywords(point.LegendMapAreaAttributes);
                                item.PostBackValue = point.ReplaceKeywords(point.LegendPostBackValue);
								item.Url = point.ReplaceKeywords(point.LegendUrl);
#endif
								item.Name = point.ReplaceKeywords(point.LegendText);
 
								item.SeriesPointIndex = index++;
								if(item.Name.Length == 0)
								{
									item.Name = point.ReplaceKeywords((point.Label.Length > 0) ? point.Label : point.AxisLabel);
								}
 
								// If legend item name is not defined - try using the X value
								if(item.Name.Length == 0 && xValuesSet)
								{
									item.Name = ValueConverter.FormatValue(
										series.Chart,
										this,
                                        this.Tag,
										point.XValue, 
										"", // Do not use point label format! For Y values only! point.LabelFormat, 
										point.series.XValueType,
										ChartElementType.LegendItem);
								}
 
								// If legend item name is not defined - use index
								if(item.Name.Length == 0)
								{
									item.Name = "Point " + index;
								}
 
								// Add legend item cells based on predefined columns
								item.AddAutomaticCells(this);
								foreach(LegendCell cell in item.Cells)
								{
									if(cell.Text.Length > 0)
									{
										// #LEGENDTEXT - series name
										cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
 
										// Process rest of the keywords
										cell.Text = point.ReplaceKeywords(cell.Text);
										cell.ToolTip = point.ReplaceKeywords(cell.ToolTip);
#if !Microsoft_CONTROL
										cell.Url = point.ReplaceKeywords(cell.Url);
										cell.MapAreaAttributes = point.ReplaceKeywords(cell.MapAreaAttributes);
                                        cell.PostBackValue = point.ReplaceKeywords(cell.PostBackValue);
#endif // !Microsoft_CONTROL
									}
								}
 
								legendItems.Add(item);
							}
						}
 
							// Add item based on series name and fore color
						else
						{
							// Point should not be shown in the legend
							if(!series.IsVisibleInLegend)
							{
								continue;
							}
 
							// Create legend item
							LegendItem	item = new LegendItem(series.Name, series.Color, "");
							item.SetAttributes(this.Common, series);
 
							item.ToolTip = series.ReplaceKeywords(series.LegendToolTip);
#if !Microsoft_CONTROL
							item.Url = series.ReplaceKeywords(series.LegendUrl);
							item.MapAreaAttributes = series.ReplaceKeywords(series.LegendMapAreaAttributes);
                            item.PostBackValue = series.ReplaceKeywords(series.LegendPostBackValue);
#endif // !Microsoft_CONTROL
 
                            if (series.LegendText.Length > 0)
							{
								item.Name = series.ReplaceKeywords(series.LegendText);
							}
 
							// Add legend item cells based on predefined columns
							item.AddAutomaticCells(this);
							foreach(LegendCell cell in item.Cells)
							{
								if(cell.Text.Length > 0)
								{
									// #LEGENDTEXT - series name
									cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
 
									// Process rest of the keywords
									cell.Text = series.ReplaceKeywords(cell.Text);
									cell.ToolTip = series.ReplaceKeywords(cell.ToolTip);
#if !Microsoft_CONTROL
									cell.Url = series.ReplaceKeywords(cell.Url);
									cell.MapAreaAttributes = series.ReplaceKeywords(cell.MapAreaAttributes);
                                    cell.PostBackValue = series.ReplaceKeywords(cell.PostBackValue);
#endif // !Microsoft_CONTROL
								}
							}
 
                            legendItems.Add(item);
						}
					}
				}
			}
		
 
			// Check if series legend items should be reversed
            if (this.LegendItemOrder == LegendItemOrder.SameAsSeriesOrder ||
                (this.LegendItemOrder == LegendItemOrder.Auto && seriesWithReversedLegendItemsPresent))
			{
				// Reversed series generated legend items
				legendItems.Reverse();
			}
 
 
			// Add custom items
			foreach(LegendItem item in this._customLegends)
			{
				if(item.Enabled)
				{
					legendItems.Add(item);
				}
			}
 
			// Legend can't be empty at design time
			if(legendItems.Count == 0 && this.Common != null && this.Common.Chart != null)
			{
				if(this.Common.Chart.IsDesignMode())
				{
                    LegendItem item = new LegendItem(this.Name + " - " + SR.DescriptionTypeEmpty, Color.White, "");
					item.ImageStyle = LegendImageStyle.Line;
					legendItems.Add(item);
				}
			}
 
			// Add legend item cells based on predefined columns
			foreach(LegendItem item in this.legendItems)
			{
				item.AddAutomaticCells(this);
			}
 
		}
 
		#endregion
 
		#region Legend painting methods
 
		/// <summary>
		/// Paints legend using chart graphics object.
		/// </summary>
		/// <param name="chartGraph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
		internal void Paint(ChartGraphics chartGraph )
		{
			// Reset some values
			this._offset = Size.Empty;
			this._itemColumns = 0;
			this._horizontalSpaceLeft = 0;
			this._verticalSpaceLeft = 0;
			this._subColumnSizes = null;
			this._numberOfRowsPerColumn = null;
			this._cellHeights = null;
			this.autofitFont = null;
			this._autoFitFontSizeAdjustment = 0;
			this._numberOfCells = -1;
			this._numberOfLegendItemsToProcess = -1;
 
			// Do nothing if legend disabled
			if(!this.IsEnabled() ||
				(this.MaximumAutoSize == 0f && this.Position.Auto))
			{
				return;
			}
 
			// Add all series legend into items collection and then add custom legend items
			FillLegendItemsCollection();
 
			// Clear all legend item cells information
			foreach(LegendItem legendItem in this.legendItems)
			{
				foreach(LegendCell cell in legendItem.Cells)
				{
					cell.ResetCache();
				}
			}
 
			// Call a notification event, so that legend items collection can be modified by user
            this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
 
			// Check if legend is empty
			if(this.legendItems.Count == 0)
			{
				return;
			}
 
			//***********************************************************
			//** RecalculateAxesScale legend information
			//***********************************************************
			this.RecalcLegendInfo(chartGraph);
 
 
			
			//***********************************************************
			//** Paint legend
			//***********************************************************
 
			// Call BackPaint event
			if( Common.ProcessModePaint )
			{
				// Draw legend background, border and shadow
				chartGraph.FillRectangleRel( 
					chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
					BackColor, 
					BackHatchStyle, 
					BackImage, 
					BackImageWrapMode, 
					BackImageTransparentColor,
					BackImageAlignment,
					BackGradientStyle, 
					BackSecondaryColor,
					BorderColor, 
					this.GetBorderSize(), 
					BorderDashStyle, 
					ShadowColor, 
					ShadowOffset,
					PenAlignment.Inset);
 
                Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
			}
 
			if( Common.ProcessModeRegions )
			{
				SelectLegendBackground();
			}
 
			//***********************************************************
			//** Draw legend header
			//***********************************************************
 
			this.DrawLegendHeader(chartGraph);
 
			//***********************************************************
			//** Draw legend title
			//***********************************************************
 
			this.DrawLegendTitle(chartGraph);
 
			// Add legend title hot region
			if( Common.ProcessModeRegions && !this._titlePosition.IsEmpty)
			{
				Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._titlePosition), this, ChartElementType.LegendTitle, true );
			}
 
			//***********************************************************
			//** Draw legend items
			//***********************************************************
			if(this._numberOfLegendItemsToProcess < 0)
			{
				this._numberOfLegendItemsToProcess = this.legendItems.Count;
			}
			for(int itemIndex = 0; itemIndex < this._numberOfLegendItemsToProcess; itemIndex++)
			{
				LegendItem legendItem = this.legendItems[itemIndex];
 
				// Iterate through legend item cells
				for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
				{
					// Get legend cell
					LegendCell legendCell = legendItem.Cells[cellIndex];
 
					// Paint cell
					legendCell.Paint(
						chartGraph, 
						this._autoFitFontSizeAdjustment,
						this.autofitFont,
						this.singleWCharacterSize);
				}
 
				// Paint legend item separator
				if(legendItem.SeparatorType != LegendSeparatorStyle.None && 
					legendItem.Cells.Count > 0)
				{
					// Calculate separator position
					Rectangle separatorPosition = Rectangle.Empty;
					separatorPosition.X = legendItem.Cells[0].cellPosition.Left;
 
					// Find right most cell position excluding ovelapped cells that have negative size
					int right = 0;
					for(int index = legendItem.Cells.Count - 1; index >= 0; index--)
					{
						right = legendItem.Cells[index].cellPosition.Right;
						if(right > 0)
						{
							break;
						}
					}
					separatorPosition.Width = right - separatorPosition.X;
					separatorPosition.Y = legendItem.Cells[0].cellPosition.Bottom;
					separatorPosition.Height = this.GetSeparatorSize(legendItem.SeparatorType).Height;
					separatorPosition.Intersect(this._legendItemsAreaPosition);
 
					// Draw separator
					this.DrawSeparator(
						chartGraph, 
						legendItem.SeparatorType,
						legendItem.SeparatorColor, 
						true,
						separatorPosition);
				}
			}
 
			//***********************************************************
			//** If legend items are in multiple columns draw vertical
			//** separator
			//***********************************************************
			if(this.ItemColumnSeparator != LegendSeparatorStyle.None)
			{
				Rectangle separatorRect = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
				separatorRect.Y += this.GetBorderSize() + this._titlePosition.Height;
				separatorRect.Height -= 2 * this.GetBorderSize() + this._titlePosition.Height;
				separatorRect.X += this.GetBorderSize() + this._offset.Width;
				separatorRect.Width = this.GetSeparatorSize(this.ItemColumnSeparator).Width;
				if(this._horizontalSpaceLeft > 0)
				{
					separatorRect.X += this._horizontalSpaceLeft / 2;
				}
 
				// Check position
				if(separatorRect.Width > 0 && separatorRect.Height > 0)
				{
					// Iterate through all columns
					for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
					{
						// Iterate through all sub-columns
						int cellCount = this.GetNumberOfCells();
						for(int subColumnIndex = 0; subColumnIndex < cellCount; subColumnIndex++ )
						{
							separatorRect.X += this._subColumnSizes[columnIndex, subColumnIndex];
						}
 
						// Draw separator if not the last column
						if(columnIndex < this._itemColumns - 1)
						{
							this.DrawSeparator(chartGraph, this.ItemColumnSeparator, this.ItemColumnSeparatorColor, false, separatorRect);
						}
 
						// Add separator width
						separatorRect.X += separatorRect.Width;
					}
				}
			}
 
			//***********************************************************
			//** Draw special indicator on the bottom of the legend if 
			//** it was truncated.
			//***********************************************************
			if(this._legendItemsTruncated &&
				this._legendItemsAreaPosition.Height > this._truncatedDotsSize / 2)
			{
				// Calculate dots step (no more than 10 pixel)
				int markerCount = 3;
				int step = (this._legendItemsAreaPosition.Width / 3) / markerCount;
				step = (int)Math.Min(step, 10);
 
				// Calculate start point
				PointF	point = new PointF(
					this._legendItemsAreaPosition.X + this._legendItemsAreaPosition.Width / 2 - step * (float)Math.Floor(markerCount/2f),
					this._legendItemsAreaPosition.Bottom + (this._truncatedDotsSize + this._offset.Height) / 2);
 
				// Draw several dots at the bottom of the legend
				for(int index = 0; index < markerCount; index++)
				{
					chartGraph.DrawMarkerRel(
						chartGraph.GetRelativePoint(point),
						MarkerStyle.Circle,
						this._truncatedDotsSize,
						this.ForeColor,
						Color.Empty,
						0,
						string.Empty,
						Color.Empty,
						0,
						Color.Empty,
						RectangleF.Empty);
 
					// Shift to the right
					point.X += step;
				}
 
			}
 
 
			// Call Paint event
			if( Common.ProcessModePaint )
			{
                Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
			}
						
			// Remove temporary cells from legend items
			foreach(LegendItem legendItem in this.legendItems)
			{
				if(legendItem.clearTempCells)
				{
					legendItem.clearTempCells = false;
					legendItem.Cells.Clear();
				}
			}
 
		}
 
		#endregion 
 
		#region	Legend properties
 
		/// <summary>
		/// Gets or sets the name of the legend.
		/// </summary>
		[
		SRCategory("CategoryAttributeMisc"),
		Bindable(true),
		SRDescription("DescriptionAttributeLegend_Name"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		]
		public override string Name
		{
			get
			{
				return base.Name;
			}
			set
			{
                base.Name = value;
			}
		}
 
		/// <summary>
		/// Gets or sets the name of the chart area where the legend
        /// should be docked.
		/// </summary>
		[
		SRCategory("CategoryAttributeDocking"),
		Bindable(true),
        DefaultValue(Constants.NotSetValue),
		SRDescription("DescriptionAttributeLegend_DockToChartArea"),
        TypeConverter(typeof(LegendAreaNameConverter)),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		]
		public string DockedToChartArea
		{
			get
			{
				return _dockedToChartArea;
			}
			set
			{
				if(value != _dockedToChartArea)
				{
					if (String.IsNullOrEmpty(value))
					{
                        _dockedToChartArea = Constants.NotSetValue;
					}
					else
					{
                        if (Chart != null && Chart.ChartAreas != null)
                        {
                            Chart.ChartAreas.VerifyNameReference(value);
                        }
						_dockedToChartArea = value;
					}
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
		/// Gets or sets a property which indicates whether 
        /// the legend is docked inside the chart area.  
        /// This property is only available when DockedToChartArea is set.
		/// </summary>
		[
        SRCategory("CategoryAttributeDocking"),
		Bindable(true),
		DefaultValue(true),
		SRDescription("DescriptionAttributeLegend_DockInsideChartArea"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		]
		public bool IsDockedInsideChartArea
		{
			get
			{
				return _isDockedInsideChartArea;
			}
			set
			{
				if(value != _isDockedInsideChartArea)
				{
					_isDockedInsideChartArea = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the position of the legend.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		SRDescription("DescriptionAttributeLegend_Position"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
		NotifyParentPropertyAttribute(true),
		TypeConverter(typeof(ElementPositionConverter)),
		SerializationVisibilityAttribute(SerializationVisibility.Element)
		]
		public ElementPosition Position
		{
			get
			{	
				// Serialize only position values if Auto set to false
                if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
				{
					if(_position.Auto)
					{
						return new ElementPosition();	
					}
					else
					{
						ElementPosition newPosition = new ElementPosition();
#if Microsoft_CONTROL
						newPosition.Auto = false;
#else
						newPosition.Auto = true;
#endif
						newPosition.SetPositionNoAuto(_position.X, _position.Y, _position.Width, _position.Height);
						return newPosition;
					}
				}
				return _position;
			}
			set
			{
				_position = value;
				this.Invalidate(false);
			}
		}
 
        /// <summary>
        /// Determoines if this position should be serialized.
        /// </summary>
        /// <returns></returns>
        internal bool ShouldSerializePosition()
        {
            return !this.Position.Auto;
        }
 
 
		/// <summary>
		/// Gets or sets a property which indicates whether 
        /// all legend items are equally spaced.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(false),
		SRDescription("DescriptionAttributeLegend_EquallySpacedItems"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public bool IsEquallySpacedItems
		{
			get
			{
				return _isEquallySpacedItems;
			}
			set
			{
				_isEquallySpacedItems = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets a flag which indicates whether the legend is enabled.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(true),
		SRDescription("DescriptionAttributeLegend_Enabled"),
		NotifyParentPropertyAttribute(true),
		ParenthesizePropertyNameAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				_enabled = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
        /// Gets or sets a value that indicates if legend text is automatically sized.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(true),
		SRDescription("DescriptionAttributeLegend_AutoFitText"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public bool IsTextAutoFit
		{
			get
			{
				return _isTextAutoFit;
			}
			set
			{
				_isTextAutoFit = value;
 
				if(_isTextAutoFit)
				{
					// Reset the font size to "8"
					// Use current font family name ans style if possible.
					if(_font != null)
					{
                        _font = _fontCache.GetFont(_font.FontFamily, 8, _font.Style); ;
					}
					else
					{
						_font = _fontCache.DefaultFont;
					}
				}
 
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the legend style.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(LegendStyle.Table),
		SRDescription("DescriptionAttributeLegend_LegendStyle"),
		NotifyParentPropertyAttribute(true),
		ParenthesizePropertyNameAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public LegendStyle LegendStyle
		{
			get
			{
				return _legendStyle;
			}
			set
			{
				_legendStyle = value;
				this.Invalidate(false);
			}
		}
 
 
		/// <summary>
        /// Gets or sets the minimum font size that can be used by the legend text's auto-fitting algorithm. 
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(7),
		SRDescription("DescriptionAttributeLegend_AutoFitMinFontSize"),
		]
		public int AutoFitMinFontSize
		{
			get
			{
				return this._autoFitMinFontSize;
			}
			set
			{
				// Font size cannot be less than 5
				if(value < 5)
				{
                    throw (new InvalidOperationException(SR.ExceptionLegendAutoFitMinFontSizeInvalid));
				}
 
				this._autoFitMinFontSize = value;
				this.Invalidate(false);
			}
		}
 
        /// <summary>
        /// Gets or sets the maximum size (in percentage) of the legend used in the automatic layout algorithm.
        /// </summary>
        /// <remarks>
        /// If the legend is docked to the left or right, this property determines the maximum width of the legend, measured as a percentage.
        /// If the legend is docked to the top or bottom, this property determines the maximum height of the legend, measured as a percentage.
        /// </remarks>
		[
		SRCategory("CategoryAttributeDocking"),
		DefaultValue(50f),
		SRDescription("DescriptionAttributeLegend_MaxAutoSize"),
		]
		public float MaximumAutoSize
		{
			get
			{
                return this._maximumLegendAutoSize;
			}
			set
			{
				if(value < 0f || value > 100f)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMaximumAutoSizeInvalid));
				}
                this._maximumLegendAutoSize = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets a collection of legend columns.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		SRDescription("DescriptionAttributeLegend_CellColumns"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
        Editor(Editors.LegendCellColumnCollectionEditor.Editor, Editors.LegendCellColumnCollectionEditor.Base),
		]
		public LegendCellColumnCollection CellColumns
		{
			get
			{
				return this._cellColumns;
			}
		}
 
		/// <summary>
		/// Gets the legend table style.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(LegendTableStyle.Auto),
		SRDescription("DescriptionAttributeLegend_TableStyle"),
		NotifyParentPropertyAttribute(true),
		ParenthesizePropertyNameAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public LegendTableStyle TableStyle
		{
			get
			{
				return this._legendTableStyle;
			}
			set
			{
				this._legendTableStyle = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets the legend header separator style.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		DefaultValue(typeof(LegendSeparatorStyle), "None"),
		SRDescription("DescriptionAttributeLegend_HeaderSeparator"),
		]
		public LegendSeparatorStyle HeaderSeparator
		{
			get
			{
				return this._headerSeparator;
			}
			set
			{
				if(value != this._headerSeparator)
				{
					this._headerSeparator = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
		/// Gets or sets the color of the legend header separator.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		DefaultValue(typeof(Color), "Black"),
		SRDescription("DescriptionAttributeLegend_HeaderSeparatorColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color HeaderSeparatorColor
		{
			get
			{
				return this._headerSeparatorColor;
			}
			set
			{
				if(value != this._headerSeparatorColor)
				{
					this._headerSeparatorColor = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the separator style of the legend table columns.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		DefaultValue(typeof(LegendSeparatorStyle), "None"),
		SRDescription("DescriptionAttributeLegend_ItemColumnSeparator"),
		]
		public LegendSeparatorStyle ItemColumnSeparator
		{
			get
			{
				return this._itemColumnSeparator;
			}
			set
			{
				if(value != this._itemColumnSeparator)
				{
					this._itemColumnSeparator = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the color of the separator of the legend table columns.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		DefaultValue(typeof(Color), "Black"),
		SRDescription("DescriptionAttributeLegend_ItemColumnSeparatorColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color ItemColumnSeparatorColor
		{
			get
			{
				return this._itemColumnSeparatorColor;
			}
			set
			{
				if(value != this._itemColumnSeparatorColor)
				{
					this._itemColumnSeparatorColor = value;
					this.Invalidate(false);
				}
			}
		}
 
 
		/// <summary>
		/// Gets or sets the legend table column spacing, as a percentage of the legend text font.
		/// </summary>
		[
		SRCategory("CategoryAttributeCellColumns"),
		DefaultValue(50),
		SRDescription("DescriptionAttributeLegend_ItemColumnSpacing"),
		]
		public int ItemColumnSpacing
		{
			get
			{
				return this._itemColumnSpacing;
			}
			set
			{
				if(value != this._itemColumnSpacing)
				{
					if(value < 0)
					{
                        throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendColumnSpacingInvalid));
					}
					this._itemColumnSpacing = value;
					this.Invalidate(false);
				}
			}
		}
 
 
 
		/// <summary>
		/// Gets or sets the legend background color.
		/// </summary>
		[
		DefaultValue(typeof(Color), ""),
        SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
        SRDescription("DescriptionAttributeBackColor"),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BackColor
		{
			get
			{
				return _backColor;
			}
			set
			{
				_backColor = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the legend border color.
		/// </summary>
		[
		DefaultValue(typeof(Color), ""),
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
        SRDescription("DescriptionAttributeBorderColor"),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BorderColor
		{
			get
			{
				return _borderColor;
			}
			set
			{
				_borderColor = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the legend border style.
		/// </summary>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartDashStyle.Solid),
        SRDescription("DescriptionAttributeBorderDashStyle"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public ChartDashStyle BorderDashStyle
		{
			get
			{
				return _borderDashStyle;
			}
			set
			{
				_borderDashStyle = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the legend border width.
		/// </summary>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(1),
        SRDescription("DescriptionAttributeBorderWidth"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public int BorderWidth
		{
			get
			{
				return _borderWidth;
			}
			set
			{
				if(value < 0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendBorderWidthIsNegative));
				}
				_borderWidth = value;
				this.Invalidate(false);
			}
		}
		
		/// <summary>
		/// Gets or sets the legend background image.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(""),
        SRDescription("DescriptionAttributeBackImage"),
        Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		NotifyParentPropertyAttribute(true),
		]
		public string BackImage
		{
			get
			{
				return _backImage;
			}
			set
			{
				_backImage = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the legend background image drawing mode.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartImageWrapMode.Tile),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeImageWrapMode"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public ChartImageWrapMode BackImageWrapMode
		{
			get
			{
				return _backImageWrapMode;
			}
			set
			{
				_backImageWrapMode = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeImageTransparentColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BackImageTransparentColor
		{
			get
			{
				return _backImageTransparentColor;
			}
			set
			{
				_backImageTransparentColor = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the background image alignment used for the unscaled drawing mode.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartImageAlignmentStyle.TopLeft),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackImageAlign"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public ChartImageAlignmentStyle BackImageAlignment
		{
			get
			{
				return _backImageAlignment;
			}
			set
			{
				_backImageAlignment = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets background gradient style of the legend.
		/// </summary>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(GradientStyle.None),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackGradientStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
        Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
 
		]
		public GradientStyle BackGradientStyle
		{
			get
			{
				return _backGradientStyle;
			}
			set
			{
				_backGradientStyle = value;
				this.Invalidate(true);
			}
		}
 
        /// <summary>
        /// Gets or sets the secondary background color.
        /// <seealso cref="BackColor"/>
        /// <seealso cref="BackHatchStyle"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used for the secondary color of background with 
        /// hatching or gradient fill.
        /// </value>
        /// <remarks>
        /// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
        /// <see cref="BackGradientStyle"/> are used.
        /// </remarks>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackSecondaryColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BackSecondaryColor
		{
			get
			{
				return _backSecondaryColor;
			}
			set
			{
				_backSecondaryColor = value;
				this.Invalidate(true);
			}
		}
 
        /// <summary>
        /// Gets or sets the background hatch style.
        /// <seealso cref="BackSecondaryColor"/>
        /// <seealso cref="BackColor"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="ChartHatchStyle"/> value used for the background.
        /// </value>
        /// <remarks>
        /// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
        /// </remarks>
		[
 
        SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartHatchStyle.None),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackHatchStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
        Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
		]
		public ChartHatchStyle BackHatchStyle
		{
			get
			{
				return _backHatchStyle;
			}
			set
			{
				_backHatchStyle = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the font of the legend text.
		/// </summary>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
		SRDescription("DescriptionAttributeLegend_Font"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Font Font
		{
			get
			{
				return _font;
			}
			set
			{
				this.IsTextAutoFit = false;
 
				_font = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the color of the legend text.
		/// </summary>
		[
 
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeLegendFontColor"),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color ForeColor
		{
			get
			{
				return _foreColor;
			}
			set
			{
				_foreColor = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the text alignment.
		/// </summary>
		[
		SRCategory("CategoryAttributeDocking"),
		Bindable(true),
		DefaultValue(StringAlignment.Near),
		SRDescription("DescriptionAttributeLegend_Alignment"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public StringAlignment Alignment
		{
			get
			{
				return _legendAlignment;
			}
			set
			{
				_legendAlignment = value;
				this.Invalidate(false);
			}
		}
		
		/// <summary>
		/// Gets or sets the property that specifies where the legend docks.
		/// </summary>
		[
        SRCategory("CategoryAttributeDocking"),
		Bindable(true),
		DefaultValue(Docking.Right),
		SRDescription("DescriptionAttributeLegend_Docking"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Docking Docking
		{
			get
			{
				return _legendDocking;
			}
			set
			{
				_legendDocking = value;
				this.Invalidate(false);
			}
		}
 
        /// <summary>
        /// Gets or sets the offset between the legend and its shadow.
        /// <seealso cref="ShadowColor"/>
        /// </summary>
        /// <value>
        /// An integer value that represents the offset between the legend and its shadow.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(0),
        SRDescription("DescriptionAttributeShadowOffset"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public int ShadowOffset
		{
			get
			{
				return _shadowOffset;
			}
			set
			{
				_shadowOffset = value;
				this.Invalidate(false);
			}
		}
 
        /// <summary>
        /// Gets or sets the color of a legend's shadow.
        /// <seealso cref="ShadowOffset"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used to draw a legend's shadow.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), "128, 0, 0, 0"),
        SRDescription("DescriptionAttributeShadowColor"),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color ShadowColor
		{
			get
			{
				return _shadowColor;
			}
			set
			{
				_shadowColor = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the name of the chart area name inside which the legend is drawn.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Browsable(false),
		Bindable(false),
        DefaultValue(Constants.NotSetValue),
		NotifyParentPropertyAttribute(true),
		SRDescription("DescriptionAttributeLegend_InsideChartArea"),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		TypeConverter(typeof(LegendAreaNameConverter))
		]
		public string InsideChartArea
		{
			get
			{
				if(this.Common != null && 
					this.Common.Chart != null &&
					this.Common.Chart.serializing)
				{
					return "NotSet";
				}
				return this.DockedToChartArea;
			}
			set
			{
				if(value.Length == 0)
				{
                    this.DockedToChartArea = Constants.NotSetValue;
				}
				else
				{
					this.DockedToChartArea = value;
				}
				this.Invalidate(false);
			}
		}
 
 
		/// <summary>
		/// Gets the custom legend items.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		NotifyParentPropertyAttribute(true),
		SRDescription("DescriptionAttributeLegend_CustomItems"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
        Editor(Editors.LegendItemCollectionEditor.Editor, Editors.LegendItemCollectionEditor.Base),
		]
		public LegendItemsCollection CustomItems
		{
			get
			{
				return _customLegends;
			}
		}
 
 
 
		/// <summary>
		/// Gets or sets a property that defines the preferred number of characters in a line of the legend text.
		/// </summary>
		/// <remarks>
		/// When legend text exceeds the value defined in the <b>TextWrapThreshold</b> property, it will be
		/// automatically wrapped on the next whitespace. Text will not be wrapped if there is no whitespace
		/// characters in the text. Set this property to zero to disable the feature.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(25),
		SRDescription("DescriptionAttributeLegend_TextWrapThreshold"),
		]
		public int TextWrapThreshold
		{
			get
			{
				return this._textWrapThreshold;
			}
			set
			{
				if(value != this._textWrapThreshold)
				{
					if(value < 0)
					{
                        throw (new ArgumentException(SR.ExceptionTextThresholdIsNegative, "value"));
					}
					this._textWrapThreshold = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
		/// Gets or sets a property that specifies the order that legend items are shown. This property only affects 
		/// legend items automatically added for the chart series and has no effect on custom legend items.
		/// </summary>
		/// <remarks>
		/// When the <b>LegendItemOrder</b> property is set to <b>Auto</b>, the legend will automatically be reversed 
		/// if StackedColumn, StackedColumn100, StackedArea or StackedArea100 chart types are used.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
        DefaultValue(LegendItemOrder.Auto),
		SRDescription("DescriptionAttributeLegend_Reversed"),
		]
        public LegendItemOrder LegendItemOrder
		{
			get
			{
				return this._legendItemOrder;
			}
			set
			{
				if(value != this._legendItemOrder)
				{
					this._legendItemOrder = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
		/// Gets or sets a flag which indicates whether 
        /// legend rows should be drawn with interlaced background color.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(false),
		SRDescription("DescriptionAttributeLegend_InterlacedRows"),
		]
		public bool InterlacedRows
		{
			get
			{
				return this._interlacedRows;
			}
			set
			{
				if(value != this._interlacedRows)
				{
					this._interlacedRows = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the legend interlaced row's background color. Only applicable if interlaced rows are used. 
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), ""),
		SRDescription("DescriptionAttributeLegend_InterlacedRowsColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color InterlacedRowsColor
		{
			get
			{
				return this._interlacedRowsColor;
			}
			set
			{
				if(value != this._interlacedRowsColor)
				{
					this._interlacedRowsColor = value;
					this.Invalidate(false);
				}
			}
		}
 
		#endregion
 
		#region Legend Title Properties
 
		/// <summary>
		/// Gets or sets the title text of the legend.
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(""),
		SRDescription("DescriptionAttributeLegend_Title"),
		]
		public string Title
		{
			get
			{
				return this._title;
			}
			set
			{
				if(value != this._title)
				{
					this._title = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the text color of the legend title.
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(typeof(Color), "Black"),
		SRDescription("DescriptionAttributeLegend_TitleColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color TitleForeColor
		{
			get
			{
				return this._titleForeColor;
			}
			set
			{
				if(value != this._titleForeColor)
				{
					this._titleForeColor = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the background color of the legend title. 
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeTitleBackColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color TitleBackColor
		{
			get
			{
				return this._titleBackColor;
			}
			set
			{
				if(value != this._titleBackColor)
				{
					this._titleBackColor = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the font of the legend title. 
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
        DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt, style=Bold"),
        SRDescription("DescriptionAttributeTitleFont"),
		]
		public Font TitleFont
		{
			get
			{
				return this._titleFont;
			}
			set
			{
				if(value != this._titleFont)
				{
					this._titleFont = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the text alignment of the legend title.
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(typeof(StringAlignment), "Center"),
		SRDescription("DescriptionAttributeLegend_TitleAlignment"),
		]
		public StringAlignment TitleAlignment
		{
			get
			{
				return this._titleAlignment;
			}
			set
			{
				if(value != this._titleAlignment)
				{
					this._titleAlignment = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the separator style of the legend title.
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(typeof(LegendSeparatorStyle), "None"),
		SRDescription("DescriptionAttributeLegend_TitleSeparator"),
		]
		public LegendSeparatorStyle TitleSeparator
		{
			get
			{
				return this._titleSeparator;
			}
			set
			{
				if(value != this._titleSeparator)
				{
					this._titleSeparator = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the separator color of the legend title.
		/// </summary>
		[
		SRCategory("CategoryAttributeTitle"),
		DefaultValue(typeof(Color), "Black"),
		SRDescription("DescriptionAttributeLegend_TitleSeparatorColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color TitleSeparatorColor
		{
			get
			{
				return this._titleSeparatorColor;
			}
			set
			{
				if(value != this._titleSeparatorColor)
				{
					this._titleSeparatorColor = value;
					this.Invalidate(false);
				}
			}
		}
 
 
 
		#endregion // Legend Title Properties
 
		#region Legent Title and Header Helper methods
 
		/// <summary>
		/// Gets legend title size in relative coordinates.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="titleMaxSize">Maximum possible legend title size.</param>
		/// <returns>Legend yitle size.</returns>
		private Size GetTitleSize(ChartGraphics chartGraph, Size titleMaxSize)
		{
			Size titleSize = Size.Empty;
			if(this.Title.Length > 0)
			{
				// Adjust available space
				titleMaxSize.Width -= this.GetBorderSize() * 2 + this._offset.Width;
 
				// Measure title text size
				titleSize = chartGraph.MeasureStringAbs(
					this.Title.Replace("\\n", "\n"), 
					this.TitleFont,
					titleMaxSize,
					StringFormat.GenericTypographic);
 
				// Add text spacing
				titleSize.Height += this._offset.Height;
				titleSize.Width += this._offset.Width;
 
				// Add space required for the title separator
				titleSize.Height += this.GetSeparatorSize(this.TitleSeparator).Height;
			}
 
			return titleSize;
		}
 
		/// <summary>
		/// Gets legend header size in relative coordinates.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="legendColumn">Legend column to get the header for.</param>
		/// <returns>Legend yitle size.</returns>
		private Size GetHeaderSize(ChartGraphics chartGraph, LegendCellColumn legendColumn)
		{
			Size headerSize = Size.Empty;
			if(legendColumn.HeaderText.Length > 0)
			{
				// Measure title text size
				headerSize = chartGraph.MeasureStringAbs(
					legendColumn.HeaderText.Replace("\\n", "\n") + "I", 
					legendColumn.HeaderFont);
 
				// Add text spacing
				headerSize.Height += this._offset.Height;
				headerSize.Width += this._offset.Width;
 
				// Add space required for the title separator
				headerSize.Height += this.GetSeparatorSize(this.HeaderSeparator).Height;
			}
 
			return headerSize;
		}
 
		/// <summary>
		/// Draw Legend header.
		/// </summary>
		/// <param name="chartGraph">Chart graphics to draw the header on.</param>
		private void DrawLegendHeader(ChartGraphics chartGraph)
		{
			// Check if header should be drawn
			if(!this._headerPosition.IsEmpty &&
				this._headerPosition.Width > 0 &&
				this._headerPosition.Height > 0)
			{
				int prevRightLocation = -1;
				bool redrawLegendBorder = false;
 
				// Get Legend position
				Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
				legendPosition.Y += /*this.offset.Height + */this.GetBorderSize();
				legendPosition.Height -= 2 * (this._offset.Height + this.GetBorderSize());
				legendPosition.X += this.GetBorderSize();
				legendPosition.Width -= 2 * this.GetBorderSize();
				if(this.GetBorderSize() > 0)
				{
					++legendPosition.Height;
					++legendPosition.Width;
				}
 
				// Check if at least 1 column header has non-empty background color
				bool	headerBackFill = false;
				for(int subColumnIndex = 0; subColumnIndex < this.CellColumns.Count; subColumnIndex++ )
				{
					LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
					if(!legendColumn.HeaderBackColor.IsEmpty)
					{
						headerBackFill = true;
					}
				}
 
				// Iterate through all columns
				for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
				{
					int columnStart = 0;
					int columnWidth = 0;
 
					// Iterate through all sub-columns
					int numberOfSubColumns = this._subColumnSizes.GetLength(1);
					for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++ )
					{
						// Calculate position of the header
						Rectangle rect = this._headerPosition;
						if(_horizontalSpaceLeft > 0)
						{
							rect.X += (int)(this._horizontalSpaceLeft / 2f);
						}
						if(prevRightLocation != -1)
						{
							rect.X = prevRightLocation;
						}
						rect.Width = this._subColumnSizes[columnIndex, subColumnIndex];
						prevRightLocation = rect.Right;
 
						// Remember column start position and update width
						if(subColumnIndex == 0)
						{
							columnStart = rect.Left;
						}
						columnWidth += rect.Width;
 
						// Make sure header position do not go outside of the legend
						rect.Intersect(legendPosition);
						if(rect.Width > 0 && rect.Height > 0)
						{
							// Define fill rectangle
							Rectangle fillRect = rect;
 
							// Make sure header fill riches legend top border
							if(this._titlePosition.Height <= 0)
							{
								fillRect.Y -= this._offset.Height;
								fillRect.Height += this._offset.Height;
							}
 
							// Stretch header fill rectangle and separators when vertical 
							// separator are used or if there is 1 column with header background
							if( (this._itemColumns == 1 && headerBackFill) ||
								this.ItemColumnSeparator != LegendSeparatorStyle.None)
							{
								// For the first cell in the first column stretch filling
								// to the left side of the legend
								if(columnIndex == 0 && subColumnIndex == 0)
								{
									int newX = legendPosition.X;
									columnWidth += columnStart - newX;
									columnStart = newX;
									fillRect.Width += fillRect.X - legendPosition.X;
									fillRect.X = newX;
								}
 
								// For the last cell in the last column stretch filling
								// to the right side of the legend
								if(columnIndex == (this._itemColumns - 1) && 
									subColumnIndex == (numberOfSubColumns - 1) )
								{
									columnWidth += legendPosition.Right - fillRect.Right + 1;
									fillRect.Width += legendPosition.Right - fillRect.Right + 1;
								}
 
								// For the first cell of any column except the first one
								// make sure we also fill the item column spacing
								if(columnIndex != 0 && subColumnIndex == 0)
								{
									columnWidth += this._itemColumnSpacingRel / 2;
									columnStart -= this._itemColumnSpacingRel / 2;
									fillRect.Width += this._itemColumnSpacingRel / 2;
									fillRect.X -= this._itemColumnSpacingRel / 2;
								}
 
								// For the last cell in all columns except the last one 
								// make sure we also fill the item column spacing
								if(columnIndex != (this._itemColumns - 1) && 
									subColumnIndex == (numberOfSubColumns - 1) )
								{
									columnWidth += this._itemColumnSpacingRel / 2;
									fillRect.Width += this._itemColumnSpacingRel / 2;
								}
							}
 
							if(subColumnIndex < this.CellColumns.Count)
							{
								// Draw header background
								LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
								if(!legendColumn.HeaderBackColor.IsEmpty)
								{
									redrawLegendBorder = true;
 
									// Fill title background
									if(fillRect.Right > legendPosition.Right)
									{
										fillRect.Width -= (legendPosition.Right - fillRect.Right);
									}
									if(fillRect.X < legendPosition.X)
									{
										fillRect.X += legendPosition.X - fillRect.X;
										fillRect.Width -= (legendPosition.X - fillRect.X);
									}
									fillRect.Intersect(legendPosition);
									chartGraph.FillRectangleRel( 
										chartGraph.GetRelativeRectangle(fillRect), 
										legendColumn.HeaderBackColor, 
										ChartHatchStyle.None,
										string.Empty,
										ChartImageWrapMode.Tile, 
										Color.Empty,
										ChartImageAlignmentStyle.Center,
										GradientStyle.None, 
										Color.Empty,
										Color.Empty, 
										0, 
										ChartDashStyle.NotSet, 
										Color.Empty, 
										0,
										PenAlignment.Inset);
 
								}
 
								// Draw header text
								using(SolidBrush textBrush = new SolidBrush(legendColumn.HeaderForeColor))
								{
									// Set text alignment
                                    using (StringFormat format = new StringFormat())
                                    {
                                        format.Alignment = legendColumn.HeaderAlignment;
                                        format.LineAlignment = StringAlignment.Center;
                                        format.FormatFlags = StringFormatFlags.LineLimit;
                                        format.Trimming = StringTrimming.EllipsisCharacter;
 
                                        // Draw string using relative coordinates
                                        chartGraph.DrawStringRel(
                                            legendColumn.HeaderText,
                                            legendColumn.HeaderFont,
                                            textBrush,
                                            chartGraph.GetRelativeRectangle(rect),
                                            format);
                                    }
								}
							}
						}
					}
 
					// Draw header separator for each column
					Rectangle separatorRect = this._headerPosition;
					separatorRect.X = columnStart;
					separatorRect.Width = columnWidth;
					if(this.HeaderSeparator == LegendSeparatorStyle.Line || this.HeaderSeparator == LegendSeparatorStyle.DoubleLine)
					{
						// NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than 
						// any other line. Reduce width to solve the issue.
						legendPosition.Width -= 1;
					}
					separatorRect.Intersect(legendPosition);
					this.DrawSeparator(chartGraph, this.HeaderSeparator, this.HeaderSeparatorColor, true, separatorRect);
 
					// Add spacing between columns
					prevRightLocation += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
				}
			
				// Draw legend border to solve any issues with header background overlapping
				if(redrawLegendBorder)
				{
					chartGraph.FillRectangleRel( 
						chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.None, 
						Color.Empty,
						BorderColor, 
						this.GetBorderSize(), 
						BorderDashStyle, 
						Color.Empty, 
						0,
						PenAlignment.Inset);
 
				}
			
				// Add legend header hot region
				if( Common.ProcessModeRegions && !this._headerPosition.IsEmpty)
				{
					Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._headerPosition), this, ChartElementType.LegendHeader, true );
				}
 
			}
		}
 
		/// <summary>
		/// Draw Legend title.
		/// </summary>
		/// <param name="chartGraph">Chart graphics to draw the title on.</param>
		private void DrawLegendTitle(ChartGraphics chartGraph)
		{
			// Check if title text is specified and position recalculated
			if(this.Title.Length > 0 &&
				!this._titlePosition.IsEmpty)
			{
				// Get Legend position
				Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
				legendPosition.Y += this.GetBorderSize();
				legendPosition.Height -= 2 * this.GetBorderSize();
				legendPosition.X += this.GetBorderSize();
				legendPosition.Width -= 2 * this.GetBorderSize();
				if(this.GetBorderSize() > 0)
				{
					++legendPosition.Height;
					++legendPosition.Width;
				}
 
				// Draw title background
				if(!this.TitleBackColor.IsEmpty)
				{
					// Fill title background
					Rectangle fillRect = this._titlePosition;
					fillRect.Intersect(legendPosition);
					chartGraph.FillRectangleRel( 
						chartGraph.GetRelativeRectangle(fillRect), 
						this.TitleBackColor, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.None, 
						Color.Empty,
						Color.Empty, 
						0, 
						ChartDashStyle.NotSet, 
						Color.Empty, 
						0,
						PenAlignment.Inset);
				}
 
				// Draw title text
				using(SolidBrush textBrush = new SolidBrush(this.TitleForeColor))
				{
					// Set text alignment
					StringFormat format = new StringFormat();
					format.Alignment = this.TitleAlignment;
					//format.LineAlignment = StringAlignment.Center;
 
					// Shift text rectangle by the top offset amount
					Rectangle rect = this._titlePosition;
					rect.Y += this._offset.Height;
					rect.X += this._offset.Width;
					rect.X += this.GetBorderSize();
					rect.Width -= this.GetBorderSize() * 2 + this._offset.Width;
 
					// Draw string using relative coordinates
					rect.Intersect(legendPosition);
					chartGraph.DrawStringRel(
						this.Title.Replace("\\n", "\n"),
						this.TitleFont,
						textBrush,
						chartGraph.GetRelativeRectangle(rect),
						format);
				}
 
				// Draw title separator
				Rectangle separatorPosition = this._titlePosition;
				if(this.TitleSeparator == LegendSeparatorStyle.Line || this.TitleSeparator == LegendSeparatorStyle.DoubleLine)
				{
					// NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than 
					// any other line. Reduce width to solve the issue.
					legendPosition.Width -= 1;
				}
				separatorPosition.Intersect(legendPosition);
				this.DrawSeparator(chartGraph, this.TitleSeparator, this.TitleSeparatorColor, true, separatorPosition);
 
				// Draw legend border to solve any issues with title background overlapping
				if(!this.TitleBackColor.IsEmpty || 
					this.TitleSeparator != LegendSeparatorStyle.None)
				{
					chartGraph.FillRectangleRel( 
						chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.None, 
						Color.Empty,
						BorderColor, 
						this.GetBorderSize(), 
						BorderDashStyle, 
						Color.Empty, 
						0,
						PenAlignment.Inset);
 
				}
			}
		}
 
		/// <summary>
		/// Gets legend separator size in pixels
		/// </summary>
		/// <param name="separatorType">Separator type.</param>
		/// <returns>Separator size in relative coordinates.</returns>
		internal Size GetSeparatorSize(LegendSeparatorStyle separatorType)
		{
			Size size = Size.Empty;
 
			if(separatorType == LegendSeparatorStyle.None)
			{
				size = Size.Empty;
			}
			else if(separatorType == LegendSeparatorStyle.Line)
			{
				size = new Size(1, 1);
			}
			else if(separatorType == LegendSeparatorStyle.DashLine)
			{
				size = new Size(1, 1);
			}
			else if(separatorType == LegendSeparatorStyle.DotLine)
			{
				size = new Size(1, 1);
			}
			else if(separatorType == LegendSeparatorStyle.ThickLine)
			{
				size = new Size(2, 2);
			}
			else if(separatorType == LegendSeparatorStyle.DoubleLine)
			{
				size = new Size(3, 3);
			}
			else if(separatorType == LegendSeparatorStyle.GradientLine)
			{
				size = new Size(1, 1);
			}
			else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
			{
				size = new Size(2, 2);
			}
			else
			{
                throw (new InvalidOperationException(SR.ExceptionLegendSeparatorTypeUnknown(separatorType.ToString())));
			}
 
			// For the vertical part of the separator always add additiobal spacing
			size.Width += this._itemColumnSpacingRel;
 
			return size;
		}
 
		/// <summary>
		/// Draws specified legend separator.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="separatorType">Separator type.</param>
		/// <param name="color">Separator color.</param>
		/// <param name="horizontal">Flag that determines if separator is vertical or horizontal.</param>
		/// <param name="position">Separator position.</param>
		private void DrawSeparator(
			ChartGraphics chartGraph, 
			LegendSeparatorStyle separatorType, 
			Color color, 
			bool horizontal,
			Rectangle position)
		{
			// Temporary disable antialiasing
			SmoothingMode oldSmoothingMode = chartGraph.SmoothingMode;
			chartGraph.SmoothingMode = SmoothingMode.None;
 
			// Get line position in absolute coordinates
			RectangleF rect = position;
			if(!horizontal)
			{
				rect.X += (int)(_itemColumnSpacingRel / 2f);
				rect.Width -= _itemColumnSpacingRel;
			}
			if(separatorType == LegendSeparatorStyle.Line)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Left, rect.Bottom - 1),
						new PointF(rect.Right, rect.Bottom - 1) );
 
				}
				else
				{
					// Draw vertical line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Right - 1, rect.Top),
						new PointF(rect.Right - 1, rect.Bottom) );
				}
			}
			else if(separatorType == LegendSeparatorStyle.DashLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Dash,
						new PointF(rect.Left, rect.Bottom - 1),
						new PointF(rect.Right, rect.Bottom - 1) );
 
				}
				else
				{
					// Draw vertical line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Dash,
						new PointF(rect.Right - 1, rect.Top),
						new PointF(rect.Right - 1, rect.Bottom) );
				}
			}
			else if(separatorType == LegendSeparatorStyle.DotLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Dot,
						new PointF(rect.Left, rect.Bottom - 1),
						new PointF(rect.Right, rect.Bottom - 1) );
 
				}
				else
				{
					// Draw vertical line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Dot,
						new PointF(rect.Right - 1, rect.Top),
						new PointF(rect.Right - 1, rect.Bottom) );
				}
			}
			else if(separatorType == LegendSeparatorStyle.ThickLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.DrawLineAbs(
						color,
						2,
						ChartDashStyle.Solid,
						new PointF(rect.Left, rect.Bottom - 1f),
						new PointF(rect.Right, rect.Bottom - 1f) );
				}
				else
				{
					// Draw vertical line separator
					chartGraph.DrawLineAbs(
						color,
						2,
						ChartDashStyle.Solid,
						new PointF(rect.Right - 1f, rect.Top),
						new PointF(rect.Right - 1f, rect.Bottom) );
				}
			}
			else if(separatorType == LegendSeparatorStyle.DoubleLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Left, rect.Bottom - 3),
						new PointF(rect.Right, rect.Bottom - 3) );
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Left, rect.Bottom - 1),
						new PointF(rect.Right, rect.Bottom - 1) );
				}
				else
				{
					// Draw vertical line separator
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Right - 3, rect.Top),
						new PointF(rect.Right - 3, rect.Bottom) );
					chartGraph.DrawLineAbs(
						color,
						1,
						ChartDashStyle.Solid,
						new PointF(rect.Right - 1, rect.Top),
						new PointF(rect.Right - 1, rect.Bottom) );
				}
			}
			else if(separatorType == LegendSeparatorStyle.GradientLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.FillRectangleAbs( 
						new RectangleF(rect.Left, rect.Bottom - 1f, rect.Width, 0f), 
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.VerticalCenter, 
						color,
						Color.Empty, 
						0, 
						ChartDashStyle.NotSet, 
						PenAlignment.Inset);
				}
				else
				{
					// Draw vertical line separator
					chartGraph.FillRectangleAbs( 
						new RectangleF(rect.Right - 1f, rect.Top, 0f, rect.Height), 
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.HorizontalCenter, 
						color,
						Color.Empty, 
						0, 
						ChartDashStyle.NotSet, 
						PenAlignment.Inset);
				}
			}
			else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
			{
				if(horizontal)
				{
					// Draw horizontal line separator
					chartGraph.FillRectangleAbs( 
						new RectangleF(rect.Left, rect.Bottom - 2f, rect.Width, 1f), 
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.VerticalCenter, 
						color,
						Color.Empty, 
						0, 
						ChartDashStyle.NotSet, 
						PenAlignment.Inset);
				}
				else
				{
					// Draw vertical line separator
					chartGraph.FillRectangleAbs( 
						new RectangleF(rect.Right - 2f, rect.Top, 1f, rect.Height), 
						Color.Transparent, 
						ChartHatchStyle.None,
						string.Empty,
						ChartImageWrapMode.Tile, 
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.HorizontalCenter, 
						color,
						Color.Empty, 
						0, 
						ChartDashStyle.NotSet, 
						PenAlignment.Inset);
				}
			}
 
			// Restore smoothing
			chartGraph.SmoothingMode = oldSmoothingMode;
		}
 
		#endregion // Legent Title Helper methods
 
		#region Helper methods
 
		/// <summary>
		/// Get visible legend border size.
		/// </summary>
		/// <returns>Visible legend border size.</returns>
		private int GetBorderSize()
		{
			if(this.BorderWidth > 0 &&
				this.BorderDashStyle != ChartDashStyle.NotSet &&
				!this.BorderColor.IsEmpty &&
				this.BorderColor != Color.Transparent)
			{
				return this.BorderWidth;
			}
			return 0;
		}
 
		/// <summary>
		/// Helper method which returns current legend table style.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <returns>Legend table style.</returns>
		private LegendTableStyle GetLegendTableStyle(ChartGraphics chartGraph)
		{
			LegendTableStyle style = this.TableStyle;
			if(this.TableStyle == LegendTableStyle.Auto)
			{
				if(this.Position.Auto)
				{
					// If legend is automatically positioned, use docking
					// do determine preffered table style
					if(this.Docking == Docking.Left ||
						this.Docking == Docking.Right)
					{
						return LegendTableStyle.Tall;
					}
					else
					{
						return LegendTableStyle.Wide;
					}
				}
				else
				{
					// If legend is custom positioned, use legend width and heiht
					// to determine the best table layout.
					SizeF legendPixelSize = chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()).Size;
					if(legendPixelSize.Width < legendPixelSize.Height)
					{
						return LegendTableStyle.Tall;
					}
					else
					{
						return LegendTableStyle.Wide;
					}
				}
			}
			
			return style;
		}
 
 
 
		/// <summary>
		/// Helper method that checks if legend is enabled.
		/// </summary>
		/// <returns>True if legend is enabled.</returns>
		internal bool IsEnabled()
		{
			if(this.Enabled)
			{
 
				// Check if legend is docked to the chart area
				if(this.DockedToChartArea.Length > 0 &&
					this.Common != null &&
					this.Common.ChartPicture != null)
				{
					if(this.Common.ChartPicture.ChartAreas.IndexOf(this.DockedToChartArea) >= 0)
					{
						// Do not show legend when it is docked to invisible chart area
						ChartArea area = this.Common.ChartPicture.ChartAreas[this.DockedToChartArea];
						if(!area.Visible)
						{
							return false;
						}
					}
				}
					
 
				return true;
			}
			return false;
		}
 
		/// <summary>
		/// Invalidate chart legend when one of the properties is changed
		/// </summary>
		/// <param name="invalidateLegendOnly">Indicates that only legend area should be invalidated.</param>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")]
		internal void Invalidate(bool invalidateLegendOnly)
		{
#if Microsoft_CONTROL

			if(Chart != null && !Chart.disableInvalidates)
			{
				if(invalidateLegendOnly)
				{
					// Calculate the position of the legend
					Rectangle	invalRect = Chart.ClientRectangle;
					if(this.Position.Width != 0 && this.Position.Height != 0 )
					{
						// Convert relative coordinates to absolute coordinates
						invalRect.X = (int)(this.Position.X * (this.Common.ChartPicture.Width - 1) / 100F); 
						invalRect.Y = (int)(this.Position.Y * (this.Common.ChartPicture.Height - 1) / 100F); 
						invalRect.Width = (int)(this.Position.Width * (this.Common.ChartPicture.Width - 1) / 100F); 
						invalRect.Height = (int)(this.Position.Height * (this.Common.ChartPicture.Height - 1) / 100F); 
 
						// Inflate rectangle size using border size and shadow size
                        invalRect.Inflate(this.BorderWidth + this.ShadowOffset + 1, this.BorderWidth + this.ShadowOffset + 1);
					}
 
					// Invalidate legend rectangle only
					Chart.dirtyFlag = true;
					Chart.Invalidate(invalRect);
				}
				else
				{
					Invalidate();
				}
			}
#endif
		}
 
		#endregion
 
        #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 override void Dispose(bool disposing)
        {
            if (disposing)
            {
                //Free managed resources
                if (_fontCache != null)
                {
                    _fontCache.Dispose();
                    _fontCache = null;
                }
                if (legendItems != null)
                {
                    legendItems.Dispose();
                    legendItems = null;
                }
                if (_cellColumns != null)
                {
                    _cellColumns.Dispose();
                    _cellColumns = null;
                }
                if (_customLegends != null)
                {
                    _customLegends.Dispose();
                    _customLegends = null;
                }
                if (_position != null)
                {
                    _position.Dispose();
                    _position = null;
                }
            }
        }
 
 
        #endregion
    }
 
	/// <summary>
    /// The LegendCollection class is a strongly typed collection of legends.
	/// </summary>
	[
		SRDescription("DescriptionAttributeLegendCollection_LegendCollection"),
	]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class LegendCollection : ChartNamedElementCollection<Legend>
    {
        #region Constructors
		/// <summary>
        /// LegendCollection constructor.
		/// </summary>
        /// <param name="chartPicture">Chart picture object.</param>
        internal LegendCollection(ChartPicture chartPicture)
            : base(chartPicture)
        {
        }
 
		#endregion
 
        #region Properties
        /// <summary>
        /// Gets the default legend name.
        /// </summary>
        internal string DefaultNameReference
        {
            get { return this.Count > 0 ? this[0].Name : String.Empty; }
        }
        #endregion
 
		#region Methods
 
        /// <summary>
        /// Creates a new Legend with the specified name and adds it to the collection.
        /// </summary>
        /// <param name="name">The new chart area name.</param>
        /// <returns>New legend</returns>
        public Legend Add(string name)
        {
            Legend legend = new Legend(name);
            this.Add(legend);
            return legend;
        }
 
        /// <summary>
		/// Recalculates legend position in the collection.
		/// </summary>
		/// <param name="chartGraph">Chart graphics used.</param>
		/// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
		/// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
		internal void CalcLegendPosition(
			ChartGraphics chartGraph, 
			ref RectangleF chartAreasRectangle, 
			float elementSpacing)
		{
			// Loop through all legends
			foreach(Legend legend in this)
			{
				// Calculate position of the legends docked to the chart picture
				if(legend.IsEnabled() &&
                    legend.DockedToChartArea == Constants.NotSetValue && 
					legend.Position.Auto)
				{
					legend.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
				}
			}
		}
 
		/// <summary>
		/// Recalculates legend position in the collection for legends docked outside of chart area.
		/// </summary>
		/// <param name="chartGraph">Chart graphics used.</param>
		/// <param name="area">Area the legend is docked to.</param>
		/// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
		/// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
		internal void CalcOutsideLegendPosition(
			ChartGraphics chartGraph, 
			ChartArea area,
			ref RectangleF chartAreasRectangle, 
			float elementSpacing)
		{
			if(Common != null && Common.ChartPicture != null)
			{
				// Get elemets spacing
				float areaSpacing = Math.Min((chartAreasRectangle.Height/100F) * elementSpacing, (chartAreasRectangle.Width/100F) * elementSpacing);
 
				// Loop through all legends
				foreach(Legend legend in this)
				{
					// Check if all chart area names are valid
                    if (legend.DockedToChartArea != Constants.NotSetValue && this.Chart.ChartAreas.IndexOf(legend.DockedToChartArea)<0)
                    {
                        throw (new ArgumentException(SR.ExceptionLegendDockedChartAreaIsMissing((string)legend.DockedToChartArea)));
                    }
 
					// Process only legends docked to specified area
					if(legend.IsEnabled() && 
						legend.IsDockedInsideChartArea == false &&
						legend.DockedToChartArea == area.Name && 
						legend.Position.Auto)
					{
						// Calculate legend position
						legend.CalcLegendPosition(chartGraph, 
							ref chartAreasRectangle,
							areaSpacing);
 
						// Adjust legend position
						RectangleF legendPosition = legend.Position.ToRectangleF();
						if(legend.Docking == Docking.Top)
						{
							legendPosition.Y -= areaSpacing;
							if(!area.Position.Auto)
							{
								legendPosition.Y -= legendPosition.Height;
							}
						}
						else if(legend.Docking == Docking.Bottom)
						{
							legendPosition.Y += areaSpacing;
							if(!area.Position.Auto)
							{
								legendPosition.Y = area.Position.Bottom + areaSpacing;
							}
						}
						if(legend.Docking == Docking.Left)
						{
							legendPosition.X -= areaSpacing;
							if(!area.Position.Auto)
							{
								legendPosition.X -= legendPosition.Width;
							}
						}
						if(legend.Docking == Docking.Right)
						{
							legendPosition.X += areaSpacing;
							if(!area.Position.Auto)
							{
								legendPosition.X = area.Position.Right + areaSpacing;
							}
						}
 
						legend.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
					}
				}
			}
		}
 
		/// <summary>
		/// Recalculates legend position inside chart area in the collection.
		/// </summary>
		/// <param name="chartGraph">Chart graphics used.</param>
		/// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
		internal void CalcInsideLegendPosition(
			ChartGraphics chartGraph, 
			float elementSpacing)
		{
			if(Common != null && Common.ChartPicture != null)
			{
				// Check if all chart area names are valid
				foreach(Legend legend in this)
				{
                    if (legend.DockedToChartArea != Constants.NotSetValue)
					{
						try
						{
							ChartArea area = Common.ChartPicture.ChartAreas[legend.DockedToChartArea];
						}
						catch
						{
							throw(new ArgumentException( SR.ExceptionLegendDockedChartAreaIsMissing( (string)legend.DockedToChartArea ) ) );
						}
					}
				}
 
				// Loop through all chart areas
                foreach (ChartArea area in Common.ChartPicture.ChartAreas)
				{
 
					// Check if chart area is visible
					if(area.Visible)
 
					{
						// Get area position
						RectangleF legendPlottingRectangle = area.PlotAreaPosition.ToRectangleF();
 
						// Get elemets spacing
						float areaSpacing = Math.Min((legendPlottingRectangle.Height/100F) * elementSpacing, (legendPlottingRectangle.Width/100F) * elementSpacing);
 
						// Loop through all legends
						foreach(Legend legend in this)
						{
							if(legend.IsEnabled() && 
								legend.IsDockedInsideChartArea == true &&
								legend.DockedToChartArea == area.Name && 
								legend.Position.Auto)
							{
								// Calculate legend position
								legend.CalcLegendPosition(chartGraph, 
									ref legendPlottingRectangle,
									areaSpacing);
							}
						}
					}
				}
			}
		}
 
		#endregion
 
        #region Event handlers
        internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
        {
            //If all the chart areas are removed and then the first one is added we don't want to dock the legends
            if (e.OldElement == null)
                return;
 
            foreach (Legend legend in this)
                if (legend.DockedToChartArea == e.OldName)
                    legend.DockedToChartArea = e.NewName;
        }
        #endregion
 
    }
 
	/// <summary>
    /// The LegendItemsCollection class is a strongly typed collection of legend items.
	/// </summary>
	[
		SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
	]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class LegendItemsCollection : ChartElementCollection<LegendItem>
	{
        #region Constructors
 
        /// <summary>
        /// LegendItemsCollection constructor
		/// </summary>
        internal LegendItemsCollection(Legend legend)
            : base(legend)
        {
        }
 
		#endregion
 
		#region Methods
 
		/// <summary>
		/// Adds a legend item into the collection.
		/// </summary>
		/// <param name="color">Legend item color.</param>
		/// <param name="text">Legend item text.</param>
		/// <returns>Index of newly added item.</returns>
		public int Add(Color color, string text)
		{
			LegendItem	item = new LegendItem(text, color, "");
			Add(item);
            return Count - 1;
		}
 
		/// <summary>
		/// Insert a legend item into the collection.
		/// </summary>
		/// <param name="index">Index to insert at.</param>
		/// <param name="color">Legend item color.</param>
		/// <param name="text">Legend item text.</param>
		/// <returns>Index of newly added item.</returns>
		public void Insert(int index, Color color, string text)
		{
			LegendItem	item = new LegendItem(text, color, "");
			this.Insert(index, item);
		}
 
		/// <summary>
		/// Adds a legend item into the collection.
		/// </summary>
		/// <param name="image">Legend item image.</param>
		/// <param name="text">Legend item text.</param>
		/// <returns>Index of newly added item.</returns>
		public int Add(string image, string text)
		{
			LegendItem	item = new LegendItem(text, Color.Empty, image);
            Add(item);
			return Count-1;
		}
 
		/// <summary>
		/// Insert one legend item into the collection.
		/// </summary>
		/// <param name="index">Index to insert at.</param>
		/// <param name="image">Legend item image.</param>
		/// <param name="text">Legend item text.</param>
		/// <returns>Index of newly added item.</returns>
		public void Insert(int index, string image, string text)
		{
			LegendItem	item = new LegendItem(text, Color.Empty, image);
			this.Insert(index, item);
		}
 
		/// <summary>
		/// Reverses the order of items in the collection.
		/// </summary>
		public void Reverse()
		{
            List<LegendItem> list = this.Items as List<LegendItem>;
            list.Reverse();
			Invalidate();
		}
 
		#endregion
 
	}
 
 
	/// <summary>
    /// The LegendItem class represents a single item (row) in the legend.
    /// It contains properties which describe visual appearance and
    /// content of the legend item.
	/// </summary>
	[
	SRDescription("DescriptionAttributeLegendItem_LegendItem"),
	DefaultProperty("Name"),
	]
#if Microsoft_CONTROL
	public class LegendItem : ChartNamedElement
#else
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class LegendItem : ChartNamedElement, IChartMapArea
#endif
    {
        #region Fields
 
        // Private data members, which store properties values
		private Color					_color = Color.Empty;
		private string					_image = "";
		private string					_seriesName = "";
		private int						_seriesPointIndex = -1;
 
		// Chart image map properties 
		private	string					_toolTip = "";
        
#if !Microsoft_CONTROL
		private	string					_url = "";
		private	string					_attributes = "";
        private string                  _postbackValue = String.Empty;
#endif
 
        // Additional appearance properties
		internal LegendImageStyle		style = LegendImageStyle.Rectangle;
		internal GradientStyle			backGradientStyle = GradientStyle.None;
		internal Color					backSecondaryColor = Color.Empty;
		internal Color					backImageTransparentColor = Color.Empty;
		internal Color					borderColor = Color.Black;
		internal int					borderWidth = 1;
		internal ChartDashStyle			borderDashStyle = ChartDashStyle.Solid;
		internal ChartHatchStyle		backHatchStyle = ChartHatchStyle.None;
		internal int					shadowOffset = 0;
		internal Color					shadowColor = Color.FromArgb(128, 0, 0, 0);
		internal ChartImageWrapMode		backImageWrapMode = ChartImageWrapMode.Tile;
		internal ChartImageAlignmentStyle		backImageAlign = ChartImageAlignmentStyle.TopLeft;
 
		// Marker properties
		internal MarkerStyle			markerStyle = MarkerStyle.None;
		internal int					markerSize = 5;
		internal string					markerImage = "";
		internal Color					markerImageTransparentColor = Color.Empty;
		internal Color					markerColor = Color.Empty;
		internal Color					markerBorderColor = Color.Empty;
 
		// True if legend item is enabled.
		private bool		_enabled = true;
 
		// Series marker border width
		private int			_markerBorderWidth = 1;
 
		// Collection of legend item cells
		private	LegendCellCollection	_cells = null;
 
		// Legend item visual separator
		private LegendSeparatorStyle	_separatorType = LegendSeparatorStyle.None;
 
		// Legend item visual separator color
		private Color		_separatorColor = Color.Black;
 
		// Indicates that temporary cells where added and thet have to be removed
		internal bool		clearTempCells = false;
 
		#endregion
 
		#region Constructors
 
		/// <summary>
        /// LegendItem constructor
		/// </summary>
		public LegendItem()
		{
 
			// Create collection of legend item cells
			this._cells = new LegendCellCollection(this);
#if !Microsoft_CONTROL
            this.PostBackValue = String.Empty;
#endif //!WIN_CONTROL
		}
 
		/// <summary>
        /// LegendItem constructor
		/// </summary>
		/// <param name="name">Item name.</param>
		/// <param name="color">Item color.</param>
		/// <param name="image">Item image.</param>
		public LegendItem(string name, Color color, string image) : base (name)
		{
			this._color = color;
			this._image = image;
 
			// Create collection of legend item cells
			this._cells = new LegendCellCollection(this);
#if !Microsoft_CONTROL
            this.PostBackValue = String.Empty;
#endif //!WIN_CONTROL
		}
 
		#endregion
 
		#region	Legend item properties
 
        /// <summary>
        /// Gets the Legend object which the item belongs to.
        /// </summary>
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
            SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        ]
        public Legend Legend
        {
            get 
            {
                if (Parent != null)
                    return Parent.Parent as Legend;
                else
                    return null;
            }
        }
 
		/// <summary>
		/// Gets or sets the name of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		SRDescription("DescriptionAttributeLegendItem_Name"),
		NotifyParentPropertyAttribute(true),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		ParenthesizePropertyNameAttribute(true)
		]
		public override string Name
		{
			get
			{
				return base.Name;
			}
			set
			{
				base.Name = value;
			}
		}
 
		/// <summary>
		/// Gets or sets the color of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		SRDescription("DescriptionAttributeLegendItem_Color"),
		DefaultValue(typeof(Color), ""),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public	Color Color
		{
			get
			{
				return _color;
			}
			set
			{
				_color = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets a string value that represents a URL to an image file, which will be used for the legend item's symbol.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		SRDescription("DescriptionAttributeLegendItem_Image"),
		DefaultValue(""),
        Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		NotifyParentPropertyAttribute(true)
		]
		public	string Image
		{
			get
			{
				return _image;
			}
			set
			{
				_image = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the picture style of the legend item image.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(LegendImageStyle), "Rectangle"),
		SRDescription("DescriptionAttributeLegendItem_Style"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		ParenthesizePropertyNameAttribute(true)
		]
		public LegendImageStyle ImageStyle
		{
			get
			{
				return style;
			}
			set
			{
				style = value;
				this.Invalidate(true);
			}
		}
 
 
		/// <summary>
		/// Gets or sets the border color of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeBorderColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BorderColor
		{
			get
			{
				return borderColor;
			}
			set
			{
				borderColor = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets the background hatch style of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartHatchStyle.None),
        SRDescription("DescriptionAttributeBackHatchStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
        Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
		]
		public ChartHatchStyle BackHatchStyle
		{
			get
			{
				return backHatchStyle;
			}
			set
			{
				backHatchStyle = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeImageTransparentColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BackImageTransparentColor
		{
			get
			{
				return backImageTransparentColor;
			}
			set
			{
				backImageTransparentColor = value;
				this.Invalidate(true);
			}
		}
 
        /// <summary>
        /// Gets or sets background gradient style of the legend item.
        /// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(GradientStyle.None),
        SRDescription("DescriptionAttributeBackGradientStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
        Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
		]
		public GradientStyle BackGradientStyle
		{
			get
			{
				return backGradientStyle;
			}
			set
			{
				backGradientStyle = value;
				this.Invalidate(true);
			}
		}
 
        /// <summary>
        /// Gets or sets the secondary background color.
        /// <seealso cref="Color"/>
        /// <seealso cref="BackHatchStyle"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used for the secondary color of background with 
        /// hatching or gradient fill.
        /// </value>
        /// <remarks>
        /// This color is used with <see cref="Color"/> when <see cref="BackHatchStyle"/> or
        /// <see cref="BackGradientStyle"/> are used.
        /// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeBackSecondaryColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color BackSecondaryColor
		{
			get
			{
				return backSecondaryColor;
			}
			set
			{
				if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
				{
                    throw (new ArgumentException(SR.ExceptionBackSecondaryColorIsTransparent));
				}
 
				backSecondaryColor = value;
 
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the border width of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(1),
        SRDescription("DescriptionAttributeBorderWidth"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public int BorderWidth
		{
			get
			{
				return borderWidth;
			}
			set
			{
				if(value < 0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsZero));
				}
				borderWidth = value;
				this.Invalidate(false);
			}
		}
 
 
 
        /// <summary>
        /// Gets or sets a flag which indicates whether the Legend item is enabled.
        /// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(true),
		SRDescription("DescriptionAttributeLegendItem_Enabled"),
		ParenthesizePropertyNameAttribute(true),
		]
		public bool Enabled
		{
			get
			{
				return this._enabled;
			}
			set
			{
				this._enabled = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
		/// Gets or sets the marker border width of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		DefaultValue(1),
        SRDescription("DescriptionAttributeMarkerBorderWidth"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public int MarkerBorderWidth
		{
			get
			{
				return this._markerBorderWidth;
			}
			set
			{
				if(value < 0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMarkerBorderWidthIsNegative));
				}
				this._markerBorderWidth = value;
				this.Invalidate(false);
			}
		}
 
 
 
        /// <summary>
        /// Gets or sets the legend item border style.
        /// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(ChartDashStyle.Solid),
        SRDescription("DescriptionAttributeBorderDashStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public ChartDashStyle BorderDashStyle
		{
			get
			{
				return borderDashStyle;
			}
			set
			{
				borderDashStyle = value;
				this.Invalidate(true);
			}
		}
 
        /// <summary>
        /// Gets or sets the offset between the legend item and its shadow.
        /// <seealso cref="ShadowColor"/>
        /// </summary>
        /// <value>
        /// An integer value that represents the offset between the legend item and its shadow.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
        SRDescription("DescriptionAttributeShadowOffset"),
#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
		DefaultValue(0)
		]
		public int ShadowOffset
		{
			get
			{
				return shadowOffset;
			}
			set
			{
				shadowOffset = value;
				this.Invalidate(false);
			}
		}
 
        /// <summary>
        /// Gets or sets the color of a legend item's shadow.
        /// <seealso cref="ShadowOffset"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used to draw a legend item's shadow.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		Bindable(true),
		DefaultValue(typeof(Color), "128,0,0,0"),
        SRDescription("DescriptionAttributeShadowColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public Color ShadowColor
		{
			get
			{
				return shadowColor;
			}
			set
			{
				shadowColor = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
		/// Gets or sets the marker style of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(MarkerStyle.None),
		SRDescription("DescriptionAttributeLegendItem_MarkerStyle"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
        Editor(Editors.MarkerStyleEditor.Editor, Editors.MarkerStyleEditor.Base),
		RefreshProperties(RefreshProperties.All)
		]
		public MarkerStyle MarkerStyle
		{
			get
			{
				return markerStyle;
			}
			set
			{
				markerStyle = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets the marker size of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(5),
		SRDescription("DescriptionAttributeLegendItem_MarkerSize"),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		RefreshProperties(RefreshProperties.All)
		]
		public int MarkerSize
		{
			get
			{
				return markerSize;
			}
			set
			{
				markerSize = value;
				this.Invalidate(false);
			}
		}
 
		/// <summary>
        /// Gets or sets the marker image of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(""),
        SRDescription("DescriptionAttributeMarkerImage"),
        Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		RefreshProperties(RefreshProperties.All)
		]
		public string MarkerImage
		{
			get
			{
				return markerImage;
			}
			set
			{
				markerImage = value;
				this.Invalidate(true);
			}
		}
 
		/// <summary>
        /// Gets or sets a color which will be replaced with a transparent color while drawing the marker image.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeImageTransparentColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		RefreshProperties(RefreshProperties.All)
		]
		public Color MarkerImageTransparentColor
		{
			get
			{
				return markerImageTransparentColor;
			}
			set
			{
				markerImageTransparentColor = value;
				this.Invalidate(true);
			}
		}
		
		/// <summary>
        /// Gets or sets the marker color of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
		SRDescription("DescriptionAttributeLegendItem_MarkerColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		RefreshProperties(RefreshProperties.All)
		]
		public Color MarkerColor
		{
			get
			{
				return markerColor;
			}
			set
			{
				markerColor = value;
				this.Invalidate(true);
			}
		}
		
		/// <summary>
        /// Gets or sets the marker border color of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeMarker"),
		Bindable(true),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeMarkerBorderColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
		#endif
		RefreshProperties(RefreshProperties.All)
		]
		public Color MarkerBorderColor
		{
			get
			{
				return markerBorderColor;
			}
			set
			{
				markerBorderColor = value;
				this.Invalidate(true);
			}
		}
 
 
		/// <summary>
        /// Gets or sets the series name of the legend item..
		/// </summary>
		[
		Browsable(false),
        DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
        SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        SRDescription("DescriptionAttributeLegendItem_SeriesName"),
		DefaultValue("")
		]
		public	string SeriesName
		{
			get
			{
				return _seriesName;
			}
			set
			{
				_seriesName = value;
			}
		}
 
		/// <summary>
        /// Gets or sets the index of the legend item's associated DataPoint object.
		/// </summary>
		[
		Browsable(false),
        DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
        SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        SRDescription("DescriptionAttributeLegendItem_SeriesPointIndex"),
		DefaultValue(-1)
		]
		public	int SeriesPointIndex
		{
			get
			{
				return _seriesPointIndex;
			}
			set
			{
				_seriesPointIndex = value;
			}
		}
 
 
 
 
		/// <summary>
		/// Gets or sets the separator style of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(LegendSeparatorStyle), "None"),
		SRDescription("DescriptionAttributeLegendItem_Separator"),
		]
		public LegendSeparatorStyle SeparatorType
		{
			get
			{
				return this._separatorType;
			}
			set
			{
				if(value != this._separatorType)
				{
					this._separatorType = value;
					this.Invalidate(false);
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the separator color of the legend item.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), "Black"),
		SRDescription("DescriptionAttributeLegendItem_SeparatorColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
		]
		public Color SeparatorColor
		{
			get
			{
				return this._separatorColor;
			}
			set
			{
				if(value != this._separatorColor)
				{
					this._separatorColor = value;
					this.Invalidate(false);
				}
			}
		}
 
 
		/// <summary>
        /// The LegendCellCollection class is a collection of legend item cells.
		/// </summary>
		[
		SRCategory("CategoryAttributeAppearance"),
		SRDescription("DescriptionAttributeLegendItem_Cells"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
        Editor(Editors.LegendCellCollectionEditor.Editor, Editors.LegendCellCollectionEditor.Base),
		]
		public LegendCellCollection Cells
		{
			get
			{
				return this._cells;
			}
		}
 
		#endregion
 
		#region	IMapAreaAttributesutes Properties implementation
 
		/// <summary>
		/// Tooltip of the area.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
        Bindable(true),
        SRDescription("DescriptionAttributeToolTip"),
		DefaultValue(""),
		#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
		#endif
		]
		public string ToolTip
		{
			set
			{
				_toolTip = value;
#if Microsoft_CONTROL
				if(Chart != null && Chart.selection != null)
				{
					Chart.selection.enabledChecked = false;
				}
#endif
 
			}
			get
			{
				return _toolTip;
			}
		}
 
#if !Microsoft_CONTROL
		/// <summary>
		/// URL target of the area.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
		Bindable(true),
		SRDescription("DescriptionAttributeUrl"),
		DefaultValue(""),
#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
        Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
#endif
		]
		public string Url
		{
			set
			{
				_url = value;
			}
			get
			{
				return _url;
			}
		}
 
#endif
#if !Microsoft_CONTROL
 
		/// <summary>
		/// Other attributes of the area.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
		Bindable(true),
		SRDescription("DescriptionAttributeMapAreaAttributes"),
		DefaultValue(""),
		PersistenceMode(PersistenceMode.Attribute)
		]
		public string MapAreaAttributes
		{
			set
			{
				_attributes = value;
			}
			get
			{
				return _attributes;
			}
		}
        /// <summary>
        /// Gets or sets the postback value which can be processed on a click event.
        /// </summary>
        /// <value>The value which is passed to a click event as an argument.</value>
        [DefaultValue("")]
        [SRCategory(SR.Keys.CategoryAttributeMapArea)]
        [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
        public string PostBackValue 
        {
            get
            {
                return this._postbackValue;
            }
            set
            {
                this._postbackValue = value;
            } 
        }
 
 
#endif //!Microsoft_CONTROL
        #endregion
 
        #region Helper methods
 
        /// <summary>
		/// Helper method adds default legend item cells based on the columns
		/// specified. If columns collection is empty we assume the presence of
		/// two columns: series marker and legend item text.
		/// </summary>
		/// <param name="legend">Legend this item belongs to.</param>
		internal void AddAutomaticCells(Legend legend)
		{
			// Check if cells defined
			if(this.Cells.Count == 0)
			{
				// Check if legend item was generated for the series
				if(this.SeriesName.Length > 0)
				{
					// If legend do not have any columns set add a series marker
					// and legend text cells
					if(legend.CellColumns.Count == 0)
					{
                        // VSTS 96787 - Text Direction (RTL/LTR)	
                        if (legend.Common != null && legend.Common.ChartPicture.RightToLeft == RightToLeft.Yes)
                        {
                            this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
                            this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
                        }
                        else
                        {
                            this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
                            this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
                        }
					}
					else
					{
						// Add cell for each of the columns
						foreach(LegendCellColumn legendColumn in legend.CellColumns)
						{
							this.Cells.Add(legendColumn.CreateNewCell());
						}
					}
				}
				else
				{
					// Add Marker plus text for everything else
					this.clearTempCells = true;
					this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
					this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
				}
			}
		}
 
 
		/// <summary>
		/// Sets legend item properties from the series
		/// </summary>
		/// <param name="series">Series object.</param>
		/// <param name="common">Common elements object.</param>
		internal void SetAttributes(CommonElements common, Series series)
		{
			// Get legend item picture style
			IChartType chartType = common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
			style = chartType.GetLegendImageStyle(series);
 
			// Set series name
			_seriesName = series.Name;
 
			// Get shadow properties
			shadowOffset = series.ShadowOffset;
			shadowColor = series.ShadowColor;
 
			// Check if series is drawn in 3D chart area
			bool area3D = common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
 
			// Get other properties
			SetAttributes((DataPointCustomProperties) series, area3D);
		}
 
		/// <summary>
		/// Sets legend item properties from the DataPointCustomProperties object.
		/// </summary>
        /// <param name="properties">DataPointCustomProperties object.</param>
		/// <param name="area3D">Element belongs to the 3D area.</param>
        internal void SetAttributes(DataPointCustomProperties properties, bool area3D)
		{
			borderColor = properties.BorderColor;
			borderWidth = properties.BorderWidth;
			borderDashStyle = properties.BorderDashStyle;
			markerStyle = properties.MarkerStyle;
			markerSize = properties.MarkerSize;
			markerImage = properties.MarkerImage;
			markerImageTransparentColor = properties.MarkerImageTransparentColor;
			markerColor = properties.MarkerColor;
			markerBorderColor = properties.MarkerBorderColor;
 
 
			this._markerBorderWidth = properties.MarkerBorderWidth;
            
            float dpi = 96;
 
            if(Common != null)
                dpi = Common.graph.Graphics.DpiX;
            
            int maxBorderWidth = (int)Math.Round((2 * dpi) / 96);
 
            if (this._markerBorderWidth > maxBorderWidth)
			{
                this._markerBorderWidth = maxBorderWidth;
			}
 
			if(properties.MarkerBorderWidth <= 0)
			{
				markerBorderColor = Color.Transparent;
			}
 
			// Improve readability of the line series marker by using at least 2 pixel wide lines
			if(this.style == LegendImageStyle.Line &&
                borderWidth <= (int)Math.Round(dpi / 96) )
			{
                borderWidth = maxBorderWidth;
			}
 
			if(!area3D)
			{
				backGradientStyle = properties.BackGradientStyle;
				backSecondaryColor = properties.BackSecondaryColor;
				backImageTransparentColor = properties.BackImageTransparentColor;
				backImageWrapMode = properties.BackImageWrapMode;
				backImageAlign = properties.BackImageAlignment;
				backHatchStyle = properties.BackHatchStyle;
			}
		}
 
		/// <summary>
		/// Invalidate chart (or just legend )when collection is changed
		/// </summary>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")]
		private void Invalidate(bool invalidateLegendOnly)
		{
#if Microsoft_CONTROL
			if(Legend != null)
			{
				// Invalidate control
				Legend.Invalidate(invalidateLegendOnly);
			}
#endif
		}
 
		#endregion
 
        #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 override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_cells != null)
                {
                    _cells.Dispose();
                    _cells = null;
                }
            }
            base.Dispose(disposing);
        }
 
 
        #endregion
 
	}
}