//============================================================================
//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.Runtime.Serialization;
using System.Security.Permissions;
namespace DrawGraph
{
	/// 
	/// A class than contains information about the position of an object on the graph.
	/// 
	/// 
	///  John Champion 
	///  $Revision: 3.14 $ $Date: 2006/06/24 20:26:43 $ 
	[Serializable]
	public class Location : ICloneable, ISerializable
	{
	#region Private Fields
		///  Private field to store the vertical alignment property for
		/// this object.  Use the public property 
		/// to access this value.  The value of this field is a  enum.
		/// 
		private AlignV	_alignV;
		///  Private field to store the horizontal alignment property for
		/// this object.  Use the public property 
		/// to access this value.  The value of this field is a  enum.
		/// 
		private AlignH	_alignH;
		///  Private fields to store the X and Y coordinate positions for
		/// this object.  Use the public properties  and
		///  to access these values.  The coordinate type stored here is
		/// dependent upon the setting of .
		/// 
		private double	_x,
							_y,
							_width,
							_height;
							
		/// 
		/// Private field to store the coordinate system to be used for defining the
		/// object position.  Use the public property
		///  to access this value. The coordinate system
		/// is defined with the  enum.
		/// 
		private CoordType	_coordinateFrame;
	#endregion
	#region Properties
		/// 
		/// A horizontal alignment parameter for this object specified
		/// using the  enum type.
		/// 
		public AlignH AlignH
		{
			get { return _alignH; }
			set { _alignH = value; }
		}
		/// 
		/// A vertical alignment parameter for this object specified
		/// using the  enum type.
		/// 
		public AlignV AlignV
		{
			get { return _alignV; }
			set { _alignV = value; }
		}
		/// 
		/// The coordinate system to be used for defining the object position
		/// 
		///  The coordinate system is defined with the 
		/// enum
		public CoordType CoordinateFrame
		{
			get { return _coordinateFrame; }
			set { _coordinateFrame = value; }
		}
		/// 
		/// The x position of the object.
		/// 
		/// 
		/// The units of this position
		/// are specified by the  property.
		/// The object will be aligned to this position based on the
		///  property.
		/// 
		public double X
		{
			get { return _x; }
			set { _x = value; }
		}
		/// 
		/// The y position of the object.
		/// 
		/// 
		/// The units of this position
		/// are specified by the  property.
		/// The object will be aligned to this position based on the
		///  property.
		/// 
		public double Y
		{
			get { return _y; }
			set { _y = value; }
		}
		/// 
		/// The x1 position of the object (an alias for the x position).
		/// 
		/// 
		/// The units of this position
		/// are specified by the  property.
		/// The object will be aligned to this position based on the
		///  property.
		/// 
		public double X1
		{
			get { return _x; }
			set { _x = value; }
		}
		/// 
		/// The y1 position of the object (an alias for the y position).
		/// 
		/// 
		/// The units of this position
		/// are specified by the  property.
		/// The object will be aligned to this position based on the
		///  property.
		/// 
		public double Y1
		{
			get { return _y; }
			set { _y = value; }
		}
		/// 
		/// The width of the object.
		/// 
		/// 
		/// The units of this position are specified by the
		///  property.
		/// 
		public double Width
		{
			get { return _width; }
			set { _width = value; }
		}
		/// 
		/// The height of the object.
		/// 
		/// 
		/// The units of this position are specified by the
		///  property.
		/// 
		public double Height
		{
			get { return _height; }
			set { _height = value; }
		}
		/// 
		/// The x2 position of the object.
		/// 
		/// 
		/// The units of this position are specified by the
		///  property.
		/// The object will be aligned to this position based on the
		///  property.  This position is only used for
		/// objects such as , where it makes sense
		/// to have a second coordinate.  Note that the X2 position is stored
		/// internally as a  offset from .
		/// 
		public double X2
		{
			get { return _x+_width; }
			//set { width = value-x; }
		}
		/// 
		/// The y2 position of the object.
		/// 
		/// 
		/// The units of this position
		/// are specified by the  property.
		/// The object will be aligned to this position based on the
		///  property.  This position is only used for
		/// objects such as , where it makes sense
		/// to have a second coordinate.  Note that the Y2 position is stored
		/// internally as a  offset from .
		/// 
		public double Y2
		{
			get { return _y+_height; }
			//set { height = value-y; }
		}
		/// 
		/// The  for this object as defined by the
		/// , , , and
		///  properties.
		/// 
		/// 
		/// Note that this method reduces the precision of the location coordinates from double
		/// precision to single precision.  In some cases, such as , it
		/// may affect the resolution of the point location.
		/// 
		/// A  in 
		/// units.
		public RectangleF Rect
		{
			get { return new RectangleF( (float)_x, (float)_y, (float)_width, (float)_height ); }
			set
			{
				_x = value.X;
				_y = value.Y;
				_width = value.Width;
				_height = value.Height;
			}
		}
		/// 
		/// The top-left  for this .
		/// 
		/// 
		/// Note that this method reduces the precision of the location coordinates from double
		/// precision to single precision.  In some cases, such as , it
		/// may affect the resolution of the point location.
		/// 
		/// A  in  units.
		public PointF TopLeft
		{
			get { return new PointF( (float)_x, (float)_y ); }
			set { _x = value.X; _y = value.Y; }
		}
		/// 
		/// The bottom-right  for this .
		/// 
		/// 
		/// Note that this method reduces the precision of the location coordinates from double
		/// precision to single precision.  In some cases, such as , it
		/// may affect the resolution of the point location.
		/// 
		/// A  in  units.
		public PointF BottomRight
		{
			get { return new PointF( (float)this.X2, (float)this.Y2 ); }
			//set { this.X2 = value.X; this.Y2 = value.Y; }
		}
	#endregion
	
