/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * util.c
 *
 *  Created on: 04.08.2010
 *      Author: Umer Kayani <u.kayani@tarent.de>,
 *              Hendrik Helwich <h.helwich@tarent.de>,
 *              Peter Neuhaus <p.neuhaus@tarent.de>,
 *              Andreas Grau <a.grau@tarent.de>
 */

/*
 * This program 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 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 Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
 */

#define _BSD_SOURCE

#include <ctype.h>
#include "util.h"
#include "logging.h"
#include "./structs/common.h"

/**
 * Tokenize string.
 *
 * str   - the input string that is tokenized
 * delim - a string that delimits the tokens (not a set of characters
 *         as in strtok()
 *
 * Return value: a pointer to pointer of char (array of strings). Uses
 *         NULL as last element (terminator).
 *
 * use free_str_tokens() to free memory of returned data structure.
 */
gchar **str_split(const gchar *str, const gchar *delim)
{
	const gchar *head = str;		/* pointer to start of substring */
	size_t l = 0;				/* length of current token */
	size_t n_delim = strlen(delim) - 1;	/* last element of delimiter */

	guint buf_chunk = 16;			/* number of tokens per allocation */
	guint buf_size = 0;			/* size of currently allocated memory */
	guint tokc = 0;				/* token counter */

	gint is_tok = 0;			/* true if end of token is reached */

	gchar **tokens = NULL;			/* result array of string tokens */

	while (1) {

		/* detect and skip delimiter */
		guint i;
		for (i = 0; i <= n_delim; ++i) {
			if (str[i] != delim[i])
				break;		/* no delimiter */

			if (i == n_delim)	/* delimiter found */
				is_tok = 1;
		}

		/* handle current token */
		if (is_tok || *str == '\0') { /* end of current token */
			/* allocate new memory if neccessary */
			if (tokc + 1 >= buf_size) { /* +1 for terminating NULL pointer */
				buf_size += buf_chunk;
				tokens = realloc(tokens, sizeof(gchar*) * buf_size);
			}

			/* copy current token */
			tokens[tokc] = malloc(sizeof(gchar)*l + 1);
			if (l) memcpy(tokens[tokc], head, sizeof(gchar) * l);
			tokens[tokc][l] = '\0';

			++tokc;

			/* end of input string */
			if (*str == '\0')
				break;

			/* reset for new token */
			l = 0;
			str += n_delim + 1;
			head = str;
			is_tok = 0;
		} else { /* inside current token, */
			++str;	/* next character */
			++l;
		}
	}

	/* append terminating NULL pointer */
	tokens[tokc] = NULL;

	return tokens;
}

/**
 * free memory of pointer to pointer of char
 */
void free_str_tokens(char **tok)
{
	gint i;
	for (i = 0; tok[i]; ++i)
		free(tok[i]);	/* free single tokens */

	free(tok);		/* free array of tokens */
}
gchar*
trim_all_spaces (gchar* str)
{
	guint pos = 0, i;
	size_t len = strlen (str);
	gchar* out = str;

	for (i = 0; i < len; i++)
		if (!isspace (str[i]))
			out[pos++] = str[i];

	out[pos] = '\0';

	return out;
}

static gchar*
ltrim (gchar* s)
{
	while (isspace (*s))
		s++;
	return s;
}

static gchar*
rtrim (gchar* s)
{
	gchar* back = s + strlen (s);
	while (isspace (*--back))
		;
	*(back + 1) = '\0';
	return s;
}

gchar*
trim (gchar *s)
{
	return rtrim (ltrim (s));
}



/**
 * print method for debugging
 */
void
print_klb_mail(Kolab_conv_mail *klb_mail)
{
	guint i=0;
	log_debug("\n*********************Printing KolabConvMail:***************************");
	if (klb_mail)
		for (i=0; i<klb_mail->length; i++) {
			log_debug("\n\tName: %s", klb_mail->mail_parts[i].name);
			log_debug("\n\tMimeType: %s", klb_mail->mail_parts[i].mime_type);
			if (klb_mail->mail_parts[i].data) {
				log_debug("\n\tLength: %d", klb_mail->mail_parts[i].length) ;
				if( strcmp(klb_mail->mail_parts[i].mime_type, "application/x-vnd.kolab.contact") == 0)
					log_debug("\n\tXML: %s", klb_mail->mail_parts[i].data);
			}
		}
	log_debug("\n***************************************************************************\n");
}

