#include <stdio.h>
#include <stdlib.h>

#define TYPE int
#define TYPE_DESC d

typedef struct _elem {
	TYPE data;
	struct _elem *next;
	struct _elem *prev;
} elem;

typedef struct _lista {
	elem *head;
	elem *tail;
} lista;

void print_lista(elem *l);

elem *create_elem(TYPE data){
	elem *res=malloc(sizeof(elem));
	res->data=data;
	res->next=0;
	res->prev=0;
}

void free_elem(elem *e){
	free(e);
}

lista *create_lista(){
	lista *res=malloc(sizeof(lista));
	res->head=0;
	res->tail=0;
	return res;
}

void free_list1(elem *e){
    if(e->next) free_list1(e->next);
    free_elem(e);
}

void free_lista(lista *l){
	elem *e=l->head;
	free_list1(e);
    free(l);
}

void conc_lista(lista *l1, lista *l2){
	elem *curr;
	l1->tail->next=l2->head;
	l2->head->prev=l1->tail;
	free(l2);
	return;
}

void insert_in_order(lista *l, elem *e){
	elem *curr=0;
	elem *prec=0;
	
	for(curr=l->head; curr!=0 && curr->data < e->data; curr=curr->next);
	prec=curr->prev;	

	/* Esegui inserimento */
	if (prec==0) { /* curr == l, inserimento in testa */
		e->next=l->head;
		l->head->prev=e;
		l->head=e;
		return;
	} else { /* in posizione diversa dalla testa, fra prec e curr */
		prec->next=e;
		e->next=curr;
		e->prev=prec;
		return;
	}
}

/* TODO */
elem *sort_elem(elem *e){
    elem *res = 0;
    lista l;
    if (!e) return 0;
    res=sort_elem(e->next);
    l.head=res;
    for(res=l.head; res->next!=0; res=res->next);
    l.tail=res;
    insert_in_order(&l,e);
    res=l.head;
    return res;
}

void sort_lista(lista *l){
	elem *res;
    if (l->head->next==0) return;
	l->head=sort_elem(l->head);
    for(res=l->head; res->next!=0; res=res->next);
    l->tail=res;
    return;
}


void insert_in_testa(lista *l, TYPE data){
	elem *curr=create_elem(data);
	if (l->head!=0) l->head->prev=curr;
	curr->next=l->head;
	l->head=curr;
	return;
}

void print_lista(elem *l){
	if (l==0) {
		printf("\n");
	} else {
		printf("%d ", l->data);
		print_lista(l->next);
	}
}

void insert_in_coda(lista *l, TYPE data){
	elem *curr;
	curr=create_elem(data);
	if (l->tail==0) { /* lista vuota */
		l->tail=curr;
		l->head=curr;
	} else {
		l->tail->next=curr;
		curr->prev=l->tail;
		l->tail=curr;
	}
}

lista *delete_from_lista(lista *l, elem *e){
	elem *curr;
	if (l->head==0) return l;
	if (l->head==e) {
		l->head=e->next;
		e->next->prev=0;
		free_elem(e);
		return l;
	} 
	if (l->tail==e) {
		l->tail=e->prev;
		e->prev->next=0;
		free_elem(e);
		return l;
	}
	e->prev->next=e->next;
	e->next->prev=e->prev;	
	free_elem(e);
	return l;
}

elem *search_lista(elem *l, TYPE data){
	if (l==0) return 0;
	if (l->data==data) return l;
	return search_lista(l->next, data);
}

int main(int argc, char **argv){
	elem *curr;
	lista *l=create_lista();
printf("%d\n", __LINE__);
    insert_in_testa(l,10);
printf("%d\n", __LINE__);
	insert_in_testa(l,5);
	insert_in_testa(l,11);
	insert_in_testa(l,7);
	insert_in_testa(l,2);
printf("%d\n", __LINE__);
	print_lista(l->head);
printf("%d\n", __LINE__);
}
