/*
 * Copyright (C) 2005 iptelorg GmbH
 *
 * This file is part of ser, a free SIP server.
 *
 * ser 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
 *
 * For a license to use the ser software under conditions
 * other than those described here, or to purchase support for this
 * software, please contact iptel.org by e-mail at the following addresses:
 *    info@iptel.org
 *
 * ser 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.
 *
 * You should have received a copy of the GNU 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
 */

#include <cds/sstr.h>
#include <cds/memory.h>
#include <cds/dstring.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cds/logger.h>

/** returns 1 if the string is empty */
int is_str_empty(const str_t *s)
{
	if(!s)
		return 1;
	if((!s->s) || (s->len < 1))
		return 1;
	return 0;
}

int str_cmp_zt(const str_t *a, const char *b)
{
	int i;

	if(!a) {
		if(b)
			return 1;
		else
			return 0;
	}

	for(i = 0; (i < a->len) && (b[i]); i++) {
		if(a->s[i] < b[i])
			return -1;
		if(a->s[i] > b[i])
			return 1;
	}
	if(i < a->len)
		return 1;
	return 0;
}

int str_prefix(const str_t *a, const str_t *b)
{
	int i;
	if(!b)
		return 0;
	if(!a)
		return -1;

	if(b->len > a->len)
		return -1;
	for(i = 0; i < b->len; i++) {
		if(a->s[i] != b->s[i])
			return -1;
	}
	return 0;
}

str_t zt2str(char *str)
{
	str_t s;

	s.s = str;
	if(str)
		s.len = strlen(str);
	else
		s.len = 0;
	return s;
}

int str_dup_dbg(str_t *dst, const str_t *src, const char *file, int line)
{
	if(!dst)
		return -1;

	dst->len = 0;
	dst->s = NULL;
	if(!src)
		return 0;
	if((!src->s) || (src->len < 1))
		return 0;

	/* ERROR_LOG("can't allocate memory (%d bytes)\n", src->len); */
	DEBUG_LOG("str_dup called from %s:%d\n", file, line);
	dst->s = cds_malloc(src->len);
	if(!dst->s) {
		/* ERROR_LOG("can't allocate memory (%d bytes)\n", src->len); */
		return -1;
	}
	memcpy(dst->s, src->s, src->len);
	dst->len = src->len;
	return 0;
}

int str_dup_impl(str_t *dst, const str_t *src)
{
	if(!dst)
		return -1;

	dst->len = 0;
	dst->s = NULL;
	if(!src)
		return 0;
	if((!src->s) || (src->len < 1))
		return 0;

	dst->s = cds_malloc(src->len);
	if(!dst->s) {
		/* ERROR_LOG("can't allocate memory (%d bytes)\n", src->len); */
		return -1;
	}
	memcpy(dst->s, src->s, src->len);
	dst->len = src->len;
	return 0;
}

str_t *str_dup_new(const str_t *src)
{
	str_t *dst = cds_malloc(sizeof(str_t));
	if(dst)
		str_dup(dst, src);
	return dst;
}

int str_dup_zt(str_t *dst, const char *src)
{
	int len;
	if(!dst)
		return -1;

	dst->len = 0;
	dst->s = NULL;
	if(!src)
		return 0;
	len = strlen(src);
	if(len < 1)
		return 0;

	dst->s = cds_malloc(len);
	if(!dst->s)
		return -1;
	memcpy(dst->s, src, len);
	dst->len = len;
	return 0;
}

char *zt_strdup(const char *src)
{
	int len;
	char *dst;

	len = strlen(src);
	if(len < 0)
		return NULL;

	dst = cds_malloc(len + 1);
	if(dst)
		memcpy(dst, src, len + 1);
	return dst;
}

int str_nocase_equals(const str_t *a, const str_t *b)
{
	int i;

	if(!a) {
		if(!b)
			return 0;
		else
			return (b->len == 0) ? 0 : 1;
	}
	if(!b)
		return (a->len == 0) ? 0 : 1;
	if(a->len != b->len)
		return 1;

	for(i = 0; i < a->len; i++)
		if(tolower(a->s[i]) != tolower(b->s[i]))
			return 1;
	return 0;
}

int str_case_equals(const str_t *a, const str_t *b)
{
	int i;

	if(!a) {
		if(!b)
			return 0;
		else
			return (b->len == 0) ? 0 : 1;
	}
	if(!b)
		return (a->len == 0) ? 0 : 1;
	if(a->len != b->len)
		return 1;

	for(i = 0; i < a->len; i++)
		if(a->s[i] != b->s[i])
			return 1;
	return 0;
}

/* void str_free_content(str_t *s)
{
	if (!s) return;
	if ((s->len > 0) && (s->s)) cds_free(s->s);
	s->len = 0;
	s->s = NULL;
}

void str_free(str_t *s)
{
	if (s) {
		str_free_content(s);
		cds_free(s);
	}
}

void str_clear(str_t *s)
{
	if (s) {
		s->s = NULL;
		s->len = 0;
	}
} */

char *str_strchr(const str_t *s, char c)
{
	if(s) {
		int i;
		for(i = 0; i < s->len; i++)
			if(s->s[i] == c)
				return s->s + i;
	}
	return NULL;
}

char *str_str(const str_t *s, const str_t *search_for)
{
	int i, j;

	if(is_str_empty(search_for))
		return s->s;
	if(is_str_empty(s))
		return NULL;

	if(search_for->len > s->len)
		return NULL;

	j = 0;
	i = 0;
	while(i < s->len) {
		if(s->s[i] == search_for->s[j]) {
			j++;
			i++;
			if(j == search_for->len)
				return s->s + i - j;
		} else {
			i = i - j + 1;
			j = 0;
		}
	}
	return NULL;
}

/* creates new string as concatenation of a and b */
int str_concat(str_t *dst, str_t *a, str_t *b)
{
	int al;
	int bl;

	if(!dst)
		return -1;

	al = str_len(a);
	bl = str_len(b);

	dst->len = al + bl;
	if(dst->len > 0) {
		dst->s = (char *)cds_malloc(dst->len);
		if(!dst->s) {
			dst->len = 0;
			return -1;
		}
	} else {
		dst->s = NULL;
		dst->len = 0;
		return 0;
	}

	if(al)
		memcpy(dst->s, a->s, al);
	if(bl)
		memcpy(dst->s + al, b->s, bl);

	return 0;
}

int replace_str(
		const str_t *src, str_t *dst, const str_t *sample, const str_t *value)
{
	str_t s;
	char *c;
	dstring_t str;
	int res, len;

	/* if (!dst) return -1;
	 if (!src) {
		str_clear(dst);
		return -1;
	} */

	if(is_str_empty(sample)) {
		str_clear(dst);
		return -1;
	}

	if(is_str_empty(src)) {
		str_clear(dst);
		return 0;
	}

	s = *src;
	dstr_init(&str, src->len + 32);
	do {
		c = str_str(&s, sample);
		if(c) {
			len = c - s.s;
			dstr_append(&str, s.s, len);
			dstr_append_str(&str, value);
			s.len = s.len - len - sample->len;
			s.s = c + sample->len;
			if(s.len <= 0)
				break;
		} else
			dstr_append_str(&str, &s);
	} while(c);

	res = dstr_get_str(&str, dst);
	dstr_destroy(&str);
	return res;
}
