//============================================================================
//ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C#
//Copyright ?2004  John Champion
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//=============================================================================
using System;
using System.Drawing;
using System.Collections;
using System.Runtime.Serialization;
using System.Security.Permissions;
#if ( !DOTNET1 )	// Is this a .Net 2 compilation?
using System.Collections.Generic;
#endif
namespace DrawGraph
{
	
	/// 
	/// This class contains the data and methods for an individual curve within
	/// a graph pane.  It carries the settings for the curve including the
	/// key and item names, colors, symbols and sizes, linetypes, etc.
	/// 
	/// 
	///  John Champion
	/// modified by Jerry Vos 
	///  $Revision: 3.40 $ $Date: 2007/04/16 00:03:01 $ 
	[Serializable]
	abstract public class CurveItem : ISerializable, ICloneable
	{
	
	#region Fields
		/// 
		/// protected field that stores a  instance for this
		/// , which is used for the 
		/// label.  Use the public
		/// property  to access this value.
		/// 
		internal Label _label;
		/// 
		/// protected field that stores the boolean value that determines whether this
		///  is on the bottom X axis or the top X axis (X2).
		/// Use the public property  to access this value.
		/// 
		protected bool _isX2Axis;
		/// 
		/// protected field that stores the boolean value that determines whether this
		///  is on the left Y axis or the right Y axis (Y2).
		/// Use the public property  to access this value.
		/// 
		protected bool _isY2Axis;
		/// 
		/// protected field that stores the index number of the Y Axis to which this
		///  belongs.  Use the public property 
		/// to access this value.
		/// 
		protected int		_yAxisIndex;
		/// 
		/// protected field that stores the boolean value that determines whether this
		///  is visible on the graph.
		/// Use the public property  to access this value.
		/// Note that this value turns the curve display on or off, but it does not
		/// affect the display of the legend entry.  To hide the legend entry, you
		/// have to set  to false.
		/// 
		protected bool		_isVisible;
		// Revision: JCarpenter 10/06
		/// 
		/// Protected field that stores the boolean value that determines whether this
		///  is selected on the graph.
		/// Use the public property  to access this value.
		/// Note that this value changes the curve display color, but it does not
		/// affect the display of the legend entry.  To hide the legend entry, you
		/// have to set  to false.
		/// 
		protected bool _isSelected;
		// Revision: JCarpenter 10/06
		/// 
		/// Protected field that stores the boolean value that determines whether this
		///  can be selected in the graph.
		/// 
		protected bool _isSelectable;
		/// 
		/// protected field that stores a boolean value which allows you to override the normal
		/// ordinal axis behavior.  Use the public property  to
		/// access this value.
		/// 
		protected bool		_isOverrideOrdinal;
		
		/// 
		/// The  of value sets that
		/// represent this .
		/// The size of this list determines the number of points that are
		/// plotted.  Note that values defined as
		/// System.Double.MaxValue are considered "missing" values
		/// (see ),
		/// and are not plotted.  The curve will have a break at these points
		/// to indicate the values are missing.
		/// 
		protected IPointList _points;
		/// 
		/// A tag object for use by the user.  This can be used to store additional
		/// information associated with the .  ZedGraph does
		/// not use this value for any purpose.
		/// 
		/// 
		/// Note that, if you are going to Serialize ZedGraph data, then any type
		/// that you store in  must be a serializable type (or
		/// it will cause an exception).
		/// 
		public object Tag;
		/// 
		/// Protected field that stores the hyperlink information for this object.
		/// 
		internal Link _link;
	#endregion
	
	#region Constructors
		/// 
		///  constructor the pre-specifies the curve label, the
		/// x and y data values as a , the curve
		/// type (Bar or Line/Symbol), the , and the
		/// . Other properties of the curve are
		/// defaulted to the values in the  class.
		/// 
		/// A string label (legend entry) for this curve
		/// An array of double precision values that define
		/// the independent (X axis) values for this curve
		/// An array of double precision values that define
		/// the dependent (Y axis) values for this curve
		public CurveItem( string label, double[] x, double[] y ) :
				this( label, new PointPairList( x, y ) )
		{
		}
/*	
		public CurveItem( string _label, int  y ) : this(  _label, new IPointList( ) )
		{
		}
*/
		/// 
		///  constructor the pre-specifies the curve label, the
		/// x and y data values as a , the curve
		/// type (Bar or Line/Symbol), the , and the
		/// . Other properties of the curve are
		/// defaulted to the values in the  class.
		/// 
		/// A string label (legend entry) for this curve
		/// A  of double precision value pairs that define
		/// the X and Y values for this curve
		public CurveItem( string label, IPointList points )
		{
			Init( label );
			if ( points == null )
				_points = new PointPairList();
			else
				//this.points = (IPointList) _points.Clone();
				_points = points;
		}
		
