/***********     CODI DE LA LLISTA GENERICA KKEP    *****************/
/********************************************************************\
*         Aqui teniu el codi de la llista generica total!!!          *
*                                                                    *
* NOTA: En contra del que sovint he insinuat que faria, no l'he      *
* copiada de cap vostra. Es bastant diferent, crec. Conte totes      *
* les barbaritats que us demanavem i algunes floritures mes. A       *
* mes a mes, he afegit d'ultima hora algunes cosetes boniques        *
* que he vist en les vostres practiques. Com totes les llibreries    *
* del Share, aquesta tambe es de domini public pero aneu amb cura    *
* si les feu servir per practiques.                                  *
*                                                                    *
* Millores implementades:                                            *
*  - Totes les funcions del node llista es fan servir com si         *
*       fossin les funcions de la llibreria standard, stdlib:        *
*       * strcmp, strcpy, malloc, free i strcat.                     *
*  - Permet diversos tipus d'insercions, segons el que passa         *
*       quan colisionin dos claus iguals:                            *
*       * La nova es postposa a la vella                             *
*       * La nova s'anteposa a la vella                              *
*       * La nova no s'insereixi                                     *
*       * La nova sustituexi la vella                                *
*       * La nova modifiqui la vella                                 *
*  - Permet operacio simultanea amb finestra i per valor a           *
*       la mateixa llista sense que un destorbi a l'altre.           *
*  - Permet dos tipus de consultes, segons es retorni                *
*       * Una copia de l'element a una altre zona de memoria         *
*       * Un punter al mateix element de la llista                   *
*  - Permet definir a la vegada:                                     *
*       * Mes d'una llista                                           *
*       * de les diferents classes a dalt mencionades                *
*       * i contenint diferents tipus d'elements                     *
*  - Funcio aplica: Resol la majoria de les vostres floritures.      *
*  - Funcio acomula: Permet obtindre un resultat de tipus            *
*       generic calculat a partir de tots els elements de la         *
*       llista.                                                      *
*                                                                    *
* Limitacions:                                                       *
*  - Per mantenir la consistencia de l'ordenacio, no es aconse.      *
*       llable inserir per finestra indiscriminadament si fem        *
*       quelcom per valor o un llista_posiciona_finestra.            *
*  - Per evitar core dumped's, s'aconsella initcialitzar la          *
*       finestra sempre que s'esborri per valor.                     *
*                                                                    *
* Be, i ara... qui s'atreveix a:                                     *
*  - Fer-la doblement encadenada.                                    *
*  - Fer-la circular.                                                *
*  - Fer-la multi-finestra.                                          *
*                                                                    *
\********************************************************************/

#include <alloc.h>   /* Es la minima llibreria que fem servir

/********************************************************************\
*   TAD Llista generica                                              *
\********************************************************************/

typedef struct NODE_LLISTA {
  void *v;
  struct NODE_LLISTA *s;
  } node_llista;

typedef struct LLISTA {
  int quants;
  node_llista *cap,*act;
  int (*gencmp) (void*,const void*);
  void* (*genalloc) (void);
  void (*gencpy) (void*,void*);
  void (*genfree) (void*);
  void (*gencat) (void*,const void*);
  } llista;

/********************************************  CREACIO I DESTRUCCIO */
llista *llista_crea( int (*fcmp) (void*,const void*),
                     void* (*falloc) (void),
                     void (*fcpy) (void*,void*),
                     void (*ffree) (void*),
                     void (*fcat) (void*,const void*))  {
  /* Primer de tot demanem memoria i despres ens podrem
     despreocupar de desfer coses si hi ha error */
  llista *nova;
  nova = (llista*) malloc (sizeof(llista));
  if (!nova) return (NULL);
  nova->cap = (node_llista*) malloc (sizeof(node_llista));
  if (!nova->cap) {
     free (nova);
     return (NULL);
     }
  /* La finestra d'interes no apunta enlloc (fi de la llista) */
  nova->act = NULL;
  /* El fantasma no te seguent element */
  nova->cap->s = NULL;
  /* No hi ha cap element inserit */
  nova->quants = 0;
  /* Initem els punters a funcio */
  nova->gencmp = fcmp;
  nova->genalloc = falloc;
  nova->gencpy = fcpy;
  nova->genfree = ffree;
  nova->gencat = fcat;
  return nova;
  }
