/*This file contains the patternlist class, to save the list of
  small icons, for pattern detection*/

/*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"
/*We include the List object motherclass*/

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


struct patindex {
   int patident;
};
/* Our Identification (List Index) Structure */

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

struct pattern {
   int* brightness;
   int width;
   int height;
};
/* Our List Data Structure*/

struct patternlist{
   struct voidlist *liste;
};
/*The structure patternlist, 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 ;) */

struct patternmatch {
   int patident;
   int differ;
};
/*The structure patternmatch, for giving back 2 values at once ;)*/

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

int patternlist_greater (struct voidident *vfrst, struct voidident *vscnd) {
   struct patindex *frst,*scnd;
   frst=(struct patindex*)vfrst;
   scnd=(struct patindex*)vscnd;
   return ( (frst->patident>scnd->patident) );
}

int patternlist_equality (struct voidident *vfrst, struct voidident *vscnd) {
   struct patindex *frst,*scnd;
   frst=(struct patindex*)vfrst;
   scnd=(struct patindex*)vscnd;
   return ( (frst->patident==scnd->patident) );
}

int patternlist_freecontent (struct voidident *videntity, struct voiddata *vdata){
   struct patindex *identity;
   struct pattern *data;
   identity=(struct patindex*)videntity;
   data=(struct pattern*)vdata;
   free (data->brightness);
   free (data);
   free (identity);
   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 */

struct patterncheck {
   struct patternmatch tmpbestmatch;
   struct pattern* checkpattern;
};
/*Var to temp save best hit and temp save the pattern actual being checked*/

int pattern_compare (struct pattern* pattern1, struct pattern* pattern2 );
/* function prototype needed here, function found somewhere below*/

int patternlist_checkall (int number, struct voidident *videntity, struct voiddata *vdata, void* userdata ) {
   struct patindex *identity;
   struct pattern *data;
   struct patterncheck *check;
   int diff;
   identity=(struct patindex*)videntity;
   data=(struct pattern*)vdata;
   check=(struct patterncheck*)userdata;

   diff= pattern_compare(data,check->checkpattern);
  
   /*Nuff sais : pattern with smallest diff matches best*/
   if (diff<check->tmpbestmatch.differ || check->tmpbestmatch.differ<0) {
      check->tmpbestmatch.differ=diff;
      check->tmpbestmatch.patident=identity->patident;
   }
   return 0;
}
/*Private function executed by voidlist for every list member to check against checkpattern*/

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

struct patternlist* patternlist_new() {
/*A constructor*/
   struct patternlist* newpattern;

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


   return newpattern;
}

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

int patternlist_rempattern (struct patternlist* list,int patident) {
/*Removes a pattern from the list
  0 on success, 1 on not found, -1 on error
*/
   struct patindex identity;

   if (!list) return -1;

   identity.patident=patident;
   return voidlist_remitem(	list->liste,
   				(struct voidident*)&identity,
   				patternlist_greater,patternlist_equality,
				patternlist_freecontent);

}

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

int patternlist_kill(struct patternlist* list) {
/*A destructor*/
   if (!list) return -1;
   voidlist_kill(list->liste,patternlist_freecontent);
   free(list);
   return 0;
}

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

int patternlist_addpattern (struct patternlist* list,int patident,int width,int height, int* icon) {
/*Sets a pattern on the list
  0 added, 1, changed, -1 error
*/
   struct patindex *identity;
   struct pattern *data;
   int* brightness;
   int t,tt;

   if (!list) return -1;

   identity=(struct patindex*)malloc(sizeof(struct patindex));
   if (!identity) return -1;
   data=(struct pattern*)malloc(sizeof(struct pattern));
   if (!data) {
      free(identity);
      return -1;
   }
   brightness=(int*)malloc(sizeof(int[width*height]));
   if (!brightness) {
      free (identity);
      free (data);
      return -1;
   }
   /*We have to create a special structure in memory to add to our list */
   
   
   identity->patident=patident;
   data->width=width;
   data->height=height;
   data->brightness=brightness;
   t=0;
   while (t<height) {
      tt=0;
      while (tt<width) {
         brightness[(t*width)+tt]=icon[(t*width)+tt];
	 tt++;
      }
      t++;
   }
   /*And fill them with data*/

   return voidlist_additem (	list->liste,
   				(struct voidident*)identity,
   				(struct voiddata*)data,
   				patternlist_greater,patternlist_equality,
				patternlist_freecontent);
   /*And include this data in the list structure*/

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

struct pattern* patternlist_pattern (struct patternlist* list, int patident){
   struct patindex identity;
   struct pattern *data;

   if (!list) return NULL;
   
   identity.patident=patident;
   data=((struct pattern*)voidlist_item(list->liste,
					(struct voidident*)&identity,
					patternlist_greater,patternlist_equality));
   if (!data) return NULL;

   return data;
}
/*Gives back a pattern.
  NULL in case of error
*/
/* ------------------------------------------------------------------- */

struct patternmatch patternlist_bestmatch (struct patternlist* list,struct pattern * pattern) {
/*Gives back the pattern that matches icon best (and how good it matches)*/
   struct patterncheck check;


   check.tmpbestmatch.patident=-1;
   check.tmpbestmatch.differ=-1;
   check.checkpattern=pattern;
   /*Initialize our checking var ;)*/

   if (!list) return check.tmpbestmatch;
   
   voidlist_all (list->liste,patternlist_checkall, (void*)&check);

   return check.tmpbestmatch;

}
/* ------------------------------------------------------------------- */
int pattern_compare (struct pattern* pattern1, struct pattern* pattern2 )
{
/* gives back the ident value of 2 compared patterns */
   int x,y,t,tt,tdiff,diff;
   
   if (pattern1->height<pattern2->height) y=pattern1->height; else y=pattern2->height;
   if (pattern1->width<pattern2->width) x=pattern2->width; else x=pattern2->width;
   
   diff=0;
   t=0;
   while (t<y) {
      tt=0;
      while (tt<x) {
         tdiff=pattern1->brightness[t*pattern1->width+tt]-pattern2->brightness[t*pattern2->width+tt];
	 if (tdiff<0) diff-=tdiff; else diff+=tdiff;
         tt++;
      }
      t++;
   }
   /*Compare every pixel found in both patterns, and add the difference to diff*/

   return diff;

}