		/// 
		/// Internal initialization routine thats sets some initial values to defaults.
		/// 
		/// A string label (legend entry) for this curve
		private void Init( string label )
		{
			_label = new Label( label, null );
			_isY2Axis = false;
			_isX2Axis = false;
			_isVisible = true;
			_isOverrideOrdinal = false;
			this.Tag = null;
			_yAxisIndex = 0;
			_link = new Link();
		}
			
		/// 
		///  constructor that specifies the label of the CurveItem.
		/// This is the same as CurveItem(label, null, null).
		/// 
		/// 
		/// A string label (legend entry) for this curve
		public CurveItem( string label ): this( label, null )
		{
		}
		 /// 
		 /// 
		 /// 
		public CurveItem(  )
		{
			Init( null );
		}
		/// 
		/// The Copy Constructor
		/// 
		/// The CurveItem object from which to copy
		public CurveItem( CurveItem rhs )
		{
			_label = rhs._label.Clone();
			_isY2Axis = rhs.IsY2Axis;
			_isX2Axis = rhs.IsX2Axis;
			_isVisible = rhs.IsVisible;
			_isOverrideOrdinal = rhs._isOverrideOrdinal;
			_yAxisIndex = rhs._yAxisIndex;
			if ( rhs.Tag is ICloneable )
				this.Tag = ((ICloneable) rhs.Tag).Clone();
			else
				this.Tag = rhs.Tag;
			
			_points = (IPointList) rhs.Points.Clone();
			_link = rhs._link.Clone();
		}
		/// 
		/// Implement the  interface in a typesafe manner by just
		/// calling the typed version of Clone.
		/// 
		/// 
		/// Note that this method must be called with an explicit cast to ICloneable, and
		/// that it is inherently virtual.  For example:
		/// 
		/// ParentClass foo = new ChildClass();
		/// ChildClass bar = (ChildClass) ((ICloneable)foo).Clone();
		/// 
		/// Assume that ChildClass is inherited from ParentClass.  Even though foo is declared with
		/// ParentClass, it is actually an instance of ChildClass.  Calling the ICloneable implementation
		/// of Clone() on foo actually calls ChildClass.Clone() as if it were a virtual function.
		/// 
		/// A deep copy of this object
		object ICloneable.Clone()
		{
			throw new NotImplementedException( "Can't clone an abstract base type -- child types must implement ICloneable" );
			//return new PaneBase( this );
		}
	#endregion
	#region Serialization
		/// 
		/// Current schema value that defines the version of the serialized file
		/// 
		public const int schema = 11;
		/// 
		/// Constructor for deserializing objects
		/// 
		/// A  instance that defines the serialized data
		/// 
		/// A  instance that contains the serialized data
		/// 
		protected CurveItem( SerializationInfo info, StreamingContext context )
		{
			// The schema value is just a file version parameter.  You can use it to make future versions
			// backwards compatible as new member variables are added to classes
			int sch = info.GetInt32( "schema" );
			_label = (Label) info.GetValue( "label", typeof(Label) );
			_isY2Axis = info.GetBoolean( "isY2Axis" );
			if ( sch >= 11 )
				_isX2Axis = info.GetBoolean( "isX2Axis" );
			else
				_isX2Axis = false;
			_isVisible = info.GetBoolean( "isVisible" );
			_isOverrideOrdinal = info.GetBoolean( "isOverrideOrdinal" );
			// Data Points are always stored as a PointPairList, regardless of the
			// actual original type (which could be anything that supports IPointList).
			_points = (PointPairList) info.GetValue( "points", typeof(PointPairList) );
			Tag = info.GetValue( "Tag", typeof(object) );
			_yAxisIndex = info.GetInt32( "yAxisIndex" );
			_link = (Link) info.GetValue( "link", typeof(Link) );
		}
		/// 
		/// Populates a  instance with the data needed to serialize the target object
		/// 
		/// A  instance that defines the serialized data
		/// A  instance that contains the serialized data
		[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
		public virtual void GetObjectData( SerializationInfo info, StreamingContext context )
		{
			info.AddValue( "schema", schema );
			info.AddValue( "label", _label );
			info.AddValue( "isY2Axis", _isY2Axis );
			info.AddValue( "isX2Axis", _isX2Axis );
			info.AddValue( "isVisible", _isVisible );
			info.AddValue( "isOverrideOrdinal", _isOverrideOrdinal );
			// if points is already a PointPairList, use it
			// otherwise, create a new PointPairList so it can be serialized
			PointPairList list;
			if ( _points is PointPairList )
				list = _points as PointPairList;
			else
				list = new PointPairList( _points );
			info.AddValue( "points", list );
			info.AddValue( "Tag", Tag );
			info.AddValue( "yAxisIndex", _yAxisIndex );
			info.AddValue( "link", _link );
		}
	#endregion
	
	#region Properties
		/// 
		/// A  instance that represents the 
		/// entry for the this  object
		/// 
		public Label Label
		{
			get { return _label; }
			set { _label = value;}
		}
		/// 
		/// The // 
		/// color (FillColor for the Bar).  This is a common access to
		/// Line.Color,
		/// Border.Color, and
		/// Fill.Color properties for this curve.
		/// 
		public Color Color
		{
			get
			{
				if ( this is BarItem )
					return ((BarItem) this).Bar.Fill.Color;
				else if ( this is LineItem && ((LineItem) this).Line.IsVisible )
					return ((LineItem) this).Line.Color;
				else if ( this is LineItem )
					return ((LineItem) this).Symbol.Border.Color;
				else if ( this is ErrorBarItem )
					return ((ErrorBarItem) this).Bar.Color;
				else if ( this is HiLowBarItem )
					return ((HiLowBarItem) this).Bar.Fill.Color;
				else
					return Color.Empty;
			}
			set 
			{
				if ( this is BarItem )
				{
					((BarItem) this).Bar.Fill.Color = value;
				}
				else if ( this is LineItem )
				{
					((LineItem) this).Line.Color			= value;
					((LineItem) this).Symbol.Border.Color	= value;
					((LineItem) this).Symbol.Fill.Color		= value;
				}
				else if ( this is ErrorBarItem )
					((ErrorBarItem) this).Bar.Color = value;
				else if ( this is HiLowBarItem )
					((HiLowBarItem) this).Bar.Fill.Color = value;
			}
		}
		/// 
		/// Determines whether this  is visible on the graph.
		/// Note that this value turns the curve display on or off, but it does not
		/// affect the display of the legend entry.  To hide the legend entry, you
		/// have to set  to false.
		/// 
		public bool IsVisible
		{
			get { return _isVisible; }
			set { _isVisible = value; }
		}
		// Revision: JCarpenter 10/06
		/// 
		/// Determines whether this  is selected on the graph.
		/// Note that this value changes the curve displayed color, but it does not
		/// affect the display of the legend entry. To hide the legend entry, you
		/// have to set  to false.
		/// 
		public bool IsSelected
		{
			get { return _isSelected; }
			set
			{
				_isSelected = value;
				/*
				if ( this is BarItem )
				{
					( (BarItem)this ).Bar.Fill.UseInactiveColor = !value;
				}
				else if ( this is LineItem )
				{
					( (LineItem)this ).Line.Fill.UseInactiveColor = !value;
					( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value;
					( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value;
				}
				else if ( this is HiLowBarItem )
					( (HiLowBarItem)this ).Bar.Fill.UseInactiveColor = !value;
				else if ( this is PieItem )
					( (PieItem)this ).Fill.UseInactiveColor = !value;
				*/
			}
		}
		// Revision: JCarpenter 10/06
		/// 
		/// Determines whether this  can be selected in the graph.
		/// 
		public bool IsSelectable
		{
			get { return _isSelectable; }
			set { _isSelectable = value; }
		}
		/// 
		/// Gets or sets a value which allows you to override the normal
		/// ordinal axis behavior.
		/// 
		/// 
		/// Normally for an ordinal axis type, the actual data values corresponding to the ordinal
		/// axis will be ignored (essentially they are replaced by ordinal values, e.g., 1, 2, 3, etc).
		/// If IsOverrideOrdinal is true, then the user data values will be used (even if they don't
		/// make sense).  Fractional values are allowed, such that a value of 1.5 is between the first and
		/// second ordinal position, etc.
		/// 
		/// 
		/// 
		public bool IsOverrideOrdinal
		{
			get { return _isOverrideOrdinal; }
			set { _isOverrideOrdinal = value; }
		}
		/// 
		/// Gets or sets a value that determines which X axis this 
		/// is assigned to.
		/// 
		/// 
		/// The
		///  is on the bottom side of the graph and the
		///  is on the top side.  Assignment to an axis
		/// determines the scale that is used to draw the curve on the graph.
		/// 
		/// true to assign the curve to the ,
		/// false to assign the curve to the 
		public bool IsX2Axis
		{
			get { return _isX2Axis; }
			set { _isX2Axis = value; }
		}
		/// 
		/// Gets or sets a value that determines which Y axis this 
		/// is assigned to.
		/// 
		/// 
		/// The
		///  is on the left side of the graph and the
		///  is on the right side.  Assignment to an axis
		/// determines the scale that is used to draw the curve on the graph.  Note that
		/// this value is used in combination with the  to determine
		/// which of the Y Axes (if there are multiples) this curve belongs to.
		/// 
		/// true to assign the curve to the ,
		/// false to assign the curve to the 
		public bool IsY2Axis
		{
			get { return _isY2Axis; }
			set { _isY2Axis = value; }
		}
		/// 
		/// Gets or sets the index number of the Y Axis to which this
		///  belongs.
		/// 
		/// 
		/// This value is essentially an index number into the 
		/// or , depending on the setting of
		/// .
		/// 
		public int YAxisIndex
		{
			get { return _yAxisIndex; }
			set { _yAxisIndex = value; }
		}
		/// 
		/// Determines whether this 
		/// is a .  This does not include 's
		/// or 's.
		/// 
		/// true for a bar chart, or false for a line or pie graph
		public bool IsBar
		{
			get { return this is BarItem; }
		}
		
		/// 
		/// Determines whether this 
		/// is a .
		/// 
		/// true for a pie chart, or false for a line or bar graph
		public bool IsPie
		{
			get { return this is PieItem; }
		}
		
		/// 
		/// Determines whether this 
		/// is a .
		/// 
		/// true for a line chart, or false for a bar type
		public bool IsLine
		{
			get { return this is LineItem; }
		}
		/// 
		/// Gets a flag indicating if the Z data range should be included in the axis scaling calculations.
		/// 
		/// The parent  of this .
		/// 
		/// true if the Z data are included, false otherwise
		abstract internal bool IsZIncluded( GraphPane pane );
		
		/// 
		/// Gets a flag indicating if the X axis is the independent axis for this 
		/// 
		/// The parent  of this .
		/// 
		/// true if the X axis is independent, false otherwise
		abstract internal bool IsXIndependent( GraphPane pane );
		
		/// 
		/// Readonly property that gives the number of points that define this
		///  object, which is the number of points in the
		///  data collection.
		/// 
		public int NPts
		{
			get 
			{
				if ( _points == null )
					return 0;
				else
					return _points.Count;
			}
		}
		
		/// 
		/// The  of X,Y point sets that represent this
		/// .
		/// 
		public IPointList Points
		{
			get { return _points; }
			set { _points = value; }
		}
		/// 
		/// An accessor for the  datum for this .
		/// Index is the ordinal reference (zero based) of the point.
		/// 
		public PointPair this[int index]
		{
			get
			{
				if ( _points == null )
					return new PointPair( PointPair.Missing, PointPair.Missing );
				else
					return ( _points )[index];
			}
		}
		/// 
		/// Gets or sets the hyperlink information for this .
		/// 
		// /// 
		public Link Link
		{
			get { return _link; }
			set { _link = value; }
		}
	#endregion
	
	#region Rendering Methods
		/// 
		/// Do all rendering associated with this  to the specified
		///  device.  This method is normally only
		/// called by the Draw method of the parent 
		/// collection object.
		/// 
		/// 
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// 
		/// 
		/// A reference to the  object that is the parent or
		/// owner of this object.
		/// 
		/// The ordinal position of the current 
		/// curve.
		/// 
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent  object using the
		///  method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// 
		abstract public void Draw( Graphics g, GraphPane pane, int pos, float scaleFactor  );
		
		/// 
		/// Draw a legend key entry for this  at the specified location.
		/// This abstract base method passes through to  or
		///  to do the rendering.
		/// 
		/// 
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// 
        /// 
        /// A reference to the  object that is the parent or
        /// owner of this object.
        /// 
        /// The  struct that specifies the
        /// location for the legend key
		/// 
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent  object using the
		///  method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// 
		abstract public void DrawLegendKey( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor );
		
	#endregion
	#region Utility Methods
		/// 
		/// Add a single x,y coordinate point to the end of the points collection for this curve.
		/// 
		/// The X coordinate value
		/// The Y coordinate value
		public void AddPoint( double x, double y )
		{
			this.AddPoint( new PointPair( x, y ) );
		}
		/// 
		/// Add a  object to the end of the points collection for this curve.
		/// 
		/// 
		/// This method will only work if the  instance reference
		/// at  supports the  interface.
		/// Otherwise, it does nothing.
		/// 
		/// A reference to the  object to
		/// be added
		public void AddPoint( PointPair point )
		{
			if ( _points == null )
				this.Points = new PointPairList();
			if ( _points is IPointListEdit )
				( _points as IPointListEdit ).Add( point );
			else
				throw new NotImplementedException();
		}
		/// 
		/// Clears the points from this .  This is the same
		/// as CurveItem.Points.Clear().
		/// 
		/// 
		/// This method will only work if the  instance reference
		/// at  supports the  interface.
		/// Otherwise, it does nothing.
		/// 
		public void Clear()
		{
			if ( _points is IPointListEdit )
				(_points as IPointListEdit).Clear();
			else
				throw new NotImplementedException();
		}
		/// 
		/// Removes a single point from this .
		/// 
		/// 
		/// This method will only work if the  instance reference
		/// at  supports the  interface.
		/// Otherwise, it does nothing.
		/// 
		/// The ordinal position of the point to be removed.
		public void RemovePoint( int index )
		{
			if ( _points is IPointListEdit )
				(_points as IPointListEdit).RemoveAt( index );
			else
				throw new NotImplementedException();
		}
		/// 
		/// Get the X Axis instance (either  or ) to
		/// which this  belongs.
		/// 
		/// The  object to which this curve belongs.
		/// Either a  or  to which this
		///  belongs.
		/// 
		public Axis GetXAxis( GraphPane pane )
		{
			if ( _isX2Axis )
				return pane.X2Axis;
			else
				return pane.XAxis;
		}
		/// 
		/// Get the Y Axis instance (either  or ) to
		/// which this  belongs.
		/// 
		/// 
		/// This method safely retrieves a Y Axis instance from either the 
		/// or the  using the values of  and
		/// .  If the value of  is out of bounds, the
		/// default  or  is used.
		/// 
		/// The  object to which this curve belongs.
		/// Either a  or  to which this
		///  belongs.
		/// 
		public Axis GetYAxis( GraphPane pane )
		{
			if ( _isY2Axis )
			{
				if ( _yAxisIndex < pane.Y2AxisList.Count )
					return pane.Y2AxisList[_yAxisIndex];
				else
					return pane.Y2AxisList[0];
			}
			else
			{
				if ( _yAxisIndex < pane.YAxisList.Count )
					return pane.YAxisList[_yAxisIndex];
				else
					return pane.YAxisList[0];
			}
		}
		/// 
		/// Get the index of the Y Axis in the  or  list to
		/// which this  belongs.
		/// 
		/// 
		/// This method safely retrieves a Y Axis index into either the 
		/// or the  using the values of  and
		/// .  If the value of  is out of bounds, the
		/// default  or  is used, which is index zero.
		/// 
		/// The  object to which this curve belongs.
		/// An integer value indicating which index position in the list applies to this
		/// 
		/// 
		public int GetYAxisIndex( GraphPane pane )
		{
			if ( _yAxisIndex >= 0 &&
					_yAxisIndex < ( _isY2Axis ? pane.Y2AxisList.Count : pane.YAxisList.Count ) )
				return _yAxisIndex;
			else
				return 0;
		}
		/// 
		/// Loads some pseudo unique colors/symbols into this CurveItem.  This
		/// is the same as MakeUnique(ColorSymbolRotator.StaticInstance).
		/// 
		/// 
		/// 
		/// 
		public void MakeUnique()
		{
			this.MakeUnique( ColorSymbolRotator.StaticInstance );
		}
		/// 
		/// Loads some pseudo unique colors/symbols into this CurveItem.  This
		/// is mainly useful for differentiating a set of new CurveItems without
		/// having to pick your own colors/symbols.
		/// 
		/// 
		/// 
		/// The  that is used to pick the color
		///  and symbol for this method call.
		/// 
		virtual public void MakeUnique( ColorSymbolRotator rotator )
		{
			this.Color = rotator.NextColor;
		}
	
		/// 
		/// Go through the list of  data values for this 
		/// and determine the minimum and maximum values in the data.
		/// 
		/// The minimum X value in the range of data
		/// The maximum X value in the range of data
		/// The minimum Y value in the range of data
		/// The maximum Y value in the range of data
		/// ignoreInitial is a boolean value that
		/// affects the data range that is considered for the automatic scale
		/// ranging (see ).  If true, then initial
		/// data points where the Y value is zero are not included when
		/// automatically determining the scale ,
		/// , and  size.  All data after
		/// the first non-zero Y value are included.
		/// 
		/// 
		/// Determines if the auto-scaled axis ranges will subset the
		/// data points based on any manually set scale range values.
		/// 
		/// 
		/// A reference to the  object that is the parent or
		/// owner of this object.
		/// 
		/// 
		virtual public void GetRange( 	out double xMin, out double xMax,
										out double yMin, out double yMax,
										bool ignoreInitial,
										bool isBoundedRanges,
										GraphPane pane )
		{
			// The lower and upper bounds of allowable data for the X values.  These
			// values allow you to subset the data values.  If the X range is bounded, then
			// the resulting range for Y will reflect the Y values for the points within the X
			// bounds.
			double xLBound = double.MinValue;
			double xUBound = double.MaxValue;
			double yLBound = double.MinValue;
			double yUBound = double.MaxValue;
			// initialize the values to outrageous ones to start
			xMin = yMin = Double.MaxValue;
			xMax = yMax = Double.MinValue;
			Axis yAxis = this.GetYAxis( pane );
			Axis xAxis = this.GetXAxis( pane );
			if ( yAxis == null || xAxis == null )
				return;
			if ( isBoundedRanges )
			{
				xLBound = xAxis._scale._lBound;
				xUBound = xAxis._scale._uBound;
				yLBound = yAxis._scale._lBound;
				yUBound = yAxis._scale._uBound;
			}
			bool isZIncluded = this.IsZIncluded( pane );
			bool isXIndependent = this.IsXIndependent( pane );
			bool isXLog = xAxis.Scale.IsLog;
			bool isYLog = yAxis.Scale.IsLog;
			// Loop over each point in the arrays
			//foreach ( PointPair point in this.Points )
			for ( int i=0; i xUBound ||
					curY < yLBound || curY > yUBound ||
					( isZIncluded && isXIndependent && ( curZ < yLBound || curZ > yUBound ) ) ||
					( isZIncluded && !isXIndependent && ( curZ < xLBound || curZ > xUBound ) ) ||
					( curX <= 0 && isXLog ) || ( curY <= 0 && isYLog );
			
				// ignoreInitial becomes false at the first non-zero
				// Y value
				if (	ignoreInitial && curY != 0 &&
						curY != PointPair.Missing )
					ignoreInitial = false;
			
				if ( 	!ignoreInitial &&
						!outOfBounds &&
						curX != PointPair.Missing &&
						curY != PointPair.Missing )
				{
					if ( curX < xMin )
						xMin = curX;
					if ( curX > xMax )
						xMax = curX;
					if ( curY < yMin )
						yMin = curY;
					if ( curY > yMax )
						yMax = curY;
					if ( isZIncluded && isXIndependent && curZ != PointPair.Missing )
					{
						if ( curZ < yMin )
							yMin = curZ;
						if ( curZ > yMax )
							yMax = curZ;
					}
					else if ( isZIncluded && curZ != PointPair.Missing )
					{
						if ( curZ < xMin )
							xMin = curZ;
						if ( curZ > xMax )
							xMax = curZ;
					}
				}
			}	
		}
		/// Returns a reference to the  object that is the "base"
		/// (independent axis) from which the values are drawn. 
		/// 
		/// This property is determined by the value of  for
		/// , , and 
		/// types.  It is always the X axis for regular  types.
		/// Note that the  setting can override the
		///  and  settings for bar types
		/// (this is because all the bars that are clustered together must share the
		/// same base axis).
		/// 
		/// 
		/// 
		public virtual Axis BaseAxis( GraphPane pane )
		{
			BarBase barBase;
			if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem )
				barBase = pane._barSettings.Base;
			else
				barBase = _isX2Axis ? BarBase.X2 : BarBase.X;
			if ( barBase == BarBase.X )
				return pane.XAxis;
			else if ( barBase == BarBase.X2 )
				return pane.X2Axis;
			else if ( barBase == BarBase.Y )
				return pane.YAxis;
			else
				return pane.Y2Axis;
		}
		/// Returns a reference to the  object that is the "value"
		/// (dependent axis) from which the points are drawn. 
		/// 
		/// This property is determined by the value of  for
		/// , , and 
		/// types.  It is always the Y axis for regular  types.
		/// 
		/// 
		/// 
		public virtual Axis ValueAxis( GraphPane pane )
		{
			BarBase barBase;
			if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem )
				barBase = pane._barSettings.Base;
			else
				barBase = BarBase.X;
			if ( barBase == BarBase.X || barBase == BarBase.X2 )
			{
				return GetYAxis( pane );
			}
			else
				return GetXAxis( pane );
		}
		/// 
		/// Calculate the width of each bar, depending on the actual bar type
		/// 
		/// The width for an individual bar, in pixel units
		public float GetBarWidth( GraphPane pane )
		{
			// Total axis width = 
			// npts * ( nbars * ( bar + bargap ) - bargap + clustgap )
			// cg * bar = cluster gap
			// npts = max number of points in any curve
			// nbars = total number of curves that are of type IsBar
			// bar = bar width
			// bg * bar = bar gap
			// therefore:
			// totwidth = npts * ( nbars * (bar + bg*bar) - bg*bar + cg*bar )
			// totwidth = bar * ( npts * ( nbars * ( 1 + bg ) - bg + cg ) )
			// solve for bar
			float barWidth;
			if ( this is ErrorBarItem )
				barWidth = (float) ( ((ErrorBarItem)this).Bar.Symbol.Size *
						pane.CalcScaleFactor() );
			else if ( this is HiLowBarItem )
//				barWidth = (float) ( ((HiLowBarItem)this).Bar.GetBarWidth( pane,
//						((HiLowBarItem)this).BaseAxis(pane), pane.CalcScaleFactor() ) );
				barWidth = (float) ( ((HiLowBarItem)this).Bar.Size *
						pane.CalcScaleFactor() );
			else // BarItem or LineItem
			{
				// For stacked bar types, the bar width will be based on a single bar
				float numBars = 1.0F;
				if ( pane._barSettings.Type == BarType.Cluster || pane._barSettings.Type == BarType.ClusterHiLow )
					numBars = pane.CurveList.NumBars;
				float denom = numBars * ( 1.0F + pane._barSettings.MinBarGap ) -
							pane._barSettings.MinBarGap + pane._barSettings.MinClusterGap;
				if ( denom <= 0 )
					denom = 1;
				barWidth = pane.BarSettings.GetClusterWidth() / denom;
			}
			if ( barWidth <= 0 )
				return 1;
			return barWidth;
		}
		/// 
		/// Determine the coords for the rectangle associated with a specified point for 
		/// this 
		/// 
		/// The  to which this curve belongs
		/// The index of the point of interest
		/// A list of coordinates that represents the "rect" for
		/// this point (used in an html AREA tag)
		/// true if it's a valid point, false otherwise
		abstract public bool GetCoords( GraphPane pane, int i, out string coords );
	#endregion
	#region Inner classes
	#if ( DOTNET1 ) // Is this a .Net 1.1 compilation?
	
