/* semplici primitive di gestione di una lista ordinata (numerica)
 * tramite rappresentazione concatenata */
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include"lista.h"

struct nodo_lista {
  type_lista elemento;
  struct nodo_lista *next;
};

/* prototipi funzioni ad uso interno */
void  districorsLISTA(struct nodo_lista *);
struct nodo_lista *punto_di_inserzione(struct nodo_lista *, type_lista);

static struct nodo_lista *testa=NULL;
static int numelementi=0;


/* crea la lista di dimensione massima fornita
 * ritorna OK o ERR */
int creaLISTA(int numel){
  if((testa=malloc(sizeof(struct nodo_lista)))==NULL)
   return LISTA_ERR;
  testa->elemento=-INT_MAX;
  testa->next=NULL;
  numelementi=0;
  return LISTA_OK;
}
/* distrugge la lista si appoggia ad una funzione 
 * ricorsiva */
void destroyLISTA(void){
 if(testa)
   districorsLISTA(testa);
 numelementi=0;
}

/* funzione interna di liberazione ricorsiva memoria */
void  districorsLISTA(struct nodo_lista *a){
  if(!a->next)
   districorsLISTA(a->next); 
  free(a);
}

/* ritorna numero elementi lista */
int elementiinLISTA(void){
 return numelementi;
}

/* inserisce elemento in lista ritorna OK o ERR
 * ancora una volta mi appoggio ad una funzione ricorsiva esterna */
int inserisciinLISTA(type_lista a){
 struct nodo_lista *nuovo, *p;
 int jj;
 
 /* attenzione! non tengo conto del massimo
  * numero di valori */

 /* controllo la presenza in lista */
 if((trovainLISTA(a, &jj))==LISTA_OK)
  return LISTA_ERR;

 ++numelementi;
 /* alloco nuovo nodo */
 if((nuovo=malloc(sizeof(struct nodo_lista)))==NULL)
   return LISTA_ERR;
 /* metto i dati */
 nuovo->elemento=a;
 nuovo->next=NULL;
 

 /* ricerco punto di inserzione */
 p=punto_di_inserzione(testa, a);
 
 nuovo->next=p->next;
 p->next=nuovo;

 return LISTA_OK;
}

/* scorre la lista e restituisce il punto in cui inserire il dato        */
struct nodo_lista *punto_di_inserzione(struct nodo_lista *start, type_lista valore){
        if(!start->next)return start; /* sicuramente inserisco qui se sono in fondo */
        if(start->next->elemento>valore)return start;
        return punto_di_inserzione(start->next,valore);
}


/* ricerca l'elemento ne ritorna l'indice e l'esito
 * dell'operazione */
int trovainLISTA(type_lista a, int* index){
 int counter=0;
 struct nodo_lista *ii;

 for(ii=testa->next;ii;ii=ii->next){
  if(ii->elemento==a){
   *index=counter;
   return LISTA_OK;
   }
  ++counter;
 }
 return LISTA_ERR;
}

/* rimuove l'elemento in funzione dell'indice
 * e ritorna l'esito */
int rimuovidaLISTA(int indice){
 int counter;
 struct nodo_lista *ii, *p;

 /* controllo il valore dell'indice */
 if((indice>numelementi)||(indice<0))
  return LISTA_ERR;

 counter=1;
 for(ii=testa->next;counter<indice;ii=ii->next)
   ++counter;

 /* ii contiene l'elemento precedente
  * a quello che si vuole eliminare */
 p=ii->next;

 /* cambio i collegamenti */
 ii->next=ii->next->next;
 free(p);
 --numelementi;

 return LISTA_OK;
}

/* recupera l'elemento in funzione dell'indice
 * ritorna lo stato dell'operazione */
int indiceLISTA(int indice,type_lista *a){
 int counter;
 struct nodo_lista *ii;

 /* controllo il valore dell'indice */
 if((indice>numelementi)||(indice<0))
  return LISTA_ERR;

 counter=0;
 for(ii=testa->next;counter!=indice;ii=ii->next)
  ++counter;

 /* ii punta al nodo di indice voluto */
 *a=ii->elemento;

 return LISTA_OK;
}

/* inverte l'ordine della lista */
void invertiLISTA(void){
   struct nodo_lista *t, *y, *r;

  if(numelementi<=1)
    return;

  /*ignoro la testa fasulla*/
  y=testa->next;
  r=NULL;
  while(y!=NULL){
   t=y->next;
   y->next=r;
   r=y;
   y=t;
  }
  testa->next=r;
}