	#region Constructors
		/// 
		/// Default constructor for the  class.
		/// 
		public Location() : this( 0, 0, CoordType.ChartFraction )
		{
		}
		/// 
		/// Constructor for the  class that specifies the
		/// x, y position and the .
		/// 
		/// 
		/// The (x,y) position corresponds to the top-left corner;
		/// 
		/// The x position, specified in units of .
		/// 
		/// The y position, specified in units of .
		/// 
		/// The  enum that specifies the
		/// units for  and 
		public Location( double x, double y, CoordType coordType ) :
				this( x, y, coordType, AlignH.Left, AlignV.Top )
		{
		}
		
		/// 
		/// Constructor for the  class that specifies the
		/// x, y position and the .
		/// 
		/// 
		/// The (x,y) position corresponds to the top-left corner;
		/// 
		/// The x position, specified in units of .
		/// 
		/// The y position, specified in units of .
		/// 
		/// The  enum that specifies the
		/// units for  and 
		/// The  enum that specifies
		/// the horizontal alignment of the object with respect to the (x,y) location
		/// The  enum that specifies
		/// the vertical alignment of the object with respect to the (x,y) location
		public Location( double x, double y, CoordType coordType, AlignH alignH, AlignV alignV )
		{
			_x = x;
			_y = y;
			_width = 0;
			_height = 0;
			_coordinateFrame = coordType;
			_alignH = alignH;
			_alignV = alignV;
		}
		
		/// 
		/// Constructor for the  class that specifies the
		/// (x, y), (width, height), and the .
		/// 
		/// 
		/// The (x,y) position
		/// corresponds to the starting position, the (x2, y2) coorresponds to the ending position
		/// (typically used for 's).
		/// 
		/// The x position, specified in units of .
		/// 
		/// The y position, specified in units of .
		/// 
		/// The width, specified in units of .
		/// 
		/// The height, specified in units of .
		/// 
		/// The  enum that specifies the
		/// units for  and 
		/// The  enum that specifies
		/// the horizontal alignment of the object with respect to the (x,y) location
		/// The  enum that specifies
		/// the vertical alignment of the object with respect to the (x,y) location
		public Location( double x, double y, double width, double height,
			CoordType coordType, AlignH alignH, AlignV alignV ) :
				this( x, y, coordType, alignH, alignV )
		{
			_width = width;
			_height = height;
		}
		
