//============================================================================
//PointPair Class
//Copyright ?2004  Jerry Vos
//
//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.Runtime.Serialization;
using System.Security.Permissions;
using System.Collections;
using IComparer	= System.Collections.IComparer;
#if ( !DOTNET1 )	// Is this a .Net 2 compilation?
using System.Collections.Generic;
#endif
namespace DrawGraph
{
	/// 
	/// A simple point represented by an (X,Y,Z) group of double values.
	/// 
	/// 
	///  Jerry Vos modified by John Champion 
	///  $Revision: 3.24 $ $Date: 2007/03/17 18:43:44 $ 
	[Serializable]
	public class PointPair : PointPairBase, ISerializable
	{
	#region Member variables
		
		/// 
		/// This PointPair's Z coordinate.  Also used for the lower value (dependent axis)
		/// for  and  charts.
		/// 
		public double Z;
		/// 
		/// A tag object for use by the user.  This can be used to store additional
		/// information associated with the .  ZedGraph never
		/// modifies this value, but if it is a  type, it
		/// may be displayed in a 
		/// within the  object.
		/// 
		/// 
		/// 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;
	#endregion
	#region Constructors
		/// 
		/// Default Constructor
		/// 
		public PointPair() : this( 0, 0, 0, null )
		{
		}
		/// 
		/// Creates a point pair with the specified X and Y.
		/// 
		/// This pair's x coordinate.
		/// This pair's y coordinate.
		public PointPair( double x, double y )
			: this ( x, y, 0, null )
		{
		}
		/// 
		/// Creates a point pair with the specified X, Y, and
		/// label ().
		/// 
		/// This pair's x coordinate.
		/// This pair's y coordinate.
		/// This pair's string label ()
		public PointPair( double x, double y, string label )
			: this( x, y, 0, label as object )
		{
		}
		/// 
		/// Creates a point pair with the specified X, Y, and base value.
		/// 
		/// This pair's x coordinate.
		/// This pair's y coordinate.
		/// This pair's z or lower dependent coordinate.
		public PointPair( double x, double y, double z )
			: this( x, y, z, null )
		{
		}
		/// 
		/// Creates a point pair with the specified X, Y, base value, and
		/// string label ().
		/// 
		/// This pair's x coordinate.
		/// This pair's y coordinate.
		/// This pair's z or lower dependent coordinate.
		/// This pair's string label ()
		public PointPair( double x, double y, double z, string label )
			: this( x, y, z, label as object )
		{
		}
		/// 
		/// Creates a point pair with the specified X, Y, base value, and
		/// ().
		/// 
		/// This pair's x coordinate.
		/// This pair's y coordinate.
		/// This pair's z or lower dependent coordinate.
		/// This pair's  property
		public PointPair( double x, double y, double z, object tag )
			: base( x, y )
		{
			this.Z = z;
			this.Tag = tag;
		}
		/// 
		/// Creates a point pair from the specified  struct.
		/// 
		/// The  struct from which to get the
		/// new  values.
		public PointPair( PointF pt ) : this( pt.X, pt.Y, 0, null )
		{
		}
		/// 
		/// The PointPair copy constructor.
		/// 
		/// The basis for the copy.
		public PointPair( PointPair rhs ) : base( rhs )
		{
			this.Z = rhs.Z;
			if ( rhs.Tag is ICloneable )
				this.Tag = ((ICloneable) rhs.Tag).Clone();
			else
				this.Tag = rhs.Tag;
		}
	#endregion
	#region Serialization
		/// 
		/// Current schema value that defines the version of the serialized file
		/// 
		public const int schema2 = 11;
		/// 
		/// Constructor for deserializing objects
		/// 
		/// A  instance that defines the serialized data
		/// 
		/// A  instance that contains the serialized data
		/// 
		protected PointPair( SerializationInfo info, StreamingContext context )
			: base( info, 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( "schema2" );
			Z = info.GetDouble( "Z" );
			Tag = info.GetValue( "Tag", typeof(object) );
		}
		/// 
		/// 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 override void GetObjectData( SerializationInfo info, StreamingContext context )
		{
			base.GetObjectData( info, context );
			info.AddValue( "schema2", schema2 );
			info.AddValue( "Z", Z );
			info.AddValue( "Tag", Tag );
		}
	#endregion
	#region Properties
		/// 
		/// Readonly value that determines if either the X, Y, or Z
		/// coordinate in this PointPair is an invalid (not plotable) value.
		/// It is considered invalid if it is missing (equal to System.Double.Max),
		/// Infinity, or NaN.
		/// 
		/// true if any value is invalid
		public bool IsInvalid3D
		{
			get { return	this.X == PointPair.Missing ||
							this.Y == PointPair.Missing ||
							this.Z == PointPair.Missing ||
							Double.IsInfinity( this.X ) ||
							Double.IsInfinity( this.Y ) ||
							Double.IsInfinity( this.Z ) ||
							Double.IsNaN( this.X ) ||
							Double.IsNaN( this.Y ) ||
							Double.IsNaN( this.Z );
				}
		}
		/// 
		/// The "low" value for this point (lower dependent-axis value).
		/// This is really just an alias for .
		/// 
		/// The lower dependent value for this .
		public double LowValue
		{
			get { return this.Z; }
			set { this.Z = value; }
		}
		/// 
		/// The ColorValue property is just an alias for the 
		/// property.
		/// 
		/// 
		/// For other types, such as the , the 
		/// can be mapped to a unique value.  This is used with the
		///  option.
		/// 
		virtual public double ColorValue
		{
			get { return Z; }
			set { Z = value; }
		}
	#endregion
	#region Inner classes
	#if ( DOTNET1 )	// Is this a .Net 1.1 compilation?
		/// 
		/// Compares points based on their y values.  Is setup to be used in an
		/// ascending order sort.
		/// 
		/// 
		public class PointPairComparerY : IComparer
		{
		
