/*--------------------------------------------------------------------------
  Project:  Manual 2D Library - m2d
  File:     Color.h

  Copyright (C)2007-2009 Nintendo  All Rights Reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law. They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Revision: 1.10 $
 *-------------------------------------------------------------------------*/

#ifndef NTMV_M2D_COLOR_H_
#define NTMV_M2D_COLOR_H_

#include <ntmv/m2d/inlines.h>

namespace ntmv
{

namespace m2d
{

struct RVLGXColor
{
    u8  r,
        g, 
        b, 
        a;

};


struct Color: public RVLGXColor
{
public:
    /* ------------------------------------------------------------------------
            Constants
       ------------------------------------------------------------------------ */
    static const int ELEMENT_MIN         = 0;
    static const int ELEMENT_MAX         = 255;
    static const int ALPHA_MIN           = ELEMENT_MIN;
    static const int ALPHA_MAX           = ELEMENT_MAX;
    static const int ALPHA_OPACITY       = ALPHA_MAX;
    static const int ALPHA_TRANSPARENT   = ALPHA_MIN;

    static const u32 BLACK      = 0x000000FF;
    static const u32 GRAY       = 0x808080FF;
    static const u32 WHITE      = 0xFFFFFFFF;
    static const u32 RED        = 0xFF0000FF;
    static const u32 GREEN      = 0x00FF00FF;
    static const u32 BLUE       = 0x0000FFFF;
    static const u32 YELLOW     = 0xFFFF00FF;
    static const u32 MAGENTA    = 0xFF00FFFF;
    static const u32 CYAN       = 0x00FFFFFF;


    /* ------------------------------------------------------------------------
            Functions
       ------------------------------------------------------------------------ */
    //---- Constructor
                Color()
    {
        operator =(WHITE);
    }

    /*implicit*/Color(u32 color)
    {
        operator =(color);
    }

    /*implicit*/Color(const RVLGXColor& color)
    {
        operator =(color);
    }

                Color(
                    int red,
                    int green,
                    int blue,
                    int alpha = ALPHA_OPACITY )
    {
        Set(red, green, blue, alpha);
    }

    //---- Destructor
                ~Color()
    {
    }

    //---- Assignment operator
    Color&      operator =(u32 color)
    {
        ToU32ref() = color;
        return *this;
    }

    Color&      operator =(const RVLGXColor& color)
    {
        // Color is expected to be aligned.
        // Given a Broadway processor, processing will be delayed, but carried out normally, even if the color is unaligned.
        return operator =(*reinterpret_cast<const u32*>(&color));
    }

    //---- Type Conversion Operator
                operator u32() const
    {
        return ToU32ref();
    }

    //---- Explicit Type Conversion
    u32         ToU32() const
    {
        return ToU32ref();
    }

    //---- Accessor
    void        Set(
                    int red,
                    int green,
                    int blue,
                    int alpha = ALPHA_OPACITY )
    {
        r = static_cast<u8>(red);
        g = static_cast<u8>(green);
        b = static_cast<u8>(blue);
        a = static_cast<u8>(alpha);
    }

    void        Set(Color color)
    {
        operator =(color);
    }

    //---- The Four Arithmetic Operations
    const Color operator +(const Color& right) const
    {
        Color color(
            Min(this->r + right.r, ELEMENT_MAX),
            Min(this->g + right.g, ELEMENT_MAX),
            Min(this->b + right.b, ELEMENT_MAX),
            Min(this->a + right.a, ELEMENT_MAX)
        );
        return color;
    }

    const Color operator -(const Color& right) const
    {
        Color color(
            Max(this->r - right.r, ELEMENT_MIN),
            Max(this->g - right.g, ELEMENT_MIN),
            Max(this->b - right.b, ELEMENT_MIN),
            Max(this->a - right.a, ELEMENT_MIN)
        );
        return color;
    }

    const Color operator *(const Color& right) const
    {
        Color color(
            this->r * right.r / ELEMENT_MAX,
            this->g * right.g / ELEMENT_MAX,
            this->b * right.b / ELEMENT_MAX,
            this->a * right.a / ELEMENT_MAX
        );
        return color;
    }

    const Color operator /(const Color& right) const
    {
        Color color(
            (right.r != 0) ? Min(this->r * ELEMENT_MAX / right.r, ELEMENT_MAX): ELEMENT_MAX,
            (right.g != 0) ? Min(this->g * ELEMENT_MAX / right.g, ELEMENT_MAX): ELEMENT_MAX,
            (right.b != 0) ? Min(this->b * ELEMENT_MAX / right.b, ELEMENT_MAX): ELEMENT_MAX,
            (right.a != 0) ? Min(this->a * ELEMENT_MAX / right.a, ELEMENT_MAX): ELEMENT_MAX
        );
        return color;
    }