/**
 * Creates an array of Kolab_conv_mail_part structures from a linked list of
 * this structs.
 * The given list will be freed inside this function and must not be use after
 * calling this function.
 * No new memory will be allocated for the content of this structures (name,
 * mimetype and data).
 * The list order will not be changed.
 *
 * @return A pointer to an array of Kolab_conv_mail_part structures
 */
Kolab_conv_mail*
g_list_to_kolab_conv_mail (GList *glist)
{
	Kolab_conv_mail *kmail = g_new0(Kolab_conv_mail, 1);
	kmail->length = g_list_length(glist);

	if (kmail->length > 0) {
		int counter = 0;

		kmail->mail_parts = g_new0(Kolab_conv_mail_part, kmail->length);

		for (; glist; glist = glist->next, counter++) {
			Kolab_conv_mail_part *mp = kmail->mail_parts+counter;
			memcpy(mp, glist->data, sizeof (Kolab_conv_mail_part));
			g_free(glist->data);
		}
	}

	g_list_free(glist);

	return kmail;
}

/**
 * creates a copy of a Kolab_conv_mail_part struct and its content.
 * It can be freed by kolabconv_free_kmail_part().
 */
Kolab_conv_mail_part*
clone_kolab_conv_mail_part(Kolab_conv_mail_part *mpart)
{
	Kolab_conv_mail_part *mpart_cpy = g_new0(Kolab_conv_mail_part, 1);
	mpart_cpy->name = g_strdup (mpart->name);
	mpart_cpy->mime_type = g_strdup (mpart->mime_type);
	mpart_cpy->length = mpart->length;
	mpart_cpy->data = g_new0(gchar, mpart->length);
	memcpy (mpart_cpy->data, mpart->data, mpart->length);
	return mpart_cpy;
}



/* TODO: Work on array directly and do not create a list; remove this operation when done. */
GList*
klb_conv_mail_to_g_list (const Kolab_conv_mail* klb_mail)
{
	GList *klb_mail_list = NULL;
	Kolab_conv_mail_part *klb_mail_part = NULL;
	guint i;

	if (klb_mail)
		for (i=0; i<klb_mail->length; i++) {
			klb_mail_part = g_new0(Kolab_conv_mail_part, 1);
			if (klb_mail->mail_parts[i].name)
				klb_mail_part->name = g_strdup(klb_mail->mail_parts[i].name);
			klb_mail_part->mime_type = g_strdup(klb_mail->mail_parts[i].mime_type);
			if (klb_mail->mail_parts[i].data) {
				klb_mail_part->length = klb_mail->mail_parts[i].length ;
				klb_mail_part->data = g_new0(gchar, (size_t)klb_mail->mail_parts[i].length );
				memcpy (klb_mail_part->data, klb_mail->mail_parts[i].data, klb_mail->mail_parts[i].length);
			}

			klb_mail_list = g_list_append(klb_mail_list, (Kolab_conv_mail_part *) klb_mail_part);
		}

	return klb_mail_list;
}


/**
 * wrapper operation for timegm().
 */
time_t
time_gm(struct tm *tm)
{
	return timegm(tm);
	/* TRICKY: more portable code of the above line increases the number of
	 *         instructions for the unit tests by ca the factor of 2.2.
	 *         If you get problems with porting the code, it could be helpful
	 *         to replace the line above by the code below.
	 */

	/* portable version of BSD timegm(). cf. manpage for timegm(): */

#if 0
	time_t ret;
	char *tz;

	tz = getenv("TZ");
	setenv("TZ", "", 1);
	tzset();
	ret = mktime(tm);
	if (tz)
		setenv("TZ", tz, 1);
	else
		unsetenv("TZ");
	tzset();
	return ret;
#endif
}
