// ------------------------------------------------------------------------
/*
	author: Jaap Suter
   
	Copyright (C) Electronic Arts Canada Inc. 2002.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#include "reveal/color.h"
#include "reveal/stdint.h"
#include "reveal/impl/util.h"

#include <assert.h>

namespace Reveal {


// -------------------------------------------------------------------------------
float& Color::operator [] ( size_t i )
{ 
	switch ( i ) 
	{ 
		case 0: return mA; break; 
		case 1: return mR; break; 
		case 2: return mG; break; 
		case 3: return mB; break; 
		default: assert( false ); 
				 return mA; // For release builds;
	} 
}

// -------------------------------------------------------------------------------
float Color::operator [] ( size_t i ) const
{ 
	switch ( i ) 
	{ 
		case 0: return mA; break; 
		case 1: return mR; break; 
		case 2: return mG; break; 
		case 3: return mB; break; 
		default: assert( false ); 
				 return mA; // For release builds;	
	} 
}

// -------------------------------------------------------------------------------
Reveal::uint32_t Color::Get32BitARGB() const 
{
	return (static_cast< Reveal::uint32_t >( mA * 255.0f ) << 24) |
		   (static_cast< Reveal::uint32_t >( mR * 255.0f ) << 16) |
		   (static_cast< Reveal::uint32_t >( mG * 255.0f ) <<  8) |
		   (static_cast< Reveal::uint32_t >( mB * 255.0f ) <<  0);

}

// -------------------------------------------------------------------------------
void Color::SetFromHSV( float h, float s, float v )
{
	h *= 360.0f;
	
	if ( s == 0.0 || h == -1.0 ) // If S equals zero, we're totally unsaturated, thus grey, so R,G and B all equal value 
	{ 
		mR = mG = mB = v; 
		return; 
	} 

	float hTemp = h / 60.0f; 
	int i = static_cast< int >( hTemp );		 // What sector are we in;
	float f = hTemp - static_cast< float >( i ); // How far through the sector 
	float p = v * ( 1 - s ); 
	float q = v * ( 1 - s * f ); 
	float t = v * ( 1 - s * ( 1 - f ) ); 

	switch( i )  
	{ 
		case 0: { mR = v; mG =  t; mB =  p; break; } 
		case 1: { mR =  q; mG = v; mB =  p; break; } 
		case 2: { mR =  p; mG = v; mB =  t; break; } 
		case 3: { mR =  p; mG =  q; mB = v; break; }  
		case 4: { mR =  t; mG =  p; mB = v; break; } 
		case 5: { mR = v; mG =  p; mB =  q; break; } 
	} 
}

// -------------------------------------------------------------------------------
void Color::ToHSV( float& h, float& s, float& v ) const
{
	float min = mR, max = mR; 
	enum { RED, GREEN, BLUE } maxVal = RED; 
	
	if ( mG > max ) { max = mG; maxVal = GREEN; } 
	if ( mB > max ) { max = mB; maxVal = BLUE;  }  
	if ( mG < min ) min = mG; 
	if ( mB < min ) min = mB;  

	float delta = max - min; 
	
	v = max;  
	if ( max != 0 )  
	{
		s = delta / max;  
	}
	else
	{ 
		h = 0; 
		s = 0; 
		return; 
	} 

	if ( s == 0.0f ) 
	{ 
		h = 0; 
		return; 
	} 
	else 
	{  
		switch ( maxVal ) 
		{ 
			case RED:   { h =	  ( mG - mB ) / delta; break; }     // yel < h < mag 
			case GREEN: { h = 2 + ( mB - mR ) / delta; break; }     // cyan < h < yel 
			case BLUE:  { h = 4 + ( mR - mG ) / delta; break; }     // mag < h < cyan 
		} 
	} 
	
	h *= 60; 
	if ( h < 0 ) h += 360;     
	h /= 360.0f;
}

// -------------------------------------------------------------------------------
namespace Util 
{
	size_t ToString( const Color& c, char* buffer, size_t size )
	{
	    char* s = buffer;
		for ( size_t i = 0; i < 4; ++i )
		{
			const size_t length = ToString( c[ i ], s, size );
			assert( size >= length );
			size -= length;
			s += length;
	
			if ( size >= 1 )
			{
				*s++ = ' ';
				--size;
			}
		}

		return s - buffer;
	}
} // Namespace Util

} // Namespace Reveal;

