#ifndef RGBA_H
#define RGBA_H

#include <cmath>
#include "colour_sensitivity.h"

namespace mimas {

  template <typename T>
    class rgba
    {
    protected:
      T b,g,r,a;
                
    public:
                
      rgba(void)
        {
          r=g=b=a=T();
        }
               
      template< class U >
                rgba(const rgba< U > &rhs)
                {
        r = (T)rhs.getRed();
        g = (T)rhs.getGreen();
        b = (T)rhs.getBlue();
        a = (T)rhs.getAlpha();
                }

      rgba( T _r, T _g, T _b, T _a = T() ):
      b(_b), g(_g), r(_r), a(_a)
        {
        }
   
   template< typename U >
   explicit rgba(const U &val)
        {
          r=(T)val;
          g=(T)val;
          b=(T)val;
          a=T();
        }
      
                //inline functions to avoid overhead of the call,
                //especially used for convert_trait
      inline T getRed(void) const
        {
          return r;
        }

      inline T getGreen(void) const
        {
          return g;
        }

      inline T getBlue(void) const
        {
          return b;
        }
      
      inline T getAlpha(void) const
        {
          return a;
        }
      

      void setRed(T val)
        {
          r=val;
        }
      
      void setGreen(T val)
        {
          g=val;
        }
      
      void setBlue(T val)
        {
          b=val;
        }
      
      void setAlpha(T val)
        {
          a=val;
        }
      
      void set(T val)
        {
          r=g=b=a=val;
        }


      //mixes the 2 colors according to the ammount of transparency
      void overlay(T r_,T g_,T b_,T a_)
        {
          //assumption that alpha take a value between 0 and 255
          //should be corrected according to the type T
          r = ((255 - a_)* r + a_ * r_)/255;
          g = ((255 - a_)* g + a_ * g_)/255;
          b = ((255 - a_)* b + a_ * b_)/255;
        }
      
      //overload casting to double
      operator double(void) const
      {
        return
          SENSITIVITY_RED * r + SENSITIVITY_GREEN * g + SENSITIVITY_BLUE * b;
      }

      operator float(void) const
      {
        return
          SENSITIVITY_RED * r + SENSITIVITY_GREEN * g + SENSITIVITY_BLUE * b;
      }

      operator short int(void) const
      {
        const int
          rwgt = (int)( SENSITIVITY_RED   * 65536 ),
          gwgt = (int)( SENSITIVITY_GREEN * 65536 ),
          bwgt = (int)( SENSITIVITY_BLUE  * 65536 );
        return (short int)( ( rwgt * r + gwgt * g + bwgt * b ) >> 16 );
      }

      operator int(void) const
      {
        return (int)operator double();
      }

      //overload casting to unsigned char
      operator unsigned char(void) const
      {
        const int
          rwgt = (int)( SENSITIVITY_RED   * 65536 ),
          gwgt = (int)( SENSITIVITY_GREEN * 65536 ),
          bwgt = (int)( SENSITIVITY_BLUE  * 65536 );
        return (unsigned char)( ( rwgt * r + gwgt * g + bwgt * b ) >> 16 );
      }

      /// Equality of two pixels
      bool operator==(const rgba<T> &rhs)
      {
        return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a;
      }

      /// Check for unequal pixels.
      bool operator!=(const rgba<T> &rhs)
      {
        return !(r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a);
      }

      rgba< T > operator+( const rgba< T > &o ) const
      {
        return rgba< T >( r + o.r, g + o.g, b + o.b );
      }

      rgba< T > operator-( const rgba< T > &o ) const
      {
        return rgba< T >( r - o.r, g - o.g, b - o.b );
      }

      rgba< T > &operator+=( const rgba< T > &o )
      {
        r += o.r; g += o.g; b += o.b;
        return *this;
      }

      rgba< T > &operator-=( const rgba< T > &o )
      {
        r -= o.r; g -= o.g; b -= o.b;
        return *this;
      }

      double getHue(void) const;///< returns number in the range 0-360
      double getSaturation(void) const; ///< returns saturation between 0 and 1.0
      
    };
 
}

#include "rgba.tcc"

#endif