#include "pixel.h"
#include "../math/function.h"

namespace sleek
{
    namespace math
    {
        pixel::pixel(u32 color) noexcept
        {
            blue =  (color >>  0) & 0xFF;
            green = (color >>  8) & 0xFF;
            red =   (color >> 16) & 0xFF;
            alpha = (color >> 24) & 0xFF;
        }

        pixel::pixel(const u8 r, const u8 g, const u8 b, const u8 a) noexcept
        {
            red = r;
            green = g;
            blue = b;
            alpha = a;
        }

        pixel::~pixel() noexcept
        {
        }

        /* ***************************************** */

        void pixel::set(const u8 r, const u8 g, const u8 b,const u8 a) noexcept
        {
            red = r;
            green = g;
            blue = b;
            alpha = a;
        }

        void pixel::setRed(const u8 i) noexcept
        {
            red = i;
        }

        void pixel::setGreen(const u8 i) noexcept
        {
            green = i;
        }

        void pixel::setBlue(const u8 i) noexcept
        {
            blue = i;
        }

        void pixel::setAlpha(const u8 i) noexcept
        {
            alpha = i;
        }

        /* ***************************************** */

        u8 pixel::getRed() const noexcept
        {
            return red;
        }

        u8 pixel::getGreen() const noexcept
        {
            return green;
        }

        u8 pixel::getBlue() const noexcept
        {
            return blue;
        }

        u8 pixel::getAlpha() const noexcept
        {
            return alpha;
        }

        pixel pixel::getInterpolated(const pixel &other, f32 d) const
        {
            d = math::clamp(d, 0.f, 1.f);
            const f32 inv = 1.0f - d;

            return {
                u8(other.red  *inv + red  *d),
                u8(other.green*inv + green*d),
                u8(other.blue *inv + blue *d),
                u8(other.alpha*inv + alpha*d)
            };
        }

        u8 pixel::getLuminaissance() const noexcept
        {
            return (red+green+blue)/3;
        }

        pixel pixel::monochrome() const noexcept
        {
            pixel tmp = monochrome_with_alpha();
            tmp.setAlpha(255);
            return tmp;;
        }

        pixel pixel::monochrome_with_alpha() const noexcept
        {
            u8 luminaissance = getLuminaissance();
            return pixel(luminaissance,luminaissance,luminaissance,alpha);
        }

        /* ***************************************** */

        vector3df pixel::HSV() const noexcept
        {
            math::vector3df hsv;

            f32 M = math::max(getRed(), getGreen(), getBlue());
            f32 m = math::min(getRed(), getGreen(), getBlue());
            f32 C = M - m;

            if(C == 0)
                hsv.x = 0;
            else if(M <= getRed())
                hsv.x = (getGreen() - getBlue()) / C;
            else if(M <= getGreen())
                hsv.x = (getBlue() - getRed()) / C + 2;
            else if(M <= getBlue())
                hsv.x = (getRed() - getGreen()) / C + 4;

            hsv.x *= 60;
            if(hsv.x < 0)
                hsv.x += 360;

            hsv.y = M;
            hsv.z = M == 0 ? 0 : C / hsv.y;

            return hsv;
        }
    }
}