//============================================================================
//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.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace DrawGraph
{
	/// 
	/// A class that encapsulates color-fill properties for an object.  The  class
	/// is used in , , ,
	/// , and  objects.
	/// 
	/// 
	///  John Champion 
	///  $Revision: 3.22 $ $Date: 2007/01/26 09:01:49 $ 
	[Serializable]
	public class Fill : ISerializable, ICloneable
	{
	#region Fields
		/// 
		/// Private field that stores the fill color.  Use the public
		/// property  to access this value.  This property is
		/// only applicable if the  is not .
		/// 
		private Color _color;
		/// 
		/// Private field that stores the secondary color for gradientByValue fills.  Use the public
		/// property  to access this value.  This property is
		/// only applicable if the  is ,
		/// , or .
		/// 
		private Color _secondaryValueGradientColor;
		/// 
		/// Private field that stores the custom fill brush.  Use the public
		/// property  to access this value.  This property is
		/// only applicable if the 
		///  property is set to .
		/// 
		protected Brush	_brush;
		/// 
		/// Private field that determines the type of color fill.  Use the public
		/// property  to access this value.  The fill color
		/// is determined by the property  or
		/// .
		/// 
		private FillType	_type;
		/// 
		/// Private field that determines if the brush will be scaled to the bounding box
		/// of the filled object.  If this value is false, then the brush will only be aligned
		/// with the filled object based on the  and 
		/// properties.
		/// 
		private bool		_isScaled;
		/// 
		/// Private field that determines how the brush will be aligned with the filled object
		/// in the horizontal direction.  This value is a  enumeration.
		/// This field only applies if  is false.
		/// properties.
		/// 
		/// 
		/// 
		private AlignH		_alignH;
		/// 
		/// Private field that determines how the brush will be aligned with the filled object
		/// in the vertical direction.  This value is a  enumeration.
		/// This field only applies if  is false.
		/// properties.
		/// 
		/// 
		/// 
		private AlignV		_alignV;
		private double	_rangeMin;
		private double	_rangeMax;
		private double _rangeDefault;
		private Bitmap	_gradientBM;
		/// 
		/// Private field that saves the image passed to the constructor.
		/// This is used strictly for serialization.
		/// 
		private Image	_image;
		/// 
		/// Private field that saves the image wrapmode passed to the constructor.
		/// This is used strictly for serialization.
		/// 
		private WrapMode _wrapMode;
		/// 
		/// Private field that saves the list of colors used to create the
		///  in the constructor.  This is used strictly
		/// for serialization.
		/// 
		private Color[] _colorList;
		/// 
		/// Private field that saves the list of positions used to create the
		///  in the constructor.  This is used strictly
		/// for serialization.
		/// 
		private float[] _positionList;
		/// 
		/// Private field the saves the angle of the fill.  This is used strictly for serialization.
		/// 
		private float _angle;
	#endregion
	#region Defaults
		/// 
		/// A simple struct that defines the
		/// default property values for the  class.
		/// 
		public struct Default
		{
			// Default Fill properties
			/// 
			/// The default scaling mode for  fills.
			/// This is the default value for the  property.
			/// 
			public static bool IsScaled = true;
			/// 
			/// The default horizontal alignment for  fills.
			/// This is the default value for the  property.
			/// 
			public static AlignH AlignH = AlignH.Center;
			/// 
			/// The default vertical alignment for  fills.
			/// This is the default value for the  property.
			/// 
			public static AlignV AlignV = AlignV.Center;
		}
	#endregion
	
	#region Constructors
		/// 
		/// Generic initializer to default values
		/// 
		private void Init()
		{
			_color = Color.White;
			_secondaryValueGradientColor = Color.White;
			_brush = null;
			_type = FillType.None;
			_isScaled = Default.IsScaled;
			_alignH = Default.AlignH;
			_alignV = Default.AlignV;
			_rangeMin = 0.0;
			_rangeMax = 1.0;
			_rangeDefault = double.MaxValue;
			_gradientBM = null;
			_colorList = null;
			_positionList = null;
			_angle = 0;
			_image = null;
			_wrapMode = WrapMode.Tile;
		}
		/// 
		/// The default constructor.  Initialized to no fill.
		/// 
		public Fill()
		{
			Init();
		}
		
		/// 
		/// Constructor that specifies the color, brush, and type for this fill.
		/// 
		/// The color of the fill for solid fills
		/// A custom brush for fills.  Can be a ,
		/// , or .
		/// The  for this fill.
		public Fill( Color color, Brush brush, FillType type )
		{
			Init();
			_color = color;
			_brush = brush;
			_type = type;
		}
		
		/// 
		/// Constructor that creates a solid color-fill, setting  to
		/// , and setting  to the
		/// specified color value.
		/// 
		/// The color of the solid fill
		public Fill( Color color )
		{
			Init();
			_color = color;
			if ( color != Color.Empty )
				_type = FillType.Solid;
		}
		
		/// 
		/// Constructor that creates a linear gradient color-fill, setting  to
		///  using the specified colors and angle.
		/// 
		/// The first color for the gradient fill
		/// The second color for the gradient fill
		/// The angle (degrees) of the gradient fill
		public Fill( Color color1, Color color2, float angle )
		{
			Init();
			_color = color2;
			ColorBlend blend = new ColorBlend( 2 );
			blend.Colors[0] = color1;
			blend.Colors[1] = color2;
			blend.Positions[0] = 0.0f;
			blend.Positions[1] = 1.0f;
			_type = FillType.Brush;
			this.CreateBrushFromBlend( blend, angle );
		}
		
		/// 
		/// Constructor that creates a linear gradient color-fill, setting  to
		///  using the specified colors.
		/// 
		/// The first color for the gradient fill
		/// The second color for the gradient fill
		public Fill( Color color1, Color color2 ) : this( color1, color2, 0.0F )
		{
		}
		
		/// 
		/// Constructor that creates a linear gradient color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of three colors.
		/// 
		/// The first color for the gradient fill
		/// The second color for the gradient fill
		/// The third color for the gradient fill
		public Fill( Color color1, Color color2, Color color3 ) :
			this( color1, color2, color3, 0.0f )
		{
		}
		/// 
		/// Constructor that creates a linear gradient color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of three colors
		/// 
		/// The first color for the gradient fill
		/// The second color for the gradient fill
		/// The third color for the gradient fill
		/// The angle (degrees) of the gradient fill
		public Fill( Color color1, Color color2, Color color3, float angle )
		{
			Init();
			_color = color3;
			ColorBlend blend = new ColorBlend( 3 );
			blend.Colors[0] = color1;
			blend.Colors[1] = color2;
			blend.Colors[2] = color3;
			blend.Positions[0] = 0.0f;
			blend.Positions[1] = 0.5f;
			blend.Positions[2] = 1.0f;
			_type = FillType.Brush;
			
			this.CreateBrushFromBlend( blend, angle );
		}
		
		/// 
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on a  object.  The gradient
		/// angle is defaulted to zero.
		/// 
		/// The  object that defines the colors
		/// and positions along the gradient.
		public Fill( ColorBlend blend ) :
			this( blend, 0.0F )
		{
		}
		/// 
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on a  object, drawn at the
		/// specified angle (degrees).
		/// 
		/// The  object that defines the colors
		/// and positions along the gradient.
		/// The angle (degrees) of the gradient fill
		public Fill( ColorBlend blend, float angle )
		{
			Init();
			_type = FillType.Brush;
			this.CreateBrushFromBlend( blend, angle );
		}
		/// 
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on an array of  objects, drawn at an
		/// angle of zero (degrees).  The  array is used to create
		/// a  object assuming a even linear distribution of the colors
		/// across the gradient.
		/// 
		/// The array of  objects that defines the colors
		/// along the gradient.
		public Fill( Color[] colors ) :
			this( colors, 0.0F )
		{
		}
		/// 
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on an array of  objects, drawn at the
		/// specified angle (degrees).  The  array is used to create
		/// a  object assuming a even linear distribution of the colors
		/// across the gradient.
		/// 
		/// The array of  objects that defines the colors
		/// along the gradient.
		/// The angle (degrees) of the gradient fill
		public Fill( Color[] colors, float angle )
		{
			Init();
			_color = colors[ colors.Length - 1 ];
			ColorBlend blend = new ColorBlend();
			blend.Colors = colors;
			blend.Positions = new float[colors.Length];
			blend.Positions[0] = 0.0F;
			for ( int i=1; i
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on an array of  objects, drawn at the
		/// an angle of zero (degrees).  The  array is used to create
		/// a  object assuming a even linear distribution of the colors
		/// across the gradient.
		/// 
		/// The array of  objects that defines the colors
		/// along the gradient.
		/// The array of floating point values that defines the color
		/// positions along the gradient.  Values should range from 0 to 1.
		public Fill( Color[] colors, float[] positions ) :
			this( colors, positions, 0.0F )
		{
		}
		/// 
		/// Constructor that creates a linear gradient multi-color-fill, setting  to
		///  using the specified colors.  This gradient fill
		/// consists of many colors based on an array of  objects, drawn at the
		/// specified angle (degrees).  The  array is used to create
		/// a  object assuming a even linear distribution of the colors
		/// across the gradient.
		/// 
		/// The array of  objects that defines the colors
		/// along the gradient.
		/// The array of floating point values that defines the color
		/// positions along the gradient.  Values should range from 0 to 1.
		/// The angle (degrees) of the gradient fill
		public Fill( Color[] colors, float[] positions, float angle )
		{
			Init();
			_color = colors[ colors.Length - 1 ];
			ColorBlend blend = new ColorBlend();
			blend.Colors = colors;
			blend.Positions = positions;
			_type = FillType.Brush;
			this.CreateBrushFromBlend( blend, angle );
		}
		/// 
		/// Constructor that creates a texture fill, setting  to
		///  and using the specified image.
		/// 
		/// The  to use for filling
		/// The  class that controls the image wrapping properties
		public Fill( Image image, WrapMode wrapMode )
		{
			Init();
			_color = Color.White;
			_brush = new TextureBrush( image, wrapMode );
			_type = FillType.Brush;
			_image = image;
			_wrapMode = wrapMode;
		}
		
		/// 
		/// Constructor that creates a  fill, using a user-supplied, custom
		/// .  The brush will be scaled to fit the destination screen object
		/// unless you manually change  to false;
		/// 
		/// The  to use for fancy fills.  Typically, this would
		/// be a  or a  class
		public Fill( Brush brush ) : this( brush, Default.IsScaled )
		{
		}
		
		/// 
		/// Constructor that creates a  fill, using a user-supplied, custom
		/// .  The brush will be scaled to fit the destination screen object
		/// according to the  parameter.
		/// 
		/// The  to use for fancy fills.  Typically, this would
		/// be a  or a  class
		/// Determines if the brush will be scaled to fit the bounding box
		/// of the destination object.  true to scale it, false to leave it unscaled
		public Fill( Brush brush, bool isScaled )
		{
			Init();
			_isScaled = isScaled;
			_color = Color.White;
			_brush = (Brush) brush.Clone();
			_type = FillType.Brush;
		}
		
		/// 
		/// Constructor that creates a  fill, using a user-supplied, custom
		/// .  This constructor will make the brush unscaled (see ),
		/// but it provides  and  parameters to control
		/// alignment of the brush with respect to the filled object.
		/// 
		/// The  to use for fancy fills.  Typically, this would
		/// be a  or a  class
		/// Controls the horizontal alignment of the brush within the filled object
		/// (see 
		/// Controls the vertical alignment of the brush within the filled object
		/// (see 
		public Fill( Brush brush, AlignH alignH, AlignV alignV )
		{
			Init();
			_alignH = alignH;
			_alignV = alignV;
			_isScaled = false;
			_color = Color.White;
			_brush = (Brush) brush.Clone();
			_type = FillType.Brush;
		}
		/// 
		/// The Copy Constructor
		/// 
		/// The Fill object from which to copy
		public Fill( Fill rhs )
		{
			_color = rhs._color;
			_secondaryValueGradientColor = rhs._color;
			if ( rhs._brush != null )
				_brush = (Brush) rhs._brush.Clone();
			else
				_brush = null;
			_type = rhs._type;
			_alignH = rhs.AlignH;
			_alignV = rhs.AlignV;
            _isScaled = rhs.IsScaled;
			_rangeMin = rhs._rangeMin;
			_rangeMax = rhs._rangeMax;
			_rangeDefault = rhs._rangeDefault;
			_gradientBM = null;
			if ( rhs._colorList != null )
				_colorList = (Color[]) rhs._colorList.Clone();
			else
				_colorList = null;
			if ( rhs._positionList != null )
			{
				_positionList = (float[]) rhs._positionList.Clone();
			}
			else
				_positionList = null;
			if ( rhs._image != null )
				_image = (Image) rhs._image.Clone();
			else
				_image = null;
			_angle = rhs._angle;
			_wrapMode = rhs._wrapMode;
		}
		/// 
		/// 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 Fill Clone()
		{
			return new Fill( this );
		}
		private void CreateBrushFromBlend( ColorBlend blend, float angle )
		{
			_angle = angle;
			_colorList = (Color[]) blend.Colors.Clone();
			_positionList = (float[]) blend.Positions.Clone();
			_brush = new LinearGradientBrush( new Rectangle( 0, 0, 100, 100 ),
				Color.Red, Color.White, angle );
			((LinearGradientBrush)_brush).InterpolationColors = blend;
		}
	#endregion
	#region Serialization
		/// 
		/// Current schema value that defines the version of the serialized file
		/// 
		public const int schema = 10;
		// schema changed to 2 with addition of rangeDefault
		// schema changed to 10 with version 5 refactor -- not backwards compatible
		/// 
		/// Constructor for deserializing objects
		/// 
		/// A  instance that defines the serialized data
		/// 
		/// A  instance that contains the serialized data
		/// 
		protected Fill( SerializationInfo info, StreamingContext context )
		{
			Init();
			// 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" );
			_color = (Color) info.GetValue( "color", typeof(Color) );
			_secondaryValueGradientColor = (Color) info.GetValue( "secondaryValueGradientColor", typeof( Color ) );
			//brush = (Brush) info.GetValue( "brush", typeof(Brush) );
			//brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof(BrushHolder) );
			_type = (FillType) info.GetValue( "type", typeof(FillType) );
			_isScaled = info.GetBoolean( "isScaled" );
			_alignH = (AlignH) info.GetValue( "alignH", typeof(AlignH) );
			_alignV = (AlignV) info.GetValue( "alignV", typeof(AlignV) );
			_rangeMin = info.GetDouble( "rangeMin" );
			_rangeMax = info.GetDouble( "rangeMax" );
			//BrushHolder brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof( BrushHolder ) );
			//brush = brush;
			_colorList = (Color[]) info.GetValue( "colorList", typeof(Color[]) );
			_positionList = (float[]) info.GetValue( "positionList", typeof(float[]) );
			_angle = info.GetSingle( "angle" );
			_image = (Image) info.GetValue( "image", typeof(Image) );
			_wrapMode = (WrapMode) info.GetValue( "wrapMode", typeof(WrapMode) );
			if ( _colorList != null && _positionList != null )
			{
				ColorBlend blend = new ColorBlend();
				blend.Colors = _colorList;
				blend.Positions = _positionList;
				CreateBrushFromBlend( blend, _angle );
			}
			else if ( _image != null )
			{
				_brush = new TextureBrush( _image, _wrapMode );
			}
			_rangeDefault = info.GetDouble( "rangeDefault" );
		}
		/// 
		/// 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( "color", _color );
			info.AddValue( "secondaryValueGradientColor", _secondaryValueGradientColor );
			//info.AddValue( "brush", brush );
			//info.AddValue( "brushHolder", brushHolder );
			info.AddValue( "type", _type );
			info.AddValue( "isScaled", _isScaled );
			info.AddValue( "alignH", _alignH );
			info.AddValue( "alignV", _alignV );
			info.AddValue( "rangeMin", _rangeMin );
			info.AddValue( "rangeMax", _rangeMax );
			//BrushHolder brushHolder = new BrushHolder();
			//brush = brush;
			//info.AddValue( "brushHolder", brushHolder );
			info.AddValue( "colorList", _colorList );
			info.AddValue( "positionList", _positionList );
			info.AddValue( "angle", _angle );
			info.AddValue( "image", _image );
			info.AddValue( "wrapMode", _wrapMode );
			info.AddValue( "rangeDefault", _rangeDefault );
		}
	#endregion
	#region Properties
		/// 
		/// The fill color.  This property is used as a single color to make a solid fill
		/// ( is ), or it can be used in 
		/// combination with  to make a
		/// 
		/// when  is  and 
		/// is null.
		/// 
		/// 
		public Color Color
		{
			get { return _color; }
			set { _color = value; }
		}
		/// 
		/// Gets or sets the secondary color for gradientByValue fills.
		/// 
		/// 
		/// This property is only applicable if the  is
		/// ,
		/// , or
		/// .  Once the gradient-by-value logic picks
		/// a color, a new gradient will be created using the SecondaryValueGradientColor, the
		/// resulting gradient-by-value color, and the angle setting for this
		/// . Use a value of Color.Empty to have
		/// a solid-color  resulting from a gradient-by-value
		/// .
		/// 
		public Color SecondaryValueGradientColor
		{
			get { return _secondaryValueGradientColor; }
			set { _secondaryValueGradientColor = value; }
		}
		/// 
		/// The custom fill brush.  This can be a , a
		/// , or a .  This property is
		/// only applicable if the  property is set
		/// to .
		/// 
		public Brush Brush
		{
			get { return _brush; }
			set { _brush = value; }
		}
		/// 
		/// Determines the type of fill, which can be either solid
		/// color () or a custom brush
		/// ().  See  for
		/// more information.
		/// 
		/// 
		public FillType Type
		{
			get { return _type; }
			set { _type = value; }
		}
		/// 
		/// This property determines the type of color fill. 
		/// Returns true if the  property is either
		///  or
		/// .  If set to true, this property
		/// will automatically set the  to
		/// .  If set to false, this property
		/// will automatically set the  to
		/// .  In order to get a regular
		/// solid-color fill, you have to manually set 
		/// to .
		/// 
		/// 
		/// 
		/// 
		public bool IsVisible
		{
			get { return _type != FillType.None; }
			set { _type = value ? ( _type == FillType.None ? FillType.Brush : _type ) : FillType.None; }
		}
		/// 
		/// Determines if the brush will be scaled to the bounding box
		/// of the filled object.  If this value is false, then the brush will only be aligned
		/// with the filled object based on the  and 
		/// properties.
		/// 
		public bool IsScaled
		{
			get { return _isScaled; }
			set { _isScaled = value; }
		}
		
		/// 
		/// Determines how the brush will be aligned with the filled object
		/// in the horizontal direction.  This value is a  enumeration.
		/// This field only applies if  is false.
		/// 
		/// 
		public AlignH AlignH
		{
			get { return _alignH; }
			set { _alignH = value; }
		}
		
		/// 
		/// Determines how the brush will be aligned with the filled object
		/// in the vertical direction.  This value is a  enumeration.
		/// This field only applies if  is false.
		/// 
		/// 
		public AlignV AlignV
		{
			get { return _alignV; }
			set { _alignV = value; }
		}
		/// 
		/// Returns a boolean value indicating whether or not this fill is a "Gradient-By-Value"
		/// type.  This is true for , ,
		/// or .
		/// 
		/// 
		/// The gradient by value fill method allows the fill color for each point or bar to
		/// be based on a value for that point (either X, Y, or Z in the .
		/// For example, assume a  class is defined with a linear gradient ranging from
		///  to  and the 
		/// is set to .  If  is set to 
		/// 100.0 and  is set to 200.0, then a point that has a Y value of
		/// 100 or less will be colored blue, a point with a Y value of 200 or more will be
		/// colored red, and a point between 100 and 200 will have a color based on a linear scale
		/// between blue and red.  Note that the fill color is always solid for any given point.
		/// You can use the Z value from  along with
		///  to color individual points according to some
		/// property that is independent of the X,Y point pair.
		/// 
		/// true if this is a Gradient-by-value type, false otherwise
		/// 
		/// 
		/// 
		public bool IsGradientValueType
		{
			get { return _type == FillType.GradientByX || _type == FillType.GradientByY ||
					_type == FillType.GradientByZ || _type == FillType.GradientByColorValue; }
		}
		/// 
		/// The minimum user-scale value for the gradient-by-value determination.  This defines
		/// the user-scale value for the start of the gradient.
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// A double value, in user scale unit
		public double RangeMin
		{
			get { return _rangeMin; }
			set { _rangeMin = value; }
		}
		/// 
		/// The maximum user-scale value for the gradient-by-value determination.  This defines
		/// the user-scale value for the end of the gradient.
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// A double value, in user scale unit
		public double RangeMax
		{
			get { return _rangeMax; }
			set { _rangeMax = value; }
		}
		/// 
		/// The default user-scale value for the gradient-by-value determination.  This defines the
		/// value that will be used when there is no point value available, or the actual point value
		/// is invalid.
		/// 
		/// 
		/// Note that this value, when defined, will determine the color that is used in the legend.
		/// If this value is set to double.MaxValue, then it remains "undefined."  In this case, the
		/// legend symbols will actually be filled with a color gradient representing the range of
		/// colors.
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// 
		/// A double value, in user scale unit
		public double RangeDefault
		{
			get { return _rangeDefault; }
			set { _rangeDefault = value; }
		}
	#endregion
	#region Methods
		/// 
		/// Create a fill brush using current properties.  This method will construct a brush based on the
		/// settings of , 
		/// and .  If
		///  is set to  and
		/// 
		/// is null, then a  will be created between the colors of
		///  and .
		/// 
		/// A rectangle that bounds the object to be filled.  This determines
		/// the start and end of the gradient fill.
		/// A  class representing the fill brush
		public Brush MakeBrush( RectangleF rect )
		{
			// just provide a default value for the valueFraction
			// return MakeBrush( rect, new PointPair( 0.5, 0.5, 0.5 ) );
			return MakeBrush( rect, null );
		}
		/// 
		/// Create a fill brush using current properties.  This method will construct a brush based on the
		/// settings of , 
		/// and .  If
		///  is set to  and
		/// 
		/// is null, then a  will be created between the colors of
		///  and .
		/// 
		/// A rectangle that bounds the object to be filled.  This determines
		/// the start and end of the gradient fill.
		/// The data value to be used for a value-based
		/// color gradient.  This is only applicable for ,
		///  or .
		/// A  class representing the fill brush
		public Brush MakeBrush( RectangleF rect, PointPair dataValue )
		{
			// get a brush
			if ( this.IsVisible && ( !_color.IsEmpty || _brush != null ) )
			{
				if ( rect.Height < 1.0F )
					rect.Height = 1.0F;
				if ( rect.Width < 1.0F )
					rect.Width = 1.0F;
					
				//Brush	brush;
				if ( _type == FillType.Brush )
				{
					return ScaleBrush( rect, _brush, _isScaled );
				}
				else if ( IsGradientValueType )
				{
					if ( dataValue != null )
					{
						if ( !_secondaryValueGradientColor.IsEmpty )
						{
							// Go ahead and create a new Fill so we can do all the scaling, etc.,
							// that is associated with a gradient
							Fill tmpFill = new Fill( _secondaryValueGradientColor,
									GetGradientColor( dataValue ), _angle );
							return tmpFill.MakeBrush( rect );
						}
						else
							return new SolidBrush( GetGradientColor( dataValue ) );
					}
					else if ( _rangeDefault != double.MaxValue )
					{
						if ( !_secondaryValueGradientColor.IsEmpty )
						{
							// Go ahead and create a new Fill so we can do all the scaling, etc.,
							// that is associated with a gradient
							Fill tmpFill = new Fill( _secondaryValueGradientColor,
									GetGradientColor( _rangeDefault ), _angle );
							return tmpFill.MakeBrush( rect );
						}
						else
							return new SolidBrush( GetGradientColor( _rangeDefault ) );
					}
					else
						return ScaleBrush( rect, _brush, true );
				}
				else
					return new SolidBrush( _color );
			}
			// Always return a suitable default
			return new SolidBrush( Color.White );
		}
		internal Color GetGradientColor( PointPair dataValue )
		{
			double val;
			if ( dataValue == null )
				val = _rangeDefault;
			else if ( _type == FillType.GradientByColorValue )
				val = dataValue.ColorValue;
			else if ( _type == FillType.GradientByZ )
				val = dataValue.Z;
			else if ( _type == FillType.GradientByY )
				val = dataValue.Y;
			else
				val = dataValue.X;
			return GetGradientColor( val );
		}
		internal Color GetGradientColor( double val )
		{
			double valueFraction;
			if ( Double.IsInfinity( val ) || double.IsNaN( val ) || val == PointPair.Missing )
				val = _rangeDefault;
			if ( _rangeMax - _rangeMin < 1e-20 || val == double.MaxValue )
				valueFraction = 0.5;
			else			
				valueFraction = ( val - _rangeMin ) / ( _rangeMax - _rangeMin );
			if ( valueFraction < 0.0 )
				valueFraction = 0.0;
			else if ( valueFraction > 1.0 )
				valueFraction = 1.0;
			if ( _gradientBM == null )
			{
				RectangleF rect = new RectangleF( 0, 0, 100, 1 );
				_gradientBM = new Bitmap( 100, 1 );
				Graphics gBM = Graphics.FromImage( _gradientBM );
				Brush tmpBrush = ScaleBrush( rect, _brush, true );
				gBM.FillRectangle( tmpBrush, rect );
			}
			return _gradientBM.GetPixel( (int) (99.9 * valueFraction), 0 );
		}
		private Brush ScaleBrush( RectangleF rect, Brush brush, bool isScaled )
		{
			if ( brush != null )
			{
				if ( brush is SolidBrush )
				{
					return (Brush) brush.Clone();
				}
				else if ( brush is LinearGradientBrush )
				{
					LinearGradientBrush linBrush = (LinearGradientBrush) brush.Clone();
					
					if ( isScaled )
					{
						linBrush.ScaleTransform( rect.Width / linBrush.Rectangle.Width,
							rect.Height / linBrush.Rectangle.Height, MatrixOrder.Append );
						linBrush.TranslateTransform( rect.Left - linBrush.Rectangle.Left,
							rect.Top - linBrush.Rectangle.Top, MatrixOrder.Append );
					}
					else
					{
						float	dx = 0,
								dy = 0;
						switch ( _alignH )
						{
						case AlignH.Left:
							dx = rect.Left - linBrush.Rectangle.Left;
							break;
						case AlignH.Center:
							dx = ( rect.Left + rect.Width / 2.0F ) - linBrush.Rectangle.Left;
							break;
						case AlignH.Right:
							dx = ( rect.Left + rect.Width ) - linBrush.Rectangle.Left;
							break;
						}
						
						switch ( _alignV )
						{
						case AlignV.Top:
							dy = rect.Top - linBrush.Rectangle.Top;
							break;
						case AlignV.Center:
							dy = ( rect.Top + rect.Height / 2.0F ) - linBrush.Rectangle.Top;
							break;
						case AlignV.Bottom:
							dy = ( rect.Top + rect.Height) - linBrush.Rectangle.Top;
							break;
						}
						linBrush.TranslateTransform( dx, dy, MatrixOrder.Append );
					}
					
					return linBrush;
					
				} // LinearGradientBrush
				else if ( brush is TextureBrush )
				{
					TextureBrush texBrush = (TextureBrush) brush.Clone();
					
					if ( isScaled )
					{
						texBrush.ScaleTransform( rect.Width / texBrush.Image.Width,
							rect.Height / texBrush.Image.Height, MatrixOrder.Append );
						texBrush.TranslateTransform( rect.Left, rect.Top, MatrixOrder.Append );
					}
					else
					{
						float	dx = 0,
								dy = 0;
						switch ( _alignH )
						{
						case AlignH.Left:
							dx = rect.Left;
							break;
						case AlignH.Center:
							dx = ( rect.Left + rect.Width / 2.0F );
							break;
						case AlignH.Right:
							dx = ( rect.Left + rect.Width );
							break;
						}
						
						switch ( _alignV )
						{
						case AlignV.Top:
							dy = rect.Top;
							break;
						case AlignV.Center:
							dy = ( rect.Top + rect.Height / 2.0F );
							break;
						case AlignV.Bottom:
							dy = ( rect.Top + rect.Height);
							break;
						}
						texBrush.TranslateTransform( dx, dy, MatrixOrder.Append );
					}
					
					return texBrush;
				}
				else // other brush type
				{
					return (Brush) brush.Clone();
				}
			}
			else
				// If they didn't provide a brush, make one using the fillcolor gradient to white
				return new LinearGradientBrush( rect, Color.White, _color, 0F );
		}
		/// 
		/// Fill the background of the  area, using the
		/// fill type from this .
		/// 
		/// 
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// 
		/// The  struct specifying the area
		/// to be filled
		public void Draw( Graphics g, RectangleF rect )
		{
			Draw( g, rect, null );
			/*
			if ( this.IsVisible )
			{
				using( Brush brush = this.MakeBrush( rect ) )
				{
					g.FillRectangle( brush, rect );
					//brush.Dispose();
				}
			}
			*/
		}
		/// 
		/// Fill the background of the  area, using the
		/// fill type from this .
		/// 
		/// 
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// 
		/// The  struct specifying the area
		/// to be filled
		/// The data value to be used in case it's a
		/// , , or
		///  .
		public void Draw( Graphics g, RectangleF rect, PointPair pt )
		{
			if ( this.IsVisible )
			{
				using ( Brush brush = this.MakeBrush( rect, pt ) )
				{
					g.FillRectangle( brush, rect );
				}
			}
		}
	#endregion
	}
}