		/// 
		/// Compares 's based on the point value at the specified
		/// index and for the specified axis.
		/// 
		/// 
		public class Comparer : IComparer
		{
			private int index;
			private SortType sortType;
			
			/// 
			/// Constructor for Comparer.
			/// 
			/// The axis type on which to sort.
			/// The index number of the point on which to sort
			public Comparer( SortType type, int index )
			{
				this.sortType = type;
				this.index = index;
			}
			
			/// 
			/// Compares two s using the previously specified index value
			/// and axis.  Sorts in descending order.
			/// 
			/// Curve to the left.
			/// Curve to the right.
			/// -1, 0, or 1 depending on l.X's relation to r.X
			public int Compare( object l, object r ) 
			{
				CurveItem cl = (CurveItem) l;
				CurveItem cr = (CurveItem) r;
				if (cl == null && cr == null )
					return 0;
				else if (cl == null && cr != null ) 
					return -1;
				else if (cl != null && cr == null) 
					return 1;
				if ( cr != null && cr.NPts <= index )
					cr = null;
				if ( cl != null && cl.NPts <= index )
					cl = null;
						
				double lVal, rVal;
				if ( sortType == SortType.XValues )
				{
					lVal = ( l != null ) ? System.Math.Abs( cl[index].X ) : PointPair.Missing;
					rVal = ( r != null ) ? System.Math.Abs( cr[index].X ) : PointPair.Missing;
				}
				else
				{
					lVal = ( l != null ) ? System.Math.Abs( cl[index].Y ) : PointPair.Missing;
					rVal = ( r != null ) ? System.Math.Abs( cr[index].Y ) : PointPair.Missing;
				}
				
				if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) )
					cl = null;
				if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) )
					cr = null;
					
				if ( ( cl == null && cr == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) )
					return 0;
				else if ( cl == null && cr != null ) 
					return -1;
				else if ( cl != null && r == null ) 
					return 1;
				else
					return rVal < lVal ? -1 : 1;
			}
		}
	
