/*
    scconfig - library for making includes on a list unique
    Copyright (C) 2012  Tibor Palinkas

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

		Project page: http://repo.hu/projects/scconfig
		Contact via email: scconfig [at] igor2.repo.hu
*/

#include <stdlib.h>
#include <string.h>
#include "libs.h"
#include "db.h"

#define grow \
	if (used >= alloced) { \
		alloced += 16; \
		list = realloc(list, alloced * sizeof(char *)); \
	}

char **uniq_inc_arr(const char *includes, int indirect, const char *sep_, int *numlines)
{
	char *node, *next, *cw, *nw, *snode, *orig_node;
	char *sep;
	char **list;
	int alloced, used, n;

	orig_node = strclone(includes);
	node = orig_node;
	if (sep_ == NULL)
		sep = strclone("\n\r");
	else
		sep = strclone(sep_);

	/* reset list */
	alloced = used = 0;
	list = NULL;
	/* take arguments one by one */
	while(node != NULL) {
		if (indirect) {
			while((*node == ' ') || (*node == '\t')) node++;
			next = strpbrk(node, " \t");
		}
		else {
			for(;;) {
				next = strpbrk(node, sep);
				if ((next > node) || (next == NULL))
					break;
				node = next+1;
			}
		}
		if (next != NULL) {
			*next = '\0';
			next++;
		}
		if (indirect)
			snode = str_subsn(get(node));
		else
			snode = node;
		cw = snode;
		/* split node value (s) by sep */
/*		fprintf(stderr, "nodename=%s snode=%s next=%s\n", node, snode, next);*/
		while(cw != NULL) {
			nw = strpbrk(cw, sep);
			if (nw != NULL) {
				*nw = '\0';
				nw++;
			}

			if (*cw != '\0') {
				/* try to find cw in the existing list - this is a slow linear search for now */
				for(n = 0; n < used; n++) {
					if (strcmp(list[n], cw) == 0)
						goto already_on_list;
				}
				/* not found, append */
				grow;
				list[used] = strclone(cw);
				used++;
			}
			already_on_list:;
			cw = nw;
		}
		if (indirect)
			free(snode);
		node = next;
	}
	grow
	list[used] = NULL;
	if (numlines != NULL)
		*numlines = used;

	free(orig_node);
	free(sep);

	return list;
}

void uniq_inc_free(char **arr)
{
	char **s;
	for(s = arr; *s != NULL; s++)
		free(*s);
	free(arr);
}

static int uniq_inc_str_cmp(const void *a_, const void *b_)
{
	char **a = (char **)a_, **b = (char **)b_;
	return strcmp(*a, *b);
}

char *uniq_inc_str(const char *includes, const char *isep, const char *osep, int sort)
{
	char **arr, **s, *ret, *end;
	int len, numelem, oseplen;

	oseplen = strlen(osep);
	arr = uniq_inc_arr(includes, 0, isep, NULL);

	len = 4; /* safety margin, for terminator \0, etc. */
	numelem = 0;
	for(s = arr; *s != NULL; s++) {
		len += strlen(*s) + oseplen + 1;
		numelem++;
	}

	if (sort)
		qsort(arr, numelem, sizeof(char *), uniq_inc_str_cmp);

	ret = malloc(len);

	for(end = ret, s = arr; *s != NULL; s++) {
		len = strlen(*s);
		memcpy(end, *s, len);
		end += len;
		memcpy(end, osep, oseplen);
		end += oseplen;
		free(*s);
	}
	*end = '\0';

	free(arr);
	return ret;
}
