#ifndef __COLORS_H
#define __COLORS_H

/*@@@**************************************************************************
 * \file  colors
 * \date   Wed Feb 25 16:45:34 Local time zone must be set--see zic manual page 2009
 * \author Hernan Badino
 * \notes  
 *******************************************************************************
 ******************************************************************************/

/* INCLUDES */
#include <algorithm>
#include <inttypes.h>

/* CONSTANTS */

namespace VIC
{
    struct SRgb;

    /// RGBA Color
    struct SRgba
    {
        SRgba() {};
        SRgba ( const int f_r_i, 
                const int f_g_i, 
                const int f_b_i, 
                const int f_a_i = 255 )
        {
            r = std::max(std::min(255, f_r_i), 0);
            g = std::max(std::min(255, f_g_i), 0);
            b = std::max(std::min(255, f_b_i), 0);
            a = std::max(std::min(255, f_a_i), 0);
        }
        
        SRgba ( const SRgb & other,
                uint8_t      f_a_8ui = 255 );

        SRgba ( uint8_t f_r_8ui, 
                uint8_t f_g_8ui, 
                uint8_t f_b_8ui, 
                uint8_t f_a_8ui = 255 )
                : r(f_r_8ui),
                  g(f_g_8ui),
                  b(f_b_8ui),
                  a(f_a_8ui)
        {
        }

        void set (  const int f_r_i, 
                    const int f_g_i, 
                    const int f_b_i, 
                    const int f_a_i = 255 )
        {
            r = std::max(std::min(255, f_r_i), 0);
            g = std::max(std::min(255, f_g_i), 0);
            b = std::max(std::min(255, f_b_i), 0);
            a = std::max(std::min(255, f_a_i), 0);
        }

        const SRgba& operator =  ( const SRgb & other );

        bool operator == ( const SRgba & other ) const
        {
            return r == other.r && g == other.g && b == other.b  && a == other.a;
        }

        uint8_t  r;
        uint8_t  g;
        uint8_t  b;
        uint8_t  a;
    } ;

    /// RGB Color
    struct SRgb 
    {
        SRgb() {};
        SRgb ( const int f_r_i, 
               const int f_g_i, 
               const int f_b_i )
        {
            r = std::max(std::min(255, f_r_i), 0);
            g = std::max(std::min(255, f_g_i), 0);
            b = std::max(std::min(255, f_b_i), 0);
        }

        SRgb ( uint8_t f_r_8ui,
               uint8_t f_g_8ui, 
               uint8_t f_b_8ui )
                : r(f_r_8ui),
                  g(f_g_8ui),
                  b(f_b_8ui)
        {
        }
        
        SRgb ( SRgba other )
        {
            r = other.r;
            g = other.g;
            b = other.b;
        }

        const SRgb& operator = ( const SRgba & other )
        {
            r = other.r;
            g = other.g;
            b = other.b;
            return (*this);
        }
        
        bool operator == ( const SRgb & other ) const
        {
            return r == other.r && g == other.g && b == other.b;
        }        

        void set (  const int f_r_i, 
                    const int f_g_i, 
                    const int f_b_i )
            
        {
            r = std::max(std::min(255, f_r_i), 0);
            g = std::max(std::min(255, f_g_i), 0);
            b = std::max(std::min(255, f_b_i), 0);
        }

        uint8_t  r;
        uint8_t  g;
        uint8_t  b;
    };

    inline SRgba::SRgba ( const SRgb & other,
                          uint8_t      f_a_8ui )
    {
        r = other.r;
        g = other.g;
        b = other.b;
        a = f_a_8ui;
    }
    
    
    inline const SRgba&
    SRgba::operator = ( const SRgb & other )
    {
        r = other.r;
        g = other.g;
        b = other.b;
        a = 255;
        return *this;
    }
    
    /// HSV Color
    struct SHsv
    {
    public:
        
        SHsv() {};
        SHsv ( const float f_h_f, 
               const float f_s_f, 
               const float f_v_f )
        {
            /// Allow continous rotation of hue.
            if (f_h_f > 360)
                h = f_h_f - ((int)(f_h_f/360.f)) * 360.f;
            else if (f_h_f < 0)
                h = f_h_f + (1+(int)(-f_h_f/360.f)) * 360.f;
            else
                h = f_h_f;
            
            s = std::max(std::min(1.f, f_s_f), 0.f);
            v = std::max(std::min(1.f, f_v_f), 0.f);
        }
        
        const SHsv& operator = ( const SHsv & other )
        {
            h = other.h;
            s = other.s;
            v = other.v;
            return (*this);
        }
        
        bool operator == ( const SHsv & other ) const
        {
            return h == other.h && s == other.s && v == other.v;
        }

        void set (  const float f_h_f, 
                    const float f_s_f, 
                    const float f_v_f )
            
        {
            /// Allow continous rotation of hue.
            if (f_h_f > 360)
                h = f_h_f - ((int)(f_h_f/360.f)) * 360.f;
            else if (f_h_f < 0)
                h = f_h_f + (1+(int)(-f_h_f/360.f)) * 360.f;
             else
                h = f_h_f;
               
            s = std::max(std::min(1.f,   f_s_f), 0.f);
            v = std::max(std::min(1.f,   f_v_f), 0.f);
        }
        
        float h;
        float s;
        float v;
        
    };

    /// HSV Color
    struct SHsl
    {
    public:
        
        SHsl() {};
        SHsl ( const float f_h_f, 
               const float f_s_f, 
               const float f_l_f )
        {
            /// Allow continous rotation of hue.
            if (f_h_f > 360)
                h = f_h_f - ((int)(f_h_f/360.f)) * 360.f;
            else if (f_h_f < 0)
                h = f_h_f + (1+(int)(-f_h_f/360.f)) * 360.f;
            else
                h = f_h_f;

            s = std::max(std::min(1.f,   f_s_f), 0.f);
            l = std::max(std::min(1.f,   f_l_f), 0.f);
        }
        
        const SHsl& operator = ( const SHsl & other )
        {
            h = other.h;
            s = other.s;
            l = other.l;
            return (*this);
        }
        
        bool operator == ( const SHsl & other ) const
        {
            return h == other.h && s == other.s && l == other.l;
        }

        void set (  const float f_h_f, 
                    const float f_s_f, 
                    const float f_l_f )
            
        {
            /// Allow continous rotation of hue.
            if (f_h_f > 360)
                h = f_h_f - ((int)(f_h_f/360.f)) * 360.f;
            else if (f_h_f < 0)
                h = f_h_f + (1+(int)(-f_h_f/360.f)) * 360.f;
            else
                h = f_h_f;

            s = std::max(std::min(1.f,   f_s_f), 0.f);
            l = std::max(std::min(1.f,   f_l_f), 0.f);
        }
        
        float h;
        float s;
        float l;
        
    };

    class CColor
    {
    /// Standard Colors (value assigned in colors.cpp).
    public:        
        static const SRgb white;
        static const SRgb black;
        static const SRgb red;
        static const SRgb blue;
        static const SRgb green;

    public:
        static SRgb getRgbFromHsv ( const SHsv & f_color );

        static SRgb getRgbFromHsl ( const SHsl & f_color );

        static SHsv getHsvFromRgb ( const SRgb & f_color );

        static SHsl getHslFromRgb ( const SRgb & f_color );
        
    };

} /// Namespace VIC

#endif // __COLORS_H

/* ////////////  Version History ///////////////
 *  $Log: colors.h,v $
 *  Revision 1.2  2009/11/18 15:51:01  badino
 *  badino: documentation added. Some other global changes.
 *
 *//////////////////////////////////////////////
