#include "xwrap.h"
#include <stdlib.h>
#include <string.h>
#include "basic-list.h"

List* list_create(void){
	List* newlist = (List*)xmalloc(sizeof(List));
	if(newlist == NULL){
		return NULL;
	}
	newlist->list_first = NULL;
	newlist->list_last = NULL;
	newlist->list_len = 0;
	return newlist;
}

void list_free(List* oldlist){
	if(oldlist->list_len <= 0){
		free(oldlist);
		return;
	}
	ListNode* i;
	ListNode* 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 ListNode* 
list_initfirst(List* list, const void* data, int size){
	/* 插入第一個資料,如果 list 不是空的就別用!
	 * 否則會造成資料結構混亂和 memory leak */
	ListNode* node = (ListNode*)xmalloc(sizeof(ListNode));
	if(node == NULL){
		return NULL;
	}
	void* newdata;
   	if(size != 0){
		newdata = xmalloc(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;
}

ListNode* list_insert_prev(List* list, ListNode* node, 
		const void* data, int size){
	/* list 送 NULL 來的我不理它,就自己去 segfault 吧
	 * node 送 NULL 來只能在 list 是空的時候用 */
	if(list->list_len == 0){
		return list_initfirst(list, data, size);
	}
	ListNode* newnode = (ListNode*)xmalloc(sizeof(ListNode));
	if(newnode == NULL){
		return NULL;
	}
	void* newdata;
	if(size != 0){
		newdata = xmalloc(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;
	}
	ListNode* 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;
}

ListNode* list_insert_next(List* list, ListNode* node, 
		const void* data, int size){
	/* 基本上同 list_insert_prev */
	if(list->list_len == 0){
		return list_initfirst(list, data, size);
	}
	ListNode* newnode = (ListNode*)xmalloc(sizeof(ListNode));
	if(newnode == NULL){
		return NULL;
	}
	void* newdata;
	if(size != 0){
		newdata = xmalloc(size);
		if(newdata == NULL){
			free(newnode);
			return NULL;
		}
		memcpy(newdata, data, size);
	}
	list->list_len++;
	if(list->list_last == node){
		list->list_last = newnode;
	}
	ListNode* 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 list_remove(List* list, ListNode* 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--; /* 不考慮長度為零的情況,空白是想要刪什麼? */
	ListNode* oldnext = node->node_next;
	ListNode* 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;
	}
}

ListNode* list_goto(ListNode* 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;
}