void llista_destroy (llista *l) {
  node_llista *tmp1,*tmp2;
  for (tmp1=l->cap->s; tmp2=tmp1; tmp1=tmp1->s,  free (tmp2))
     l->genfree(tmp2->v);
  free(l->cap);
  free(l);
  }

/*********************  IMPLEMENTACIO AMB PUNT D'INTERES (FINESTRA) */
/* NOTA: act apunta al anterior */
void llista_primer (llista *l) {
  l->act = l->cap;
  }
void llista_seguent (llista *l) {
  l->act = l->act->s;
  }
int llista_fi (llista *l) {
  return (l->act->s == NULL);
  }
void llista_posiciona (llista *l,void *v) {
  for (l->act=l->cap;
       l->act->s && l->gencmp(l->act->s->v,v)<0;
       l->act=l->act->s);
  }
void llista_fes_copia_finestra(llista *l, void *v) {
  l->gencpy(v,l->act->s->v);
  }
void* llista_consulta_finestra(llista *l) {
  return (l->act->s->v);
  }
void llista_esborra_finestra(llista *l) {
  node_llista *tmp;
  tmp=l->act->s;
  l->act->s=tmp->s;
  l->genfree(tmp->v);
  free (tmp);
  }
int llista_afegeix_finestra (llista *l, void*v) {
  node_llista *nounode;
  if (!(nounode = (node_llista *) malloc (sizeof(node_llista))))
      return (NULL);
  if (!(nounode->v=l->genalloc())) {
      free (nounode);
      return (NULL);
      }
  l->gencpy(nounode->v,v);
  nounode->s = l->act->s;
  l->act->s = nounode;
  return (!NULL);
  }


/****************************************** IMPLEMENTACIO PER VALOR */

int llista_fes_copia(llista *l, void *v1, const void *v2) {
  node_llista *browser;
  for (browser=l->cap;
       browser->s && l->gencmp(browser->s->v,v2)<0;
       browser=browser->s);
  if (!(browser->s) || l->gencmp(browser->s->v,v2)!=0) return(NULL);
  l->gencpy(v1,browser->s->v);
  return(!NULL);
  }
void* llista_consulta(llista *l, const void *v) {
  node_llista *browser;
  for (browser=l->cap;
       browser->s && l->gencmp(browser->s->v,v)<0;
       browser=browser->s);
  if (!(browser->s) || l->gencmp(browser->s->v,v)!=0) return(NULL);
  return(browser->s->v);
  }
int llista_esborra(llista *l, const void *v) {
  node_llista *browser,
              *tmp;
  for (browser=l->cap;
       browser->s && l->gencmp(browser->s->v,v)<0;
       browser=browser->s);
  if (!(browser->s) || l->gencmp(browser->s->v,v)!=0) return(NULL);
  tmp=browser->s;
  browser->s=tmp->s;
  l->genfree(tmp->v);
  free (tmp);
  return(!NULL);
  }
int llista_afegeix (llista *l, void *v) {
  node_llista *browser,
              *nounode;
  /* Aquest bucle posiciona el 'browser' en el node previ
     al lloc on hauriem d'inserir */
  for (browser=l->cap;
       browser->s && l->gencmp(browser->s->v,v)<0;
       browser=browser->s);

  /* Si es al final o ha trobat un de mes gran ha de crear el node */
  if (!(browser->s) || l->gencmp(browser->s->v,v)>0) {
      if (!(nounode = (node_llista *) malloc (sizeof(node_llista))))
          return (NULL);
      if (!(nounode->v=l->genalloc())) {
          free (nounode);
          return (NULL);
          }
      l->gencpy(nounode->v,v);
      nounode->s = browser->s;
      browser->s = nounode;
      }
  /* Si en canvi ha trobat un element amb la mateixa clau modifical */
  else {
      l->gencat(browser->s->v,v);
      }
  return (!NULL);
  }

/************  LA FAMOSA FUNCIO APLICA I ALTRA FUNCIO IGUAL DE UTIL */

void llista_aplica (llista *l, void*(*modifica)(void*)) {
  node_llista *browser;
  for (browser=l->cap->s; browser; browser=browser->s)
     browser->v = modifica (browser->v);
  }

void llista_acomula (llista *l, void (*acomula)(void*,void*),
                      void *valor_acomulat) {
  node_llista *browser;
  for (browser=l->cap->s; browser; browser=browser->s)
     acomula (valor_acomulat, browser->v);
  }

