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

Array* array_create_setmax(int itemsize, int len, int maxlen){
	if(itemsize <= 0 || len < 0 || maxlen < len){
		return NULL;
	}
	Array* arr = (Array*)xmalloc(sizeof(Array));
	if(arr == NULL){
		return NULL;
	}
	arr->arr_itemsize = itemsize;
	arr->arr_curlen = len;
	arr->arr_maxlen = maxlen;
	if(maxlen != 0){
		arr->arr_data = xmalloc(itemsize * maxlen);
		if(arr->arr_data == NULL){
			free(arr);
			return NULL;
		}
	}else{
		arr->arr_data = NULL;
	}
	return arr;
}

Array* array_create(int itemsize, int len){
	return array_create_setmax(itemsize, len, len);
}

void array_free(Array* arr){
	if(arr->arr_data != NULL){
		free(arr->arr_data);
	}
	free(arr);
}

int array_pushback(Array* arr, const void* data){
	if((arr->arr_maxlen) < (arr->arr_curlen + 1)){
		if(arr->arr_maxlen != 0){
			if(array_setmax(arr, arr->arr_maxlen*2) < 0){
				return -1;
			}
		}else{
			if(array_setmax(arr, 1) < 0){
				return -1;
			}
		}
	}
	memcpy(array_vp(arr, arr->arr_curlen), data, arr->arr_itemsize);
	arr->arr_curlen++;
	return 0;
}

int array_setlen(Array* arr, int len){
	if(len > (arr->arr_maxlen)){
		if(array_setmax(arr, len) < 0){
			return -1;
		}else{
			arr->arr_curlen = len;
		}
	}else{
		arr->arr_curlen = len;
		return 0;
	}
	return 0;
}

int array_setmax(Array* arr, int max){
	void* newptr;
	if(arr->arr_data == NULL){
		newptr = xmalloc((arr->arr_itemsize)*max);
		if(newptr == NULL){
			return -1;
		}else{
			arr->arr_maxlen = max;
			arr->arr_data = newptr;
			return 0;
		}
	}
	newptr = realloc(arr->arr_data, (arr->arr_itemsize)*max);
	if(newptr == NULL){
		return -1;
	}else{
		arr->arr_maxlen = max;
		arr->arr_data = newptr;
	}
	return 0;
}

int array_strip(Array* arr){
	if(arr->arr_data == NULL){
		return 0;
	}
	Array* newptr; 
	/* 其實縮小空間營該一定會成功才對......
	 * 不過還是保險一點,加個判斷式,別說 memory leak 是我害的
	 * 當然也是避免編譯器一直跳 warning
	 */
	if((arr->arr_maxlen) > (arr->arr_curlen)){
		arr->arr_maxlen = arr->arr_curlen;
		newptr = realloc(arr->arr_data, (arr->arr_curlen)*(arr->arr_itemsize));
		if(newptr == NULL){
			return -1;
		}
		arr->arr_data = newptr;
	}
	return 0;
}

/* 基本上直接玩 struct 的函式還是少用吧 */
void* array_drop_struct(Array* arr){
	void* toreturn = arr->arr_data;
	free(arr);
	return toreturn;
}

Array* array_make_struct(void* data, int itemsize, int len, int maxlen){
	if(itemsize <= 0 || len < 0 || maxlen < len){
		return NULL;
	}
	Array* arr = (Array*)xmalloc(sizeof(Array));
	if(arr == NULL){
		return NULL;
	}
	arr->arr_itemsize = itemsize;
	arr->arr_curlen = len;
	arr->arr_maxlen = maxlen;
	arr->arr_data = data;
	return arr;
}