			/// 
			/// Compares two s.
			/// 
			/// Point to the left.
			/// Point to the right.
			/// -1, 0, or 1 depending on l.Y's relation to r.Y
			public int Compare( object l, object r ) 
			{
				PointPair pl = (PointPair) l;
				PointPair pr = (PointPair) r;
				if (pl == null && pr == null) 
				{
					return 0;
				} 
				else if (pl == null && pr != null) 
				{
					return -1;
				} 
				else if (pl != null && pr == null) 
				{
					return 1;
				} 
				double lY = pl.Y;
				double rY = pr.Y;
				if (System.Math.Abs(lY - rY) < .000000001)
					return 0;
				
				return lY < rY ? -1 : 1;
			}
		}
	
		/// 
		/// Compares points based on their x values.  Is setup to be used in an
		/// ascending order sort.
		/// 
		/// 
		public class PointPairComparer : IComparer
		{
			private SortType sortType;
			
			/// 
			/// Constructor for PointPairComparer.
			/// 
			/// The axis type on which to sort.
			public PointPairComparer( SortType type )
			{
				this.sortType = type;
			}
			
			/// 
			/// Compares two s.
			/// 
			/// Point to the left.
			/// Point to the right.
			/// -1, 0, or 1 depending on l.X's relation to r.X
			public int Compare( object l, object r ) 
			{				 
				PointPair pl = (PointPair) l;
				PointPair pr = (PointPair) r;
				if ( pl == null && pr == null ) 
					return 0;
				else if ( pl == null && pr != null ) 
					return -1;
				else if ( pl != null && pr == null ) 
					return 1;
				double lVal, rVal;
			
				if ( sortType == SortType.XValues )
				{
					lVal = pl.X;
					rVal = pr.X;
				}
				else
				{
					lVal = pl.Y;
					rVal = pr.Y;
				}
				
				if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) )
					pl = null;
				if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) )
					pr = null;
				if ( ( pl == null && pr == null ) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) )
					return 0;
				else if ( pl == null && pr != null ) 
					return -1;
				else if ( pl != null && pr == null ) 
					return 1;
				else
					return lVal < rVal ? -1 : 1;
			}
		}
	
	#else		// Otherwise, it's .Net 2.0, so use generics
		/// 
		/// Compares points based on their y values.  Is setup to be used in an
		/// ascending order sort.
		/// 
		/// 
		public class PointPairComparerY : IComparer
		{
			/// 
			/// Compares two s.
			/// 
			/// Point to the left.
			/// Point to the right.
			/// -1, 0, or 1 depending on l.Y's relation to r.Y
			public int Compare( PointPair l, PointPair r )
			{
				if ( l == null && r == null )
				{
					return 0;
				}
				else if ( l == null && r != null )
				{
					return -1;
				}
				else if ( l != null && r == null )
				{
					return 1;
				}
				double lY = l.Y;
				double rY = r.Y;
				if ( System.Math.Abs( lY - rY ) < .000000001 )
					return 0;
				return lY < rY ? -1 : 1;
			}
		}
		/// 
		/// Compares points based on their x values.  Is setup to be used in an
		/// ascending order sort.
		/// 
		/// 
		public class PointPairComparer : IComparer
		{
			private SortType sortType;
			/// 
			/// Constructor for PointPairComparer.
			/// 
			/// The axis type on which to sort.
			public PointPairComparer( SortType type )
			{
				this.sortType = type;
			}
			/// 
			/// Compares two s.
			/// 
			/// Point to the left.
			/// Point to the right.
			/// -1, 0, or 1 depending on l.X's relation to r.X
			public int Compare( PointPair l, PointPair r )
			{
				if ( l == null && r == null )
					return 0;
				else if ( l == null && r != null )
					return -1;
				else if ( l != null && r == null )
					return 1;
				double lVal, rVal;
				if ( sortType == SortType.XValues )
				{
					lVal = l.X;
					rVal = r.X;
				}
				else
				{
					lVal = l.Y;
					rVal = r.Y;
				}
				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 lVal < rVal ? -1 : 1;
			}
		}
	#endif
	#endregion
	#region Methods
		/// 
		/// Compare two  objects for equality.  To be equal, X, Y, and Z
		/// must be exactly the same between the two objects.
		/// 
		/// The  object to be compared with.
		/// true if the  objects are equal, false otherwise
		public override bool Equals( object obj )
		{
			PointPair rhs = obj as PointPair;
			return this.X == rhs.X && this.Y == rhs.Y && this.Z == rhs.Z;
		}
		/// 
		/// Return the HashCode from the base class.
		/// 
		/// 
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
		/// 
		/// Format this PointPair value using the default format.  Example:  "( 12.345, -16.876 )".
		/// The two double values are formatted with the "g" format type.
		/// 
		/// true to show the third "Z" or low dependent value coordinate
		/// A string representation of the PointPair
		virtual public string ToString( bool isShowZ )
		{
			return this.ToString( PointPair.DefaultFormat, isShowZ );
		}
		/// 
		/// Format this PointPair value using a general format string.
		/// Example:  a format string of "e2" would give "( 1.23e+001, -1.69e+001 )".
		/// If 
		/// is true, then the third "Z" coordinate is also shown.
		/// 
		/// A format string that will be used to format each of
		/// the two double type values (see ).
		/// A string representation of the PointPair
		/// true to show the third "Z" or low dependent value coordinate
		virtual public string ToString( string format, bool isShowZ )
		{
			return "( " + this.X.ToString( format ) +
					", " + this.Y.ToString( format ) + 
					( isShowZ ? ( ", " + this.Z.ToString( format ) ) : "" )
					+ " )";
		}
		/// 
		/// Format this PointPair value using different general format strings for the X, Y, and Z values.
		/// Example:  a format string of "e2" would give "( 1.23e+001, -1.69e+001 )".
		/// 
		/// A format string that will be used to format the X
		/// double type value (see ).
		/// A format string that will be used to format the Y
		/// double type value (see ).
		/// A format string that will be used to format the Z
		/// double type value (see ).
		/// A string representation of the PointPair
		public string ToString( string formatX, string formatY, string formatZ )
		{
			return "( " + this.X.ToString( formatX ) +
					", " + this.Y.ToString( formatY ) + 
					", " + this.Z.ToString( formatZ ) + 
					" )";
		}
	#endregion
	}
}