#include "common.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include "colormod.h"
#include "image.h"

static uint64_t     mod_count = 0;

ImlibColorModifier *
__imlib_CreateCmod(void)
{
   ImlibColorModifier *cm;
   int                 i;

   cm = malloc(sizeof(ImlibColorModifier));
   if (!cm)
      return NULL;
   cm->modification_count = mod_count;
   for (i = 0; i < 256; i++)
     {
        cm->red_mapping[i] = (uint8_t) i;
        cm->green_mapping[i] = (uint8_t) i;
        cm->blue_mapping[i] = (uint8_t) i;
        cm->alpha_mapping[i] = (uint8_t) i;
     }
   return cm;
}

void
__imlib_FreeCmod(ImlibColorModifier * cm)
{
   free(cm);
}

void
__imlib_CmodChanged(ImlibColorModifier * cm)
{
   mod_count++;
   cm->modification_count = mod_count;
}

void
__imlib_CmodSetTables(ImlibColorModifier * cm,
                      uint8_t * r, uint8_t * g, uint8_t * b, uint8_t * a)
{
   int                 i;

   for (i = 0; i < 256; i++)
     {
        if (r)
           cm->red_mapping[i] = r[i];
        if (g)
           cm->green_mapping[i] = g[i];
        if (b)
           cm->blue_mapping[i] = b[i];
        if (a)
           cm->alpha_mapping[i] = a[i];
     }
   __imlib_CmodChanged(cm);
}

void
__imlib_CmodReset(ImlibColorModifier * cm)
{
   int                 i;

   for (i = 0; i < 256; i++)
     {
        cm->red_mapping[i] = (uint8_t) i;
        cm->green_mapping[i] = (uint8_t) i;
        cm->blue_mapping[i] = (uint8_t) i;
        cm->alpha_mapping[i] = (uint8_t) i;
     }
   __imlib_CmodChanged(cm);
}

void
__imlib_DataCmodApply(uint32_t * data, int w, int h, int jump,
                      ImlibImageFlags * fl, ImlibColorModifier * cm)
{
   int                 x, y;
   uint32_t           *p;

   /* We might be adding alpha */
   if (fl && !(*fl & F_HAS_ALPHA))
     {
        p = data;
        for (y = 0; y < h; y++)
          {
             for (x = 0; x < w; x++)
               {
                  R_VAL(p) = R_CMOD(cm, R_VAL(p));
                  G_VAL(p) = G_CMOD(cm, G_VAL(p));
                  B_VAL(p) = B_CMOD(cm, B_VAL(p));
                  p++;
               }
             p += jump;
          }
        return;
     }

   p = data;
   for (y = 0; y < h; y++)
     {
        for (x = 0; x < w; x++)
          {
             R_VAL(p) = R_CMOD(cm, R_VAL(p));
             G_VAL(p) = G_CMOD(cm, G_VAL(p));
             B_VAL(p) = B_CMOD(cm, B_VAL(p));
             A_VAL(p) = A_CMOD(cm, A_VAL(p));
             p++;
          }
        p += jump;
     }
}

void
__imlib_CmodGetTables(ImlibColorModifier * cm, uint8_t * r, uint8_t * g,
                      uint8_t * b, uint8_t * a)
{
   if (r)
      memcpy(r, cm->red_mapping, (256 * sizeof(uint8_t)));
   if (g)
      memcpy(g, cm->green_mapping, (256 * sizeof(uint8_t)));
   if (b)
      memcpy(b, cm->blue_mapping, (256 * sizeof(uint8_t)));
   if (a)
      memcpy(a, cm->alpha_mapping, (256 * sizeof(uint8_t)));
}

void
__imlib_CmodModBrightness(ImlibColorModifier * cm, double v)
{
   int                 i, val, val2;

   val = (int)(v * 255);
   for (i = 0; i < 256; i++)
     {
        val2 = (int)cm->red_mapping[i] + val;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->red_mapping[i] = (uint8_t) val2;

        val2 = (int)cm->green_mapping[i] + val;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->green_mapping[i] = (uint8_t) val2;

        val2 = (int)cm->blue_mapping[i] + val;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->blue_mapping[i] = (uint8_t) val2;

        val2 = (int)cm->alpha_mapping[i] + val;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->alpha_mapping[i] = (uint8_t) val2;
     }
}

void
__imlib_CmodModContrast(ImlibColorModifier * cm, double v)
{
   int                 i, val2;

   for (i = 0; i < 256; i++)
     {
        val2 = (int)(((double)cm->red_mapping[i] - 127) * v) + 127;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->red_mapping[i] = (uint8_t) val2;

        val2 = (int)(((double)cm->green_mapping[i] - 127) * v) + 127;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->green_mapping[i] = (uint8_t) val2;

        val2 = (int)(((double)cm->blue_mapping[i] - 127) * v) + 127;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->blue_mapping[i] = (uint8_t) val2;

        val2 = (int)(((double)cm->alpha_mapping[i] - 127) * v) + 127;
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->alpha_mapping[i] = (uint8_t) val2;
     }
}

void
__imlib_CmodModGamma(ImlibColorModifier * cm, double v)
{
   int                 i, val2;

   if (v < 0.01)
      v = 0.01;
   for (i = 0; i < 256; i++)
     {
        val2 = (int)(pow(((double)cm->red_mapping[i] / 255), (1 / v)) * 255);
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->red_mapping[i] = (uint8_t) val2;

        val2 = (int)(pow(((double)cm->green_mapping[i] / 255), (1 / v)) * 255);
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->green_mapping[i] = (uint8_t) val2;

        val2 = (int)(pow(((double)cm->blue_mapping[i] / 255), (1 / v)) * 255);
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->blue_mapping[i] = (uint8_t) val2;

        val2 = (int)(pow(((double)cm->alpha_mapping[i] / 255), (1 / v)) * 255);
        if (val2 < 0)
           val2 = 0;
        if (val2 > 255)
           val2 = 255;
        cm->alpha_mapping[i] = (uint8_t) val2;
     }
}

#if 0
void
__imlib_ImageCmodApply(ImlibImage * im, ImlibColorModifier * cm)
{
   __imlib_DataCmodApply(im->data, im->w, im->h, 0, cm);
}
#endif
