/** \defgroup Utilities Utility classes */

/** @addtogroup Utilities
    @{
*/

/** @file CColor.h 
    \brief This file contains the declaration and implementation of
    the CColor class, a class that represents a color.
*/

#ifndef CCOLOR_H
#define CCOLOR_H


/**
   \brief This class represents a color.

   It holds four reel numbers meant to be clamped between 0 and 1.
*/
class CColor
{
 public:
  /**
     \brief This is the CColor simple constructor.
  */
  CColor(float r = 0, float g = 0, float b = 0, float a = 0)
    {
      red   = r;
      green = g;
      blue  = b;
      alpha = a;
    }

  /**
     \brief This operator returns a reference to the color
     component corresponding to the index.
  */
  float& operator[] (int i)
    {
      switch (i)
        {
        case 0: return red;
        case 1: return green;
        case 2: return blue;
        case 3: return alpha;
        default: POP_ILLEGAL("Invalid color index."); return red;
        }
    }

  /**
     \brief This const operator returns the color component 
     corresponding to the index.
  */
  float operator[] (int i) const
    {
      switch (i)
        {
        case 0: return red;
        case 1: return green;
        case 2: return blue;
        case 3: return alpha;
        default: POP_ILLEGAL("Invalid color index."); return red;
        }
    }

  /**
     \brief This function clamps the four components of the
     color between 0 and 1.
  */
  void Clamp(void)
    {
      if (red < 0)
        red = 0;
      else if (red > 1)
        red = 1;

      if (green < 0)
        green = 0;
      else if (green > 1)
        green = 1;

      if (blue < 0)
        blue = 0;
      else if (blue > 1)
        blue = 1;

      if (alpha < 0)
        alpha = 0;
      else if (alpha > 1)
        alpha = 1;
    }

  /**
     \brief This operator adds two colors.
     
     \f$ A + B = \left ( A_r+B_r , A_g+B_g , A_b+B_b , A_a+B_a \right ) \f$
  */
  inline CColor operator +(const CColor &c) const
    {
      return CColor(red + c.red, green + c.green,
                    blue + c.blue, alpha + c.alpha);
    }

  /**
     \brief This operator multiplies two colors.
     
     \f$ A * B = \left ( A_r*B_r , A_g*B_g , A_b*B_b , A_a*B_a \right ) \f$
  */
  inline CColor operator *(const CColor &c) const
    {
      return CColor(red * c.red, green * c.green,
                    blue * c.blue, alpha * c.alpha);
    }

  /**
     \brief This operator returns the product of a color and a scalar.

     \f$ k*A = \left ( k A_r , k A_g , k A_b, k A_a \right ) \f$
  */
  inline CColor operator *(float k) const
    {
      return CColor(k*red, k*green, k*blue, k*alpha);
    }

  // Same operator, but with the operands switched
  friend inline CColor operator *(float k, const CColor &c);


  /**
     \brief This operator is the same as + with an additionnal assignment.
  */
  inline CColor operator += (const CColor &c)
    {
      red   += c.red;
      green += c.green;
      blue  += c.blue;
      alpha += c.alpha;
      return (*this);
    }

  /**
     \brief This operator is the same as - with an additionnal assignment.
  */
  inline CColor operator -= (const CColor &c)
    {
      red   -= c.red;
      green -= c.green;
      blue  -= c.blue;
      alpha -= c.alpha;
      return (*this);
    }

  /**
     \brief This operator is the same as * with an additionnal assignment.
  */
  inline CColor operator *= (const CColor &c)
    {
      red   *= c.red;
      green *= c.green;
      blue  *= c.blue;
      alpha *= c.alpha;
      return (*this);
    }

  /**
     \brief This operator is the same as * with an additionnal assignment.
  */
  inline CColor operator *= (float k)
    {
      red   *= k;
      green *= k;
      blue  *= k;
      alpha *= k;
      return (*this);
    }

  friend inline std::ostream& operator <<(std::ostream& o,
                                          const CColor &c);
  
 private:
  float red;   /**< Red component of the color. */
  float green; /**< Green component of the color. */
  float blue;  /**< Blue component of the color. */
  float alpha; /**< Alpha component of the color. */
};

/**
   \brief This operator returns the product of a scalar and a color.

   \f$ A*k = \left ( k A_r , k A_g , k A_b , k A_a \right ) \f$
*/
inline CColor operator *(float k, const CColor &c)
{
  return CColor(k*c.red, k*c.green, k*c.blue, k*c.alpha);
}

/**
   \brief This operator prints the value of the color.
*/
inline std::ostream& operator << (std::ostream& o, const CColor &c)
{
  o << "( " << c.red << " , " << c.green 
    << " , " << c.blue << " , " << c.alpha << " )";
  return o;
}


#endif  // CCOLOR_H

/** @} */