		/// 
		/// The Copy Constructor
		/// 
		/// The  object from which to copy
		public Location( Location rhs )
		{
			_x = rhs._x;
			_y = rhs._y;
			_width = rhs._width;
			_height = rhs._height;
			_coordinateFrame = rhs.CoordinateFrame;
			_alignH = rhs.AlignH;
			_alignV = rhs.AlignV;
		}
		/// 
		/// Implement the  interface in a typesafe manner by just
		/// calling the typed version of 
		/// 
		/// A deep copy of this object
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		/// 
		/// Typesafe, deep-copy clone method.
		/// 
		/// A new, independent copy of this class
		public Location Clone()
		{
			return new Location( this );
		}
	#endregion
	#region Serialization
		/// 
		/// Current schema value that defines the version of the serialized file
		/// 
		public const int schema = 10;
		/// 
		/// Constructor for deserializing objects
		/// 
		/// A  instance that defines the serialized data
		/// 
		/// A  instance that contains the serialized data
		/// 
		protected Location( 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" );
			_alignV = (AlignV) info.GetValue( "alignV", typeof(AlignV) );
			_alignH = (AlignH) info.GetValue( "alignH", typeof(AlignH) );
			_x = info.GetDouble( "x" );
			_y = info.GetDouble( "y" );
			_width = info.GetDouble( "width" );
			_height = info.GetDouble( "height" );
			_coordinateFrame = (CoordType) info.GetValue( "coordinateFrame", typeof(CoordType) );
		}
		/// 
		/// 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( "alignV", _alignV );
			info.AddValue( "alignH", _alignH );
			info.AddValue( "x", _x );
			info.AddValue( "y", _y );
			info.AddValue( "width", _width );
			info.AddValue( "height", _height );
			info.AddValue( "coordinateFrame", _coordinateFrame );
		}
	#endregion
	#region Methods
		/// 
		/// Transform this  object to display device
		/// coordinates using the properties of the specified .
		/// 
		/// 
		/// A reference to the  object that contains
		/// the  classes which will be used for the transform.
		/// 
		/// A point in display device coordinates that corresponds to the
		/// specified user point.
		public PointF Transform( PaneBase pane )
		{
			return Transform( pane, _x, _y,
						_coordinateFrame );
		}
		
		/// 
		/// Transform a data point from the specified coordinate type
		/// () to display device coordinates (pixels).
		/// 
		/// 
		/// If  is not of type , then
		/// only the  transformation is available.
		/// 
		/// 
		/// A reference to the  object that contains
		/// the  classes which will be used for the transform.
		/// 
		/// The x coordinate that defines the point in user
		/// space.
		/// The y coordinate that defines the point in user
		/// space.
		/// A  type that defines the
		/// coordinate system in which the X,Y pair is defined.
		/// A point in display device coordinates that corresponds to the
		/// specified user point.
		public static PointF Transform( PaneBase pane, double x, double y, CoordType coord )
		{
			return pane.TransformCoord( x, y, coord );
		}
		
		/// 
		/// Transform this  from the coordinate system
		/// as specified by  to the device coordinates
		/// of the specified  object.
		/// 
		/// 
		/// The returned
		///  struct represents the top-left corner of the
		/// object that honors the  properties.
		/// The  and  properties are honored in 
		/// this transformation.
		/// 
		/// 
		/// A reference to the  object that contains
		/// the  classes which will be used for the transform.
		/// 
		/// The width of the object in device pixels
		/// The height of the object in device pixels
		/// The top-left corner of the object
		public PointF TransformTopLeft( PaneBase pane, float width, float height )
		{
			PointF pt = Transform( pane );
			
			if ( _alignH == AlignH.Right )
				pt.X -= width;
			else if ( _alignH == AlignH.Center )
				pt.X -= width / 2.0F;
				
			if ( _alignV == AlignV.Bottom )
				pt.Y -= height;
			else if ( _alignV == AlignV.Center )
				pt.Y -= height / 2.0F;
			
			return pt;
		}
		/// 
		/// The  for this object as defined by the
		///  and 
		/// properties.
		/// 
		/// 
		/// This method transforms the location to output device pixel units.
		/// The  and  properties are ignored for
		/// this transformation (see ).
		/// 
		/// A  in pixel units.
		public PointF TransformTopLeft( PaneBase pane )
		{
			return Transform( pane );
		}
		/// 
		/// The  for this object as defined by the
		///  and  properties.
		/// 
		/// 
		/// This method transforms the location to output device pixel units.
		/// The  and  properties are ignored for
		/// this transformation (see ).
		/// 
		/// A  in pixel units.
		public PointF TransformBottomRight( PaneBase pane )
		{
			return Transform( pane, this.X2, this.Y2, _coordinateFrame );
		}
		/// 
		/// Transform the  for this object as defined by the
		/// , , , and
		///  properties.
		/// 
		/// 
		/// This method transforms the location to output device pixel units.
		/// The  and  properties are honored in 
		/// this transformation.
		/// 
		/// A  in pixel units.
		public RectangleF TransformRect( PaneBase pane )
		{
			PointF pix1 = TransformTopLeft( pane );
			PointF pix2 = TransformBottomRight( pane );
			//PointF pix3 = TransformTopLeft( pane, pix2.X - pix1.X, pix2.Y - pix1.Y );
			return new RectangleF( pix1.X, pix1.Y, Math.Abs(pix2.X - pix1.X), Math.Abs(pix2.Y - pix1.Y) );
		}
	#endregion
	}
}