#include <stdlib.h>
#include <string.h>
#include <l4bds.h>

L4LL* l4ll_create(void){
	L4LL* newlist = (L4LL*)malloc(sizeof(L4LL));
	if(newlist == NULL){
		return NULL;
	}
	newlist->list_first = NULL;
	newlist->list_last = NULL;
	newlist->list_len = 0;
	return newlist;
}

void l4ll_free(L4LL* oldlist){
	if(oldlist->list_len <= 0){
		free(oldlist);
		return;
	}
	L4LLNODE* i;
	L4LLNODE* next;
	for(i=oldlist->list_first; i!=NULL; i=next){
		next = i->node_next;
		if(i->node_data_size){ /* 只要資料大小不為零,就還要釋放資料區 */
			free(i->node_data);
		}
		free(i);
	}
	free(oldlist);
}

static L4LLNODE* 
l4ll_initfirst(L4LL* list, const void* data, int size){
	/* 插入第一個資料,如果 list 不是空的就別用!
	 * 否則會造成資料結構混亂和 memory leak */
	L4LLNODE* node = (L4LLNODE*)malloc(sizeof(L4LLNODE));
	if(node == NULL){
		return NULL;
	}
	void* newdata;
   	if(size != 0){
		newdata = malloc(size);
		if(newdata == NULL){
			free(node);
			return NULL;
		}
		memcpy(newdata, data, size);
	}
	list->list_first = node;
	list->list_last = node;
	list->list_len = 1;
	node->node_prev = NULL;
	node->node_next = NULL;
	node->node_data = (size != 0) ? newdata : NULL;
	node->node_data_size = size;
	return node;
}

L4LLNODE* l4ll_insert_prev(L4LL* list, L4LLNODE* node, 
		const void* data, int size){
	/* list 送 NULL 來的我不理它,就自己去 segfault 吧
	 * node 送 NULL 來只能在 list 是空的時候用 */
	if(list->list_len == 0){
		return l4ll_initfirst(list, data, size);
	}
	L4LLNODE* newnode = (L4LLNODE*)malloc(sizeof(L4LLNODE));
	if(newnode == NULL){
		return NULL;
	}
	void* newdata;
	if(size != 0){
		newdata = malloc(size);
		if(newdata == NULL){
			free(newnode);
			return NULL;
		}
		memcpy(newdata, data, size);
	}
	list->list_len++;
	if(list->list_first == node){ /* 如果是第一個,那要修改 list_first */
		list->list_first = newnode;
	}
	L4LLNODE* oldprev = node->node_prev;
	node->node_prev = newnode;
	newnode->node_next = node;
	newnode->node_prev = oldprev;
	if(oldprev != NULL){
		oldprev->node_next = newnode;
	}
	newnode->node_data = (size != 0) ? newdata : NULL;
	newnode->node_data_size = size;
	return newnode;
}

L4LLNODE* l4ll_insert_next(L4LL* list, L4LLNODE* node, 
		const void* data, int size){
	/* 基本上同 l4ll_insert_prev */
	if(list->list_len == 0){
		return l4ll_initfirst(list, data, size);
	}
	L4LLNODE* newnode = (L4LLNODE*)malloc(sizeof(L4LLNODE));
	if(newnode == NULL){
		return NULL;
	}
	void* newdata;
	if(size != 0){
		newdata = malloc(size);
		if(newdata == NULL){
			free(newnode);
			return NULL;
		}
		memcpy(newdata, data, size);
	}
	list->list_len++;
	if(list->list_last == node){
		list->list_last = newnode;
	}
	L4LLNODE* oldnext = node->node_next;
	node->node_next = newnode;
	newnode->node_prev = node;
	newnode->node_next = oldnext;
	if(oldnext != NULL){
		oldnext->node_prev = newnode;
	}
	newnode->node_data = (size != 0) ? newdata : NULL;
	newnode->node_data_size = size;
	return newnode;
}

void l4ll_remove(L4LL* list, L4LLNODE* node){
	/* 不要在 node 傳 NULL,這一點意義也沒有且我不知道會發生什麼事 */
	if(list->list_first == node){
		list->list_first = node->node_next;
	}
	if(list->list_last == node){
		list->list_last = node->node_prev;
	}
	list->list_len--; /* 不考慮長度為零的情況,空白是想要刪什麼? */
	L4LLNODE* oldnext = node->node_next;
	L4LLNODE* oldprev = node->node_prev;
	if(node->node_data_size != 0){
		free(node->node_data);
	}
	free(node);
	if(oldnext != NULL){
		oldnext->node_prev = oldprev;
	}
	if(oldprev != NULL){
		oldprev->node_next = oldnext;
	}
}

L4LLNODE* l4ll_goto(L4LLNODE* node, int count){
	int i;
	if(count == 0){
		return node;
	}else if(count > 0){
		for(i=1; i<=count; i++){
			node = node->node_next;
			if(node == NULL){
				return NULL;
			}
		}
	}else{
		count = -count;
		for(i=1; i<=count; i++){
			node = node->node_prev;
			if(node == NULL){
				return NULL;
			}
		}
	}
	return node;
}

#if 0
int l4ll_pushback(L4LL* list, void* data, int size){
	L4LLNODE* cur_save = list->list_current; /* 等一下要把現在位置搬回去 */
	list->list_current = list->list_last;
	int result = l4ll_insnext(list, data, size);
	if(result == 0){ /* 成功 */
		if(cur_save != NULL){ /* 原先的現在位置若為空就無意義了 */
			list->list_current = cur_save;
		}
	}else{ /* 失敗 */
		list->list_current = cur_save;
	}
	return result;
}


int l4ll_pushfront(L4LL*, void*){ /* 取自 l4ll_pushback */
	L4LLNODE* cur_save = list->list_current; 
	list->list_current = list->list_front;
	int result = l4ll_insprev(list, data, size);
	if(result == 0){
		if(cur_save != NULL){ 
			list->list_current = cur_save;
		}
	}else{ 
		list->list_current = cur_save;
	}
	return result;
}

int l4ll_popback(L4LL*){
	L4LLNODE* cur_save = list->list_current;
	L4LLNODE* last_save = list->list_last
	list->list_current = last_save;
	int result = l4ll_remove(list, L4LL_PREV);
	if(result == 0){ 
		if(cur_save != NULL && ){ 
			list->list_current = cur_save;
		}
	}else{ 
		list->list_current = cur_save;
	}
	return result;
}

int l4ll_popfront(L4LL*){
	L4LLNODE* cur_save = list->list_current;
	list->list_current = list->list_first;
	int result = l4ll_remove(list, L4LL_NEXT);
	if(result == 0){ 
		if(cur_save != NULL){ 
			list->list_current = cur_save;
		}
	}else{ 
		list->list_current = cur_save;
	}
	return result;
}
#endif