/*
 * Copyright (c) 2004 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 "config.h"
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "sgtk-hig.h"
#include "st-action.h"
#include "st-dialog-api.h"
#include "st-util.h"

/*** API implementation ******************************************************/

/**
 * st_format_bitrate:
 * @bitrate: a bitrate to format, expressed in kilobits per seconds.
 *
 * Formats @bitrate as a string.
 *
 * Return value: @bitrate formatted as a string, which should be freed
 * when no longer needed.
 **/
char *
st_format_bitrate (int bitrate)
{
  g_return_val_if_fail(bitrate > 0, NULL);
  return g_strdup_printf(_("%i kbps"), bitrate);
}

/**
 * st_format_samplerate:
 * @samplerate: a samplerate to format, expressed in Hz.
 *
 * Formats @samplerate as a string.
 *
 * Return value: @samplerate formatted as a string, which should be
 * freed when no longer needed.
 **/
char *
st_format_samplerate (int samplerate)
{
  g_return_val_if_fail(samplerate > 0, NULL);
  return g_strdup_printf(_("%i Hz"), samplerate);
}

/**
 * st_format_channels:
 * @channels: a number of audio channels, which must be greater than
 * 0.
 *
 * Formats @channels as a string.
 *
 * Return value: @channels formatted as a string, which should be
 * freed when no longer needed.
 **/
char *
st_format_channels (int channels)
{
  g_return_val_if_fail(channels > 0, NULL);
  switch (channels)
    {
    case 1:	return g_strdup(_("Mono"));
    case 2:	return g_strdup(_("Stereo"));
    default:	return g_strdup_printf(ngettext("%i channel", "%i channels", channels), channels);
    }
}

/**
 * st_format_audio_properties:
 * @bitrate: a bitrate expressed in kbps, or 0.
 * @samplerate: a samplerate expressed in kbps, or 0.
 * @channels: a number of audio channels, or 0.
 *
 * Formats @bitrate, @samplerate and @channels as a string.
 *
 * Return value: a formatted string, which should be freed when no
 * longer needed.
 **/
char *
st_format_audio_properties (int bitrate,
			    int samplerate,
			    int channels)
{
  GString *audio;
  char *str;

  audio = g_string_new(NULL);

  if (bitrate > 0)
    {
      str = st_format_bitrate(bitrate);
      g_string_append(audio, str);
      g_free(str);
    }
  
  if (samplerate > 0)
    {
      if (*audio->str)
	g_string_append(audio, ", ");

      str = st_format_samplerate(samplerate);
      g_string_append(audio, str);
      g_free(str);
    }
  
  if (channels > 0)
    {
      if (*audio->str)
	g_string_append(audio, ", ");

      str = st_format_channels(channels);
      g_string_append(audio, str);
      g_free(str);
    }

  if (*audio->str)
    return g_string_free(audio, FALSE);
  else
    {
      g_string_free(audio, TRUE);
      return NULL;
    }
}

/**
 * st_strchr_span:
 * @str: a string.
 * @c: a character to locate, which must not be 0.
 *
 * Locates the first occurrence of @c (converted to a char) in @str.
 *
 * Return value: a pointer to the character following the first
 * occurrence of @c in @str, or %NULL if @c does not appear in @str.
 **/
char *
st_strchr_span (const char *str, int c)
{
  char *s;

  g_return_val_if_fail(str != NULL, NULL);
  g_return_val_if_fail(c != 0, NULL);

  s = strchr(str, c);
  if (s)
    s++;

  return s;
}

/**
 * st_strstr_span:
 * @big: a string.
 * @little: a string to search for in @big.
 *
 * Locates the first occurrence of @little in @big.
 *
 * Return value: a pointer to the character following the first
 * occurrence of @little in @big, or %NULL if @little does not appear
 * in @big.
 **/
char *
st_strstr_span (const char *big, const char *little)
{
  char *s;

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

  s = strstr(big, little);
  if (s)
    s += strlen(little);

  return s;
}

/**
 * st_str_has_prefix_span:
 * @str: a string.
 * @prefix: the prefix to look for.
 *
 * Checks if @str begins with @prefix.
 *
 * Return value: a pointer to the character following @prefix in @str,
 * or %NULL if @str does not begin with @prefix.
 **/
char *
st_str_has_prefix_span (const char *str, const char *prefix)
{
  g_return_val_if_fail(str != NULL, NULL);
  g_return_val_if_fail(prefix != NULL, NULL);

  return g_str_has_prefix(str, prefix)
    ? (char *) str + strlen(prefix)
    : NULL;
}

/**
 * st_str_like:
 * @str: a string.
 * @charset: a set of characters.
 *
 * Checks if all the characters of @str are members of @charset.
 *
 * Return value: %TRUE if all the characters of @str are members of
 * @charset.
 **/
