#include "rssi_list.h"

u_char *string_to_mac(char * buf, u_char * byte_mac) {
	sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &byte_mac[0], &byte_mac[1],&byte_mac[2],&byte_mac[3],&byte_mac[4],&byte_mac[5]);
	return byte_mac;
}

char * mac_to_string(u_char * byte_mac, char * buf) {
	//opposite of sscanf is sprintf
    	sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", byte_mac[0], byte_mac[1], byte_mac[2], byte_mac[3], byte_mac[4], byte_mac[5]); 
    	return buf;
}

int is_equal(u_char * array1, u_char * array2) {
	if (sizeof(array1) != sizeof(array2))
		return 0;
	int i = 0;
	while (i < 6) {
		if(array1[i] != array2[i])
		    return 0;
		++i;
	}
	return 1;
}

/* -------------------------------------------------------------------------------------------- */
/* ---------------------------------gestionaire de liste chainée ------------------------------ */
/* -------------------------------------------------------------------------------------------- */

void clear_outdated_values(Deque * list) {
	if(list != NULL) {
		struct timeval timer;
		unsigned long long ull_timer = 0;
		gettimeofday(&timer, NULL);
		ull_timer = timer.tv_sec;
		if (list->head != NULL) {
			Rssi_sample * cursor = list->head;
			Rssi_sample * lastElem = NULL; //last element checked
			while (cursor != NULL) {
				//check if cursor element has to be cleared
				if (cursor->deadline + DEFAULT_KEEP_DELAY < ull_timer ) {
					//only my cursor element  
					if (cursor == list->head && cursor->next == NULL) {
						free(cursor);
						list->head = NULL;
						list->tail = NULL;
						cursor = NULL;
					}
					//first element but not alone 
					else if (cursor == list->head) {
						list->head = cursor->next;
						free(cursor);
						cursor = list->head;
					}
					//last element : if deque is properly sorted it should never appear
					else if (cursor == list->tail){
						list->tail = lastElem;
						lastElem->next = NULL;
						free(cursor);
						cursor = NULL;
					}
					else {
						lastElem->next = cursor->next;
						free(cursor);
						cursor = lastElem->next;
					}
				}
				//no need to modify. get next elem
				else {
					//update last elem with cursor, go to next elem
					lastElem = cursor;
					cursor = cursor->next;
				}
			}
		}
	}
}

void clear_values(Deque * list) {
	if (list != NULL && list->head != NULL) {
		Rssi_sample * next;
		while (list->head != NULL) {
			next = list->head->next;
			free(list->head);
			list->head = next;
		}
	}
	list->tail = NULL;
}

void add_value(Deque * list, int value) {
	if (list != NULL)
	{

		//initialize the new rssi_sample
		//Rssi_sample * new_rssi= NULL;
		/***********************************************************
		*Note :                                                    *
		*using malloc causes memory corruption                     *
		*It seems to be because of a static declaration of new_el  *
		* ! need an investigation !                                *
		************************************************************/
		//new_rssi = (Rssi_sample*) calloc(sizeof(Rssi_sample), 1);
		//initialize the new rssi_sample

		Rssi_sample * new_rssi;
		new_rssi = malloc(sizeof(Rssi_sample));
		new_rssi->rssi_mW = value;
		struct timeval timer;
		gettimeofday(&timer, NULL);
		new_rssi->deadline = timer.tv_sec;
		new_rssi->next = NULL;

		if (list->head == NULL) {
			list->head = new_rssi;
		}
		else {
			list->tail->next = new_rssi;	
		}
		list->tail = new_rssi;
	}
}

void clear_list(Element ** list) {
	if (*list != NULL) {
	Element * next;
		while (*list != NULL) {
			//save next device(element)
			next = (*list)->next;
			//clear deque of the device
			clear_values(&(*list)->measurements);
			free(*list);
			*list = next;
		}
	}
}

Element * find_mac(Element * list, u_char * mac_value) {
	if (list != NULL) {
		Element * cursor = list;
		while (cursor != NULL) {
			if (is_equal(cursor->mac_addr, mac_value))
				return cursor;
			cursor = cursor->next;
		}		
	}
    	return NULL;
}


Element * add_element(Element ** list, u_char * mac_value) {
	int i;
	//initialize new element
	Element * elem;
	//el = (Element*)calloc(sizeof(Element), 1);
	elem = malloc(sizeof(Element));
	for (i =0; i < 6; i++)
		elem->mac_addr[i] = mac_value[i];
	elem->measurements.head = NULL;
	elem->measurements.tail = NULL;
	elem->next = NULL;

	if (*list != NULL) {
		Element * cursor = *list;
		while (cursor!= NULL)
			cursor = cursor->next;
		cursor = elem;
	}
	else
		*list = elem;
	return elem;
}

void delete_element(Element ** list, Element * e) {
    	if (*list != NULL && e != NULL)
	{
		Element * cursor = *list;
		Element * previous = NULL;
		// find the matched device (element)
		while (cursor->next != NULL && cursor->mac_addr != e->mac_addr)
		{
			previous = cursor;
			cursor = cursor->next;
		}
		if(previous==NULL) // first elem will be delete
			*list = cursor->next;
		else
			previous->next=cursor->next; //relink the list
			
		//clear the rssi list

		//clear rssi deque of the device
		clear_values(&(cursor->measurements));
		/*Rssi_sample * rssi = cursor->measurements.head;
		while (rssi != NULL) {
			cursor->measurements.head = rssi->next;
			free(rssi);
			rssi = cursor->next->measurements.head;
		}
		cursor->measurements.tail = NULL;*/
		free(cursor);
    	}
}

void clear_empty_macs(Element ** list) {
	Element * cursor = *list;
	Element * tmp;
	while (cursor != NULL) {
		//if the current element has an empty rssi sample list
		if (cursor->measurements.head == NULL) {
			//get next element
			tmp = cursor->next;
			//deleete element from the list
			delete_element(list, cursor);
			//restore the element
			cursor = tmp;
		}
		else    
			cursor = cursor->next; //get next element
	}
}

/* -------------------------------------------------------------------------------------------- */
/* --------------------------------- element building ------------------------------ */
/* -------------------------------------------------------------------------------------------- */
/*
char * build_element(Element * e, char * buf) {

}

char * build_buffer(Element * list, char * buffer, char * my_name, u_char * macs_requested, unsigned short nb_macs) {

}*/