    const Color operator +(u32 rhs) const
    {
        const Color right = rhs;
        Color color(
            Min(this->r + right.r, ELEMENT_MAX),
            Min(this->g + right.g, ELEMENT_MAX),
            Min(this->b + right.b, ELEMENT_MAX),
            Min(this->a + right.a, ELEMENT_MAX)
        );
        return color;
    }

    const Color operator -(u32 rhs) const
    {
        const Color right = rhs;
        Color color(
            Max(this->r - right.r, ELEMENT_MIN),
            Max(this->g - right.g, ELEMENT_MIN),
            Max(this->b - right.b, ELEMENT_MIN),
            Max(this->a - right.a, ELEMENT_MIN)
        );
        return color;
    }

    const Color operator *(u32 rhs) const
    {
        const Color right = rhs;
        Color color(
            this->r * right.r / ELEMENT_MAX,
            this->g * right.g / ELEMENT_MAX,
            this->b * right.b / ELEMENT_MAX,
            this->a * right.a / ELEMENT_MAX
        );
        return color;
    }

    const Color operator /(u32 rhs) const
    {
        const Color right = rhs;
        Color color(
            (right.r != 0) ? Min(this->r * ELEMENT_MAX / right.r, ELEMENT_MAX): ELEMENT_MAX,
            (right.g != 0) ? Min(this->g * ELEMENT_MAX / right.g, ELEMENT_MAX): ELEMENT_MAX,
            (right.b != 0) ? Min(this->b * ELEMENT_MAX / right.b, ELEMENT_MAX): ELEMENT_MAX,
            (right.a != 0) ? Min(this->a * ELEMENT_MAX / right.a, ELEMENT_MAX): ELEMENT_MAX
        );
        return color;
    }

    //---- Increment, Decrement
    const Color operator ++()
    {
        (r >= ELEMENT_MAX) ? 0: r++;
        (g >= ELEMENT_MAX) ? 0: g++;
        (b >= ELEMENT_MAX) ? 0: b++;
        (a >= ELEMENT_MAX) ? 0: a++;

        return *this;
    }

    const Color operator ++(int)
    {
        Color old = *this;
        (r >= ELEMENT_MAX) ? 0: r++;
        (g >= ELEMENT_MAX) ? 0: g++;
        (b >= ELEMENT_MAX) ? 0: b++;
        (a >= ELEMENT_MAX) ? 0: a++;

        return old;
    }

    const Color operator --()
    {
        (r <= ELEMENT_MIN) ? 0: r--;
        (g <= ELEMENT_MIN) ? 0: g--;
        (b <= ELEMENT_MIN) ? 0: b--;
        (a <= ELEMENT_MIN) ? 0: a--;

        return *this;
    }

    const Color operator --(int)
    {
        Color old = *this;
        (r <= ELEMENT_MIN) ? 0: r--;
        (g <= ELEMENT_MIN) ? 0: g--;
        (b <= ELEMENT_MIN) ? 0: b--;
        (a <= ELEMENT_MIN) ? 0: a--;

        return old;
    }

    //---- Bitwise OR and AND
    const Color operator |(const Color& right) const
    {
        return (this->ToU32() | right.ToU32());
    }

    const Color operator &(const Color& right) const
    {
        return (this->ToU32() & right.ToU32());
    }

    const Color operator |(u32 right) const
    {
        return (this->ToU32() | right);
    }

    const Color operator &(u32 right) const
    {
        return (this->ToU32() & right);
    }


    Color& operator +=(const Color& rhs)
    {
        *this = *this + rhs;
        return *this;
    }
    Color& operator -=(const Color& rhs)
    {
        *this = *this - rhs;
        return *this;
    }
    Color& operator *=(const Color& rhs)
    {
        *this = *this * rhs;
        return *this;
    }
    Color& operator /=(const Color& rhs)
    {
        *this = *this / rhs;
        return *this;
    }

protected:
    /* ------------------------------------------------------------------------
            Functions
       ------------------------------------------------------------------------ */
    u32&        ToU32ref()
    {
        return *reinterpret_cast<u32*>(this);
    }
    const u32&  ToU32ref() const
    {
        return *reinterpret_cast<const u32*>(this);
    }

} ATTRIBUTE_ALIGN(4);



}   // namespace m2d
}   // namespace ntmv

#endif //  NTMV_M2D_COLOR_H_