gboolean
st_str_like (const char *str, const char *charset)
{
  g_return_val_if_fail(str != NULL, FALSE);
  g_return_val_if_fail(charset != NULL, FALSE);

  return strspn(str, charset) == strlen(str);
}

/**
 * st_pixbuf_new_from_file:
 * @filename: the name of the file to load.
 *
 * Creates a new pixbuf by loading an image from a file. If the file
 * cannot be loaded, st_notice() will be used to print the error.
 *
 * Return value: a new #GdkPixbuf, or %NULL on error.
 **/
GdkPixbuf *
st_pixbuf_new_from_file (const char *filename)
{
  GdkPixbuf *pixbuf;
  GError *err = NULL;

  pixbuf = gdk_pixbuf_new_from_file(filename, &err);
  if (! pixbuf)
    {
      st_notice(_("error loading image: %s"), err->message);
      g_error_free(err);
    }

  return pixbuf;
}

/**
 * st_hig_section_new:
 * @title: the section title.
 * @contents: the widget to use as section contents.
 *
 * Creates a new HIG-compliant section, as defined by
 * <ulink url="http://developer.gnome.org/projects/gup/hig/2.0/design-window.html" type="http">Window Layout</ulink>.
 *
 * Return value: a new #GtkVBox containing @title and @contents.
 **/
GtkWidget *
st_hig_section_new (const char *title, GtkWidget *contents)
{
  GtkWidget *vbox;
  char *markup;
  GtkWidget *label;
  GtkWidget *alignment;

  g_return_val_if_fail(title != NULL, NULL);
  g_return_val_if_fail(GTK_IS_WIDGET(contents), NULL);

  vbox = gtk_vbox_new(FALSE, SGTK_HIG_CONTROL_SPACING);

  markup = g_markup_printf_escaped("<span weight=\"bold\">%s</span>", title);
  label = gtk_label_new(markup);
  g_free(markup);

  gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  gtk_label_set_use_markup(GTK_LABEL(label), TRUE);

  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

  alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
  gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);

  gtk_container_add(GTK_CONTAINER(alignment), contents);

  gtk_widget_show(alignment);
  gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);

  return vbox;
}

/**
 * st_set_tooltip:
 * @widget: a widget.
 * @tooltip: a tooltip text.
 *
 * Sets the tooltip of @widget using the global #GtkTooltips object
 * used by streamtuner.
 **/
void
st_set_tooltip (GtkWidget *widget, const char *tooltip)
{
  GtkTooltips *tooltips = NULL;

  g_return_if_fail(GTK_IS_WIDGET(widget));

  if (! tooltips)
    tooltips = gtk_tooltips_new();

  gtk_tooltips_set_tip(tooltips, widget, tooltip, NULL);
}

/*** private implementation **************************************************/

GtkWidget *
st_logo_new (void)
{
  GdkPixbuf *logo;
  GtkWidget *image;

  logo = st_pixbuf_new_from_file(ST_PNG("logo"));
  if (logo)
    {
      image = gtk_image_new_from_pixbuf(logo);
      g_object_unref(logo);
    }
  else
    image = gtk_image_new();

  return image;
}

void
st_show_help (const char *link_id)
{
#define filename BASEDOCDIR G_DIR_SEPARATOR_S "C" G_DIR_SEPARATOR_S "streamtuner.xml"
  if (g_file_test(filename, G_FILE_TEST_EXISTS))
    {
      char *uri;
      gboolean status;
      GError *err = NULL;
      
      uri = link_id
	? g_strconcat("ghelp://", filename, "?", link_id, NULL)
	: g_strconcat("ghelp://", filename, NULL);

      status = st_action_run("view-ghelp", uri, &err);
      g_free(uri);

      if (! status)
	{
	  char *normalized;

	  normalized = st_dialog_normalize(err->message);
	  g_error_free(err);

	  st_error_dialog(_("Unable to view the manual"), "%s", normalized);
	  g_free(normalized);
	}
    }
  else
    st_error_dialog(_("Unable to view the manual"),
		    _("The manual file %s does not exist."), filename);
#undef filename
}

void
st_visit_homepage (const char *url)
{
  GError *err = NULL;

  g_return_if_fail(url != NULL);

  if (! st_action_run("view-web", url, &err))
    {
      char *normalized;

      normalized = st_dialog_normalize(err->message);

      st_error_dialog(_("Unable to visit the homepage"), "%s", normalized);

      g_free(normalized);
      g_error_free(err);
    }
}

void
st_parser_msg_cb (GScanner *scanner, char *message, gboolean error)
{
  st_notice("%s:%i: %s", scanner->input_name, scanner->line, message);
}

void
st_window_set_icon (GtkWindow *window)
{
  GdkPixbuf *icon;

  g_return_if_fail(GTK_IS_WINDOW(window));

  icon = st_pixbuf_new_from_file(ST_PNG("streamtuner"));
  if (icon)
    {
      gtk_window_set_icon(window, icon);
      g_object_unref(icon);
    }
}
