using System;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DrawGraph
{
	/// 
	/// Hue-Saturation-Brightness Color class to store a color value, and to manage conversions
	/// to and from RGB colors in the  struct.
	/// 
	/// 
	/// This class is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
	/// This struct stores the hue, saturation, brightness, and alpha values internally as
	///  values from 0 to 255.  The hue represents a fraction of the 360 degrees
	/// of color space available. The saturation is the color intensity, where 0 represents gray scale
	/// and 255 is the most colored.  For the brightness, 0 represents black and 255
	/// represents white.
	/// 
	[Serializable]
	public struct HSBColor
	{
		/// 
		/// The color hue value, ranging from 0 to 255.
		/// 
		/// 
		/// This property is actually a rescaling of the 360 degrees on the color wheel to 255
		/// possible values.  Therefore, every 42.5 units is a new sector, with the following
		/// convention:  red=0, yellow=42.5, green=85, cyan=127.5, blue=170, magenta=212.5
		/// 
		public byte H;
		/// 
		/// The color saturation (intensity) value, ranging from 0 (gray scale) to 255 (most colored).
		/// 
		public byte S;
		/// 
		/// The brightness value, ranging from 0 (black) to 255 (white).
		/// 
		public byte B;
		/// 
		/// The alpha value (opacity), ranging from 0 (transparent) to 255 (opaque).
		/// 
		public byte A;
		/// 
		/// Constructor to load an  struct from hue, saturation and
		/// brightness values
		/// 
		/// The color hue value, ranging from 0 to 255
		/// The color saturation (intensity) value, ranging from 0 (gray scale)
		/// to 255 (most colored)
		/// The brightness value, ranging from 0 (black) to 255 (white)
		public HSBColor( int h, int s, int b )
		{
			this.H = (byte)h;
			this.S = (byte)s;
			this.B = (byte)b;
			this.A = 255;
		}
		/// 
		/// Constructor to load an  struct from hue, saturation,
		/// brightness, and alpha values
		/// 
		/// The color hue value, ranging from 0 to 255
		/// The color saturation (intensity) value, ranging from 0 (gray scale)
		/// to 255 (most colored)
		/// The brightness value, ranging from 0 (black) to 255 (white)
		/// The alpha value (opacity), ranging from 0 (transparent) to
		/// 255 (opaque)
		public HSBColor( int a, int h, int s, int b )
			: this( h, s, b )
		{
			this.A = (byte)a;
		}
		/// 
		/// Constructor to load an  struct from a system
		///  struct.
		/// 
		/// An rgb  struct containing the equivalent
		/// color you want to generate
		public HSBColor( Color color )
		{
			this = FromRGB( color );
		}
		/// 
		/// Implicit conversion operator to convert directly from an  to
		/// a  struct.
		/// 
		/// The  struct to be converted
		/// An equivalent  struct that can be used in the GDI+
		/// graphics library
		public static implicit operator Color( HSBColor hsbColor )
		{
			return ToRGB( hsbColor );
		}
		/// 
		/// Convert an  value to an equivalent  value.
		/// 
		/// 
		/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
		/// 
		/// The  struct to be converted
		/// An equivalent  struct, compatible with the GDI+ library
		public static Color ToRGB( HSBColor hsbColor )
		{
			Color rgbColor = Color.Black;
			// Determine which sector of the color wheel contains this hue
			// hsbColor.H ranges from 0 to 255, and there are 6 sectors, so 42.5 per sector
			int sector = (int) Math.Floor( (double) hsbColor.H / 42.5 );
			// Calculate where the hue lies within the sector for interpolation purpose
			double fraction = (double) hsbColor.H / 42.5 - (double) sector;
			double sFrac = (double) hsbColor.S / 255.0;
			byte p = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac ) ) + 0.5);
			byte q = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac * fraction ) ) + 0.5);
			byte t = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac * ( 1.0 - fraction ) ) ) + 0.5);
			switch( sector )
			{
				case 0:			// red - yellow
					rgbColor = Color.FromArgb( hsbColor.A, hsbColor.B, t, p );
					break;
				case 1:			// yellow - green
					rgbColor = Color.FromArgb( hsbColor.A, q, hsbColor.B, p );
					break;
				case 2:			// green - cyan
					rgbColor = Color.FromArgb( hsbColor.A, p, hsbColor.B, t );
					break;
				case 3:			// cyan - blue
					rgbColor = Color.FromArgb( hsbColor.A, p, q, hsbColor.B );
					break;
				case 4:			// blue - magenta
					rgbColor = Color.FromArgb( hsbColor.A, t, p, hsbColor.B );
					break;
				case 5:
				default:		// magenta - red
					rgbColor = Color.FromArgb( hsbColor.A, hsbColor.B, p, q );
					break;
			}
			return rgbColor;
		}
		/// 
		/// Convert this  value to an equivalent  value.
		/// 
		/// 
		/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
		/// 
		/// An equivalent  struct, compatible with the GDI+ library
		public Color ToRGB()
		{
			return ToRGB( this );
		}
			
		/// 
		/// Convert a  value to an equivalent  value.
		/// 
		/// 
		/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
		/// 
		/// An equivalent  struct
		public HSBColor FromRGB()
		{
			return FromRGB( this );
		}
		/// 
		/// Convert a  value to an equivalent  value.
		/// 
		/// 
		/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
		/// 
		/// The  struct to be converted
		/// An equivalent  struct
		public static HSBColor FromRGB( Color rgbColor )
		{
			double r = (double) rgbColor.R / 255.0;
			double g = (double) rgbColor.G / 255.0;
			double b = (double) rgbColor.B / 255.0;
			double min = Math.Min( Math.Min( r, g ), b );
			double max = Math.Max( Math.Max( r, g ), b );
			HSBColor hsbColor = new HSBColor( rgbColor.A, 0, 0, 0 );
			hsbColor.B = (byte) ( max * 255.0 + 0.5 );
			double delta = max - min;
			if ( max != 0.0 )
			{
				hsbColor.S = (byte) ( delta / max * 255.0 + 0.5 );
			}
			else
			{
				hsbColor.S = 0;
				hsbColor.H = 0;
				return hsbColor;
			}
			double h;
			if ( r == max )
				h = ( g - b ) / delta;		// between yellow & magenta
			else if ( g == max )
				h = 2 + ( b - r ) / delta;	// between cyan & yellow
			else
				h = 4 + ( r - g ) / delta;	// between magenta & cyan
			hsbColor.H = (byte) ( h * 42.5 );	
			if ( hsbColor.H < 0 )
				hsbColor.H += 255;
			return hsbColor;
		}
	
	}
}