/*
 * Copyright (c) 2003 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <string.h>
#include <glib.h>

#ifndef ST_REGRESSION_TEST

#include <glib-object.h>
#include "sg-util.h"

/*** function declarations ***************************************************/

static gboolean sg_objects_free_node_cb (GNode *node, gpointer data);

/*** implementation **********************************************************/

char *
sg_str_sentencize (const char *str)
{
  char *sentencized;
  int len;

  g_return_val_if_fail(str != NULL, NULL);

  len = strlen(str);

  if (len > 0
      && str[len - 1] != '.'
      && str[len - 1] != '!'
      && str[len - 1] != '?')
    sentencized = g_strconcat(str, ".", NULL);
  else
    sentencized = g_strdup(str);
  
  if (sentencized[0])
    sentencized[0] = g_ascii_toupper(sentencized[0]);

  return sentencized;
}

void
sg_pointers_free (GSList *pointers)
{
  GSList *l;

  SG_LIST_FOREACH(l, pointers)
    g_free(l->data);

  g_slist_free(pointers);
}

void
sg_objects_free (GSList *objects)
{
  GSList *l;

  SG_LIST_FOREACH(l, objects)
    g_object_unref(l->data);

  g_slist_free(objects);
}

void
sg_objects_free_node (GNode *objects)
{
  g_return_if_fail(objects != NULL);

  g_node_traverse(objects,
		  G_PRE_ORDER,
		  G_TRAVERSE_ALL,
		  -1,
		  sg_objects_free_node_cb,
		  NULL);
  g_node_destroy(objects);
}

static gboolean
sg_objects_free_node_cb (GNode *node, gpointer data)
{
  if (node->data)
    g_object_unref(node->data);

  return FALSE;			/* continue */
}

int
sg_utf8_strcmp (const char *s1, const char *s2)
{
  int cmp;
  char *normalized_s1;
  char *normalized_s2;

  g_return_val_if_fail(s1 != NULL, 0);
  g_return_val_if_fail(s2 != NULL, 0);

  normalized_s1 = g_utf8_normalize(s1, -1, G_NORMALIZE_ALL);
  normalized_s2 = g_utf8_normalize(s2, -1, G_NORMALIZE_ALL);
  
  cmp = strcmp(normalized_s1, normalized_s2);

  g_free(normalized_s1);
  g_free(normalized_s2);

  return cmp;
}

gboolean
sg_utf8_strcontains (const char *big, const char *little)
{
  gboolean contains;
  char *normalized_big;
  char *normalized_little;

  g_return_val_if_fail(big != NULL, FALSE);
  g_return_val_if_fail(little != NULL, FALSE);

  normalized_big = g_utf8_normalize(big, -1, G_NORMALIZE_ALL);
  normalized_little = g_utf8_normalize(little, -1, G_NORMALIZE_ALL);

  contains = strstr(normalized_big, normalized_little) != NULL;

  g_free(normalized_big);
  g_free(normalized_little);

  return contains;
}

gboolean
sg_utf8_strcasecontains (const char *big, const char *little)
{
  gboolean contains;
  char *normalized_big;
  char *normalized_little;
  char *case_normalized_big;
  char *case_normalized_little;

  g_return_val_if_fail(big != NULL, FALSE);
  g_return_val_if_fail(little != NULL, FALSE);

  normalized_big = g_utf8_normalize(big, -1, G_NORMALIZE_ALL);
  normalized_little = g_utf8_normalize(little, -1, G_NORMALIZE_ALL);
  case_normalized_big = g_utf8_casefold(normalized_big, -1);
  case_normalized_little = g_utf8_casefold(normalized_little, -1);

  contains = strstr(case_normalized_big, case_normalized_little) != NULL;

  g_free(normalized_big);
  g_free(normalized_little);
  g_free(case_normalized_big);
  g_free(case_normalized_little);

  return contains;
}

char *
sg_value_array_get_string (GValueArray *value_array)
{
  GString *string;
  int i;

  g_return_val_if_fail(value_array != NULL, NULL);

  string = g_string_new(NULL);
  for (i = 0; i < value_array->n_values; i++)
    {
      GValue *value = g_value_array_get_nth(value_array, i);
      GValue transformed = { 0, };

      g_value_init(&transformed, G_TYPE_STRING);
      if (g_value_transform(value, &transformed))
	{
	  if (*string->str)
	    g_string_append_printf(string, ", %s", g_value_get_string(&transformed));
	  else
	    g_string_append(string, g_value_get_string(&transformed));
	}
      g_value_unset(&transformed);
    }

  return g_string_free(string, FALSE);
}

void
sg_string_append_escaped (GString *string, const char *str)
{
  char *escaped;

  g_return_if_fail(string != NULL);
  g_return_if_fail(str != NULL);

  escaped = g_markup_escape_text(str, -1);

  g_string_append(string, escaped);
  g_free(escaped);
}

void
sg_string_append_printf_escaped (GString *string, const char *format, ...)
{
  va_list args;

  g_return_if_fail(string != NULL);
  g_return_if_fail(format != NULL);

  va_start(args, format);
  sg_string_append_vprintf_escaped(string, format, args);
  va_end(args);
}

void
sg_string_append_vprintf_escaped (GString *string,
				  const char *format,
				  va_list args)
{
  char *escaped;

  g_return_if_fail(string != NULL);
  g_return_if_fail(format != NULL);

  escaped = g_markup_vprintf_escaped(format, args);

  g_string_append(string, escaped);
  g_free(escaped);
}

gboolean
sg_str_slist_contains (GSList *list, const char *str)
{
  GSList *l;

  g_return_val_if_fail(str != NULL, FALSE);

  SG_LIST_FOREACH(l, list)
    if (! strcmp(l->data, str))
      return TRUE;

  return FALSE;
}

GValue *
sg_value_new (GType type)
{
  GValue *value;

  value = g_new0(GValue, 1);
  g_value_init(value, type);

  return value;
}

void
sg_value_free (GValue *value)
{
  g_return_if_fail(G_IS_VALUE(value));

  g_value_unset(value);
  g_free(value);
}

void
sg_slist_push (GSList **list, gpointer data)
{
  g_return_if_fail(list != NULL);

  *list = g_slist_prepend(*list, data);
}

gpointer
sg_slist_peek (GSList *list)
{
  return list ? list->data : NULL;
}

gpointer
sg_slist_pop (GSList **list)
{
  gpointer data;

  g_return_val_if_fail(list != NULL, NULL);

  data = sg_slist_peek(*list);
  *list = g_slist_delete_link(*list, *list);

  return data;
}

gboolean
sg_double_equal (double a, double b)
{
  return ! (a < b || a > b);
}
#endif /* ! ST_REGRESSION_TEST */

gboolean
sg_ascii_validate (const char *str)
{
  int i;

  g_return_val_if_fail(str != NULL, FALSE);

  for (i = 0; str[i]; i++)
    if ((unsigned char) str[i] > 127)
      return FALSE;

  return TRUE;
}

char *
sg_ascii_strcasestr (const char *big, const char *little)
{
  char *lower_big;
  char *lower_little;
  char *s;

  g_return_val_if_fail(big != NULL, NULL);
  g_return_val_if_fail(little != NULL, NULL);

  lower_big = g_ascii_strdown(big, -1);
  lower_little = g_ascii_strdown(little, -1);
  
  s = strstr(lower_big, lower_little);
  
  g_free(lower_big);
  g_free(lower_little);

  return s ? (char *) big + (s - lower_big) : NULL;
}