#else		// Otherwise, it's .Net 2.0 so use generics
		/// 
		/// Compares 's based on the point value at the specified
		/// index and for the specified axis.
		/// 
		/// 
		public class Comparer : IComparer
		{
			private int index;
			private SortType sortType;
			
			/// 
			/// Constructor for Comparer.
			/// 
			/// The axis type on which to sort.
			/// The index number of the point on which to sort
			public Comparer( SortType type, int index )
			{
				this.sortType = type;
				this.index = index;
			}
			
			/// 
			/// Compares two s using the previously specified index value
			/// and axis.  Sorts in descending order.
			/// 
			/// Curve to the left.
			/// Curve to the right.
			/// -1, 0, or 1 depending on l.X's relation to r.X
			public int Compare( CurveItem l, CurveItem r ) 
			{
				if (l == null && r == null )
					return 0;
				else if (l == null && r != null ) 
					return -1;
				else if (l != null && r == null) 
					return 1;
				if ( r != null && r.NPts <= index )
					r = null;
				if ( l != null && l.NPts <= index )
					l = null;
						
				double lVal, rVal;
				if ( sortType == SortType.XValues )
				{
					lVal = ( l != null ) ? System.Math.Abs( l[index].X ) : PointPair.Missing;
					rVal = ( r != null ) ? System.Math.Abs( r[index].X ) : PointPair.Missing;
				}
				else
				{
					lVal = ( l != null ) ? System.Math.Abs( l[index].Y ) : PointPair.Missing;
					rVal = ( r != null ) ? System.Math.Abs( r[index].Y ) : PointPair.Missing;
				}
				
				if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) )
					l = null;
				if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) )
					r = null;
					
				if ( (l == null && r == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) )
					return 0;
				else if (l == null && r != null ) 
					return -1;
				else if (l != null && r == null) 
					return 1;
				else
					return rVal < lVal ? -1 : 1;
			}
		}
	#endif
	
	#endregion
	}
}