/*
 *  String Arrays (Null-terminated array of char *).
 *
 *  The StrArray owns copies of the strings it contains, and also deletes them.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "StrArray.h"

int strarray_get_length(char ** const array)
{
	int i;

	if (array == NULL)
		return 0;
	for (i=0; array[i] != NULL; i++)
		continue;
	return i;
}

int strarray_has_string(char **array, const char *s)
{
	int i;

	if (array == NULL)
		return 0;
	for (i=0; array[i] != NULL; i++)
	{
		if ((array[i] == s) || (0 == strcmp(array[i], s)))
			return i+1;
	}
	return 0;
}

char ** strarray_del(char **array)
{
	int i;

	if (array == NULL)
		return NULL;
	for (i=0; array[i] != NULL; i++)
		app_free(array[i]);
	app_free(array);
	return NULL;
}

char ** strarray_append_allocated(char **array, const char *s)
{
	int length = strarray_get_length(array);
	int roundup = ((length+2 + 15) / 16) * 16; /* +2 is for s and NULL */

	array = (char **) app_realloc(array, roundup * sizeof(char *));
	if (array) {
		array[length] = (char *) s;
		array[length+1] = NULL;
	}
	return array;
}

char ** strarray_append(char **array, const char *s)
{
	int length = strarray_get_length(array);
	int roundup = ((length+2 + 15) / 16) * 16; /* +2 is for s and NULL */

	array = (char **) app_realloc(array, roundup * sizeof(char *));
	if (array) {
		array[length] = app_copy_string(s);
		array[length+1] = NULL;
	}
	return array;
}

char ** strarray_remove(char **array, const char *s)
{
	int i;
	int length;
	int roundup;

	/* If array is empty, stop now. */
	if (array == NULL)
		return array;

	/* Find index of 's' within the array. */
	for (i = -1, length = 0; array[length] != NULL; length++)
	{
		if ((array[length] == s) || (0 == strcmp(array[length], s)))
		{
			i = length;
			break;
		}
	}

	/* If not found, stop now. */
	if (i == -1)
		return array;

	/* Delete the found element, since the array owns it. */
	app_free(array[i]);

	if (length == 1) {
		/* Found, and it must have been the first and only element. */
		/* So free the whole array. */
		app_free(array);
		return NULL;
	}

	/* Otherwise move the rest of the array down over the match. */
	memmove(&array[i], &array[i+1], (length - i) * sizeof(char *));
	roundup = ((length + 15) / 16) * 16;
	return app_realloc(array, roundup * sizeof(char *));
}

char ** strarray_split(const char *s, const char *sep)
{
	char *pos;
	const char *src = s;
	int seplen = strlen(sep);
	char **array = NULL;

	pos = strstr(src, sep);
	while (pos != NULL)
	{
		size_t length = pos - src;
		char *part = app_alloc(length + 1);
		if (part == NULL)
			break;
		memcpy(part, src, length);
		part[length] = '\0';
		array = strarray_append_allocated(array, part);

		src += length + seplen;
		pos = strstr(src, sep);
	}
	strarray_append(array, src);

	return array;
}

char * strarray_join(char **array, const char *sep)
{
	int i;
	int seplen;
	int length = 0;
	char *joined = NULL;

	if (array == NULL)
		return joined;

	seplen = strlen(sep);

	for (i=0; array[i] != NULL; i++)
	{
		char *next;
		char *s = array[i];
		int slen = strlen(s);
		int extra = slen;

		if (length > 0)
			extra += seplen;

		next = app_realloc(joined, length + extra + 1);
		if (next == NULL)
			break;
		joined = next;

		if (length > 0) {
			memcpy(joined + length, sep, seplen);
			length += seplen;
		}

		memcpy(joined + length, s, slen);
		length += slen;
	}
	joined[length] = '\0';

	return joined;
}

static int scmp(const void *sp1, const void *sp2)
{
	char *s = *((char **)sp1);
	char *t = *((char **)sp2);

	return strcmp(s, t);
}

char ** strarray_sort(char **array)
{
	if (array == NULL)
		return NULL;
	qsort(array, strarray_get_length(array), sizeof(array[0]), scmp);
	return array;
}

