// https://stackoverflow.com/a/14733008

#include "colors.h"

inline int rgbcmp(const RgbColor* a, const RgbColor* b) {
    return memcmp(a, b, sizeof(RgbColor));
}

inline int hsvcmp(const HsvColor* a, const HsvColor* b) {
    return memcmp(a, b, sizeof(HsvColor));
}

void hsv2rgb(const HsvColor* hsv, RgbColor* rgb) {
    if(hsv->s == 0) {
        rgb->r = hsv->v;
        rgb->g = hsv->v;
        rgb->b = hsv->v;
        return;
    }

    uint8_t region = hsv->h / 43;
    uint8_t remainder = (hsv->h - (region * 43)) * 6;

    uint8_t p = (hsv->v * (255 - hsv->s)) >> 8;
    uint8_t q = (hsv->v * (255 - ((hsv->s * remainder) >> 8))) >> 8;
    uint8_t t = (hsv->v * (255 - ((hsv->s * (255 - remainder)) >> 8))) >> 8;

    switch(region) {
    case 0:
        rgb->r = hsv->v;
        rgb->g = t;
        rgb->b = p;
        break;
    case 1:
        rgb->r = q;
        rgb->g = hsv->v;
        rgb->b = p;
        break;
    case 2:
        rgb->r = p;
        rgb->g = hsv->v;
        rgb->b = t;
        break;
    case 3:
        rgb->r = p;
        rgb->g = q;
        rgb->b = hsv->v;
        break;
    case 4:
        rgb->r = t;
        rgb->g = p;
        rgb->b = hsv->v;
        break;
    default:
        rgb->r = hsv->v;
        rgb->g = p;
        rgb->b = q;
        break;
    }
}

void rgb2hsv(const RgbColor* rgb, HsvColor* hsv) {
    uint8_t rgbMin = rgb->r < rgb->g ? (rgb->r < rgb->b ? rgb->r : rgb->b) :
                                       (rgb->g < rgb->b ? rgb->g : rgb->b);
    uint8_t rgbMax = rgb->r > rgb->g ? (rgb->r > rgb->b ? rgb->r : rgb->b) :
                                       (rgb->g > rgb->b ? rgb->g : rgb->b);

    hsv->v = rgbMax;
    if(hsv->v == 0) {
        hsv->h = 0;
        hsv->s = 0;
        return;
    }

    hsv->s = 255 * ((long)rgbMax - (long)rgbMin) / hsv->v;
    if(hsv->s == 0) {
        hsv->h = 0;
        return;
    }

    if(rgbMax == rgb->r) {
        hsv->h = 0 + 43 * (rgb->g - rgb->b) / (rgbMax - rgbMin);
    } else if(rgbMax == rgb->g) {
        hsv->h = 85 + 43 * (rgb->b - rgb->r) / (rgbMax - rgbMin);
    } else {
        hsv->h = 171 + 43 * (rgb->r - rgb->g) / (rgbMax - rgbMin);
    }
}
