#include <stdlib.h>
#include <string.h>
#include "slist.h"
#define DMID 12
#include "debug.h"

struct slist {
	int(*fn)(const void *, const void *);
	void **data;
	int sz,cnt;
};

static int findpos(Slist *s, void *item, int first, int last);

Slist *slist_new(int sz, int(*compare)(const void *, const void *)) {
	Slist *s;

	s = calloc(1,sizeof(Slist));
	s->fn = compare;
	slist_expand(s,sz);
	return s;
}
void slist_clear(Slist *s, void(*clear)(void *)) {
	if (clear) {
		int i;
		for(i = 0; i < s->cnt; i++)
			clear(s->data[i]);
	}
	s->cnt = 0;
}
void slist_free(Slist **s) {
	free((*s)->data);
	free(*s);
	*s = NULL;
}

int slist_size(Slist *s) {
	if (s) return s->sz;
	return -1;
}
int slist_items(Slist *s) {
	if (s) return s->cnt;
	return -1;
}

int slist_expand(Slist *s, int x) {
	if (!s || x < 0) return -1;
	if (x == 0) x = 1;
	if (s->sz < x) {
		s->data = realloc(s->data,sizeof(void *)*(x));
		s->sz = x;
	}
	return s->sz;
}

int slist_insert(Slist *s, void *item) {
	int i;

	if (!s || !item) return -1;
	i = findpos(s,item,0,s->cnt);
	if (s->cnt == s->sz) slist_expand(s,s->sz+(s->sz/2));
	if (i < s->cnt) memmove(&s->data[i+1],&s->data[i],(s->cnt-i+1)*sizeof(void *));
	s->data[i] = item;
	s->cnt++;
	return i;
}

void *slist_get(Slist *s, int i) {
	if (i == -1) i = s->cnt-1;
	if (i < 0 || i > s->cnt-1) return NULL;
	return s->data[i];
}

void *slist_del(Slist *s, int i) {
	void *item;

	if (i == -1) i = s->cnt-1;
	if (i < 0 || i > s->cnt-1) return NULL;
	item = s->data[i];
	if (i < s->cnt-1) memmove(&s->data[i],&s->data[i+1],(s->cnt-i)*sizeof(void *));
	s->cnt--;
	return item;
}


static int findpos(Slist *s, void *item, int first, int last) {
	int v,x;

	x = (last+first)/2;
	if (x == s->cnt) return x;

	v = s->fn(item,s->data[x]);
	if (v < 0) {
		if (x == first) return first;
		return findpos(s,item,first,x-1);
	}
	if (v > 0) {
		if (x == last) return last+1;
		return findpos(s,item,x+1,last);
	}
	return x;
}
