/*This file contains the colorlist class, to save a list of
  RGB colors to exclude from the motion check*/

/*Maybe i should be proud of this, this is a classical!
  I always said "Who needs C++?"
  >;>>> */


#include "defs.h"
#include <stdlib.h>
#include "voidlist.h"
#include <math.h>
/*We include the List object motherclass*/
/*And we need sqrt*/

/* Private structures --------------------------------------------------*/


struct colorindex {
   int color;
};
/* Our Identification (List Index) Structure */

struct colordata {
   int red;
   int green;
   int blue;
   int width;
};
/* Our List Data Structure*/


/* Public structures --------------------------------------------------*/

struct colorlist{
   struct voidlist *liste;
};

/*The structure colorlist, public itself, but members are private*/
/*Since my new class system the members are taken from class voidlist,
  so even unknown to this very file ;) */

/* Private functions --------------------------------------------------*/

int colorlist_greater (struct voidident *vfrst, struct voidident *vscnd) {
   struct colorindex *frst,*scnd;
   frst=(struct colorindex*)vfrst;
   scnd=(struct colorindex*)vscnd;
   return ( (frst->color>scnd->color) );
}

int colorlist_equality (struct voidident *vfrst, struct voidident *vscnd) {
   struct colorindex *frst,*scnd;
   frst=(struct colorindex*)vfrst;
   scnd=(struct colorindex*)vscnd;
   return ( (frst->color==scnd->color) );
}

int colorlist_freecontent (struct voidident *videntity, struct voiddata *vdata){
   struct colorindex *identity;
   struct colordata *data;
   identity=(struct colorindex*)videntity;
   data=(struct colordata*)vdata;
   free (identity);
   free (data);
   return 0;
}

/* Function for comparisation of Index values, and to free the memory of
   the data of our list members. To tell the upper voidlist class.
   I think this is some kind of workaround since ident and data are no
   object classes but ordinary var structs */


/* Public functions ---------------------------------------------------*/

struct colorlist* colorlist_new() {
/*A constructor*/
   struct colorlist* newcolor;

   newcolor=(struct colorlist*)malloc(sizeof(struct colorlist));
   if (!newcolor) return NULL;
   newcolor->liste=voidlist_new();
   if (!newcolor->liste) {
      free (newcolor);
      return NULL;
   }


   return newcolor;
}

/* ------------------------------------------------------------------- */

int colorlist_remcolor (struct colorlist* list,int color){
/*Removes a color from the list, 0 on success, 1 on not found, -1 on error*/
   struct colorindex identity;

   if (!list) return -1;

   identity.color=color;
   return voidlist_remitem(	list->liste,
   				(struct voidident*)&identity,
   				colorlist_greater,colorlist_equality,
				colorlist_freecontent);

}

/* ------------------------------------------------------------------- */

int colorlist_kill(struct colorlist* list) {
/*A destructor*/
   voidlist_kill(list->liste,colorlist_freecontent);
   free(list);
   return 0;
}

/* ------------------------------------------------------------------- */

int colorlist_setcolor (struct colorlist* list,int color,int red, int green, int blue, int width) {
/*Sets a color on the list to specified value
  0 added, 1, changed, -1 error
*/
   struct colorindex *identity;
   struct colordata *data;

   if (!list) return -1;

   identity=(struct colorindex*)malloc(sizeof(struct colorindex));
   if (!identity) return -1;
   data=(struct colordata*)malloc(sizeof(struct colordata));
   if (!data) {
      free (identity);
      return -1;
   }
   /*We have to create a special structure in memory to add to our list */

   identity->color=color;
   data->red=red;
   data->green=green;
   data->blue=blue;
   data->width=width;
   /*And fill them with data*/

   return voidlist_additem (	list->liste,
   				(struct voidident*)identity,
   				(struct voiddata*)data,
   				colorlist_greater,colorlist_equality,
				colorlist_freecontent);
   /*And include this data in the list structure*/

}
/* ------------------------------------------------------------------- */

int colorlist_addcolor (struct colorlist* list,int red, int green, int blue, int width) {
/*Adds a color to the end of the list
  0 success, -1 error
*/
   struct colorindex *identity;
   struct colordata *data;
   int color;

   if (!list) return -1;

   identity=(struct colorindex*)voidlist_last(list->liste);
   if (identity==NULL) {
      color=0;
   } else {
      color=identity->color+1;
   }
   /* We calculate the position which should be the last, but maybe is also the 1st */
   identity=(struct colorindex*)malloc(sizeof(struct colorindex));
   if (!identity) return -1;
   data=(struct colordata*)malloc(sizeof(struct colordata));
   if (!data) {
      free (identity);
      return -1;
   }
   /*We have to create a special structure in memory to add to our list */

   identity->color=color;
   data->red=red;
   data->green=green;
   data->blue=blue;
   data->width=width;
   /*And fill them with data*/

   return voidlist_additem (	list->liste,
   				(struct voidident*)identity,
   				(struct voiddata*)data,
   				colorlist_greater,colorlist_equality,
				colorlist_freecontent);
   /*And include this data in the list structure*/

}

/* ------------------------------------------------------------------- */

int colorlist_getvalue (struct colorlist* list, int red, int green, int blue) {
/*Gives back the alphablend value of a color.
  This has to do with color exclusion. if the specified color is "near" a
  "excluded color" (within "width") this will be close to 0 to let the
  caller know to ignore this color.
  if the color in not near any of the excluded, it has to be calculated and
  this value is up to 255 */
   struct colorindex identity;
   struct colordata *data;
   double actual,sum;
   int alpha;

   if (!list) return 255;

   identity.color=0;
   data=(struct colordata*)voidlist_item (	list->liste,
   						(struct voidident*)&identity,
   						colorlist_greater,colorlist_equality);
   sum=1.;
   while (data!=NULL) {
      /*Go through all exclude colors*/
      actual=sqrt(	 ((red - data->red)*(red - data->red))
			+((green - data->green)*(green - data->green))
			+((blue - data->blue)*(blue - data->blue)));
      /*We take this color and calculate the distance of the given color to it*/

      actual=(actual*actual)/(data->width*data->width);
      if (actual>1.) actual=1.;
      /*We use a cubic function to calculate the alpha value of the given color,
        with the actual color as exclude*/

      sum*=actual;
      /*We multiply all this alphas together to get the overall alpha*/


      identity.color++;
      data=(struct colordata*)voidlist_item (	list->liste,
   						(struct voidident*)&identity,
   						colorlist_greater,colorlist_equality);
      /*Get the next color*/
   }

   alpha=sum*255;
   return alpha;
   /*We return an integer value corresponding to our calculation double*/
}

/* -End--------------------------------------------------------------- */
