/*
 * Part:        Vector structure manipulation.
 *
 * Version:     $Id: vector.c,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
 *
 * Author:      Alexandre Cassen, <acassen@linux-vs.org>
 *
 *              This program is distributed in the hope that it will be useful,
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *              See the GNU General Public License for more details.
 *
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *
 * Copyright (c) 2002, 2003, 2004 Alexandre Cassen
 * Copyright (c) 2005 Christophe Varoqui
 */

#include "memory.h"
#include <stdlib.h>
#include "vector.h"

/*
 * Initialize vector struct.
 * allocated 'size' slot elements then return vector.
 */
vector
vector_alloc(void)
{
	vector v = (vector) MALLOC(sizeof (struct _vector));
	return v;
}

/* allocated one slot */
bool
vector_alloc_slot(vector v)
{
	void *new_slot = NULL;
	int new_allocated;
	int i;

	if (!v)
		return false;

	new_allocated = v->allocated + VECTOR_DEFAULT_SIZE;
	new_slot = REALLOC(v->slot, sizeof (void *) * new_allocated);
	if (!new_slot)
		return false;

	v->slot = new_slot;
	for (i = v->allocated; i < new_allocated; i++)
		v->slot[i] = NULL;

	v->allocated = new_allocated;
	return true;
}

int
vector_move_up(vector v, int src, int dest)
{
	void *value;
	int i;
	if (dest == src)
		return 0;
	if (dest > src || src >= v->allocated)
		return -1;
	value = v->slot[src];
	for (i = src - 1; i >= dest; i--)
		v->slot[i + 1] = v->slot[i];
	v->slot[dest] = value;
	return 0;
}

void *
vector_insert_slot(vector v, int slot, void *value)
{
	int i;

	if (!vector_alloc_slot(v))
		return NULL;

	for (i = VECTOR_SIZE(v) - 2; i >= slot; i--)
		v->slot[i + 1] = v->slot[i];

	v->slot[slot] = value;

	return v->slot[slot];
}

int
find_slot(vector v, void * addr)
{
	int i;

	if (!v)
		return -1;

	for (i = 0; i < VECTOR_SIZE(v); i++)
		if (v->slot[i] == addr)
			return i;

	return -1;
}

void
vector_del_slot(vector v, int slot)
{
	int i;

	if (!v || !v->allocated || slot < 0 || slot >= VECTOR_SIZE(v))
		return;

	for (i = slot + 1; i < VECTOR_SIZE(v); i++)
		v->slot[i-1] = v->slot[i];

	v->allocated -= VECTOR_DEFAULT_SIZE;

	if (v->allocated <= 0) {
		FREE(v->slot);
		v->slot = NULL;
		v->allocated = 0;
	} else {
		void *new_slot;

		new_slot = REALLOC(v->slot, sizeof (void *) * v->allocated);
		if (!new_slot)
			v->allocated += VECTOR_DEFAULT_SIZE;
		else
			v->slot = new_slot;
	}
}

void
vector_repack(vector v)
{
	int i;

	if (!v || !v->allocated)
		return;

	for (i = 0; i < VECTOR_SIZE(v); i++)
		if (i > 0 && v->slot[i] == NULL)
			vector_del_slot(v, i--);
}

vector
vector_reset(vector v)
{
	if (!v)
		return NULL;

	if (v->slot)
		FREE(v->slot);

	v->allocated = 0;
	v->slot = NULL;
	return v;
}

/* Free memory vector allocation */
void
vector_free(vector v)
{
	if (!vector_reset(v))
		return;
	FREE(v);
}

void
free_strvec(vector strvec)
{
	int i;
	char *str;

	if (!strvec)
		return;

	vector_foreach_slot (strvec, str, i)
		if (str)
			FREE(str);

	vector_free(strvec);
}

/* Set a vector slot value */
void
vector_set_slot(vector v, void *value)
{
	unsigned int i;

	if (!v)
		return;

	i = VECTOR_SIZE(v) - 1;
	v->slot[i] = value;
}

int vector_find_or_add_slot(vector v, void *value)
{
	int n = find_slot(v, value);

	if (n >= 0)
		return n;
	if (!vector_alloc_slot(v))
		return -1;
	vector_set_slot(v, value);
	return VECTOR_SIZE(v) - 1;
}
