/*
 * Copyright (c) 2002, 2003, 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 <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "sg-util.h"
#include "st-dialog-api.h"
#include "st-settings.h"
#include "st-transfer.h"
#include "st-shell.h"

/*** variable declarations ***************************************************/

STSettings st_settings;
G_LOCK_DEFINE(st_settings);

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

static gboolean st_settings_load_disabled_plugins_list (GError **err);

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

/**
 * st_settings_get_private_dir:
 *
 * Gets the streamtuner private directory (the value passed to the -d
 * command line argument, or ~/.streamtuner).
 *
 * Return value: the private directory.
 **/
const char *
st_settings_get_private_dir (void)
{
  return st_settings.private_dir;
}

/**
 * st_settings_get_music_dir:
 *
 * Gets the streamtuner music directory, which can be set by the user
 * from the preferences.
 *
 * Return value: the music directory, or %NULL if unset. The returned
 * string must be freed when no longer needed.
 **/
char *
st_settings_get_music_dir (void)
{
  char *converted = NULL;

  G_LOCK(st_settings);
  if (st_settings.music_dir)
    {
      GError *err = NULL;

      converted = g_filename_from_utf8(st_settings.music_dir, -1, NULL, NULL, &err);
      if (! converted)
	{
	  st_notice(_("unable to convert st_settings.music_dir to the encoding for filenames: %s"), err->message);
	  g_error_free(err);
	}
    }
  G_UNLOCK(st_settings);

  return converted;
}

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

void
st_settings_init (const char *custom_private_dir)
{
  const char *home;
  const char *local_root;
  
  if (! (home = g_get_home_dir()))
    {
      st_error_dialog(_("A fatal error has occurred"),
		      _("Could not find your home directory."));
      exit(1);
    }

  st_settings.private_dir = custom_private_dir
    ? custom_private_dir
    : g_build_filename(home, ".streamtuner", NULL);

  st_settings.config_file = g_build_filename(st_settings.private_dir, "config", NULL);
  st_settings.cache_dir = g_build_filename(st_settings.private_dir, "cache", NULL);
  st_settings.accels_file = g_build_filename(st_settings.private_dir, "accels", NULL);
  st_settings.splash_disabled_file = g_build_filename(st_settings.private_dir, "splash-disabled", NULL);
  st_settings.disabled_plugins_file = g_build_filename(st_settings.private_dir, "disabled-plugins", NULL);
  st_settings.images_dir = g_build_filename(st_settings.private_dir, "images", NULL);

  /*
   * We don't store this setting into the config file because we need
   * it earlier in the initialization phase.
   */
  st_settings.splash_enabled = ! g_file_test(st_settings.splash_disabled_file, G_FILE_TEST_EXISTS);

  st_settings.view_toolbar = TRUE;
  st_settings.view_tabs = TRUE;
  st_settings.view_tab_icons = TRUE;
  st_settings.view_statusbar = TRUE;

  st_settings.toolbar_style = ST_SHELL_TOOLBAR_STYLE_GTK;
  st_settings.toolbar_size = ST_SHELL_TOOLBAR_SIZE_GTK;

  st_settings.main_window_width = 600;
  st_settings.main_window_height = 400;

  st_settings.preferences_window_width = 400;
  st_settings.preferences_window_height = -1;

  st_settings.preferences_selected_page = NULL;
  st_settings.preferences_plugins_expanded = TRUE;

  st_settings.stream_properties_window_width = -1;

  st_settings.stream_columns_window_width = 330;
  st_settings.stream_columns_window_height = 220;

  st_settings.proxy_enabled = FALSE;
  st_settings.proxy_type = ST_TRANSFER_PROXY_HTTP;
  st_settings.proxy_server = NULL;
  st_settings.proxy_port = 8080; /* a good default for a HTTP proxy */

  st_settings.proxy_auth_enabled = FALSE;
  st_settings.proxy_auth_name = NULL;
  st_settings.proxy_auth_password = NULL;

  st_settings.selected_handler_name = NULL;
  
  st_settings.always_reload = FALSE;

  st_settings.find_token = NULL;
  st_settings.find_history = NULL;
  st_settings.find_case_sensitive = FALSE;
  st_settings.find_wrap_around = FALSE;

  /*
   * We don't store this setting into the config file because we need
   * it before loading plugins, but the config file is loaded after
   * that.
   */
  st_settings.disabled_plugins = NULL;
  if (g_file_test(st_settings.disabled_plugins_file, G_FILE_TEST_IS_REGULAR))
    {
      GError *err = NULL;

      if (! st_settings_load_disabled_plugins_list(&err))
	{
	  char *normalized;

	  normalized = st_dialog_normalize(err->message);
	  
	  st_error_dialog(_("Unable to load list of disabled plugins"), "%s", normalized);

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

  /* we support the deprecated STREAMTUNER_LOCAL_ROOT environment variable */
  local_root = g_getenv("STREAMTUNER_LOCAL_ROOT");
  if (local_root)
    {
      GError *err = NULL;

      st_settings.music_dir = g_filename_to_utf8(local_root, -1, NULL, NULL, &err);
      if (! st_settings.music_dir)
	{
	  st_notice(_("unable to convert the contents of the STREAMTUNER_LOCAL_ROOT environment variable to UTF-8 encoding: %s"), err->message);
	  g_error_free(err);
	}
    }
  else
    st_settings.music_dir = NULL;
}

gboolean
st_settings_save_splash_enabled (GError **err)
{
  if (g_file_test(st_settings.splash_disabled_file, G_FILE_TEST_EXISTS))
    {
      if (st_settings.splash_enabled)
	{
	  if (unlink(st_settings.splash_disabled_file) < 0)
	    {
	      g_set_error(err, 0, 0, _("unable to unlink %s: %s"), st_settings.splash_disabled_file, g_strerror(errno));
	      return FALSE;
	    }
	}
    }
  else
    {
      if (! st_settings.splash_enabled)
	{
	  GError *tmp_err = NULL;
	  GIOChannel *channel;
	  gboolean status;

	  channel = g_io_channel_new_file(st_settings.splash_disabled_file, "w", &tmp_err);
	  if (! channel)
	    {
	      g_set_error(err, 0, 0, _("unable to create %s: %s"), st_settings.splash_disabled_file, tmp_err->message);
	      g_error_free(tmp_err);
	      
	      return FALSE;
	    }

	  status = g_io_channel_shutdown(channel, TRUE, &tmp_err) == G_IO_STATUS_NORMAL;
	  g_io_channel_unref(channel);

	  if (! status)
	    {
	      g_set_error(err, 0, 0, _("unable to close %s: %s"), st_settings.splash_disabled_file, tmp_err->message);
	      g_error_free(tmp_err);

	      return FALSE;
	    }
	}
    }

  return TRUE;
}

static gboolean
st_settings_load_disabled_plugins_list (GError **err)
{
  GError *tmp_err = NULL;
  GIOChannel *channel;
  GIOStatus status;
  char *line;
  gsize terminator_pos;

  channel = g_io_channel_new_file(st_settings.disabled_plugins_file, "r", &tmp_err);
  if (! channel)
    {
      g_set_error(err, 0, 0, _("unable to open %s: %s"), st_settings.disabled_plugins_file, tmp_err->message);
      g_error_free(tmp_err);
      return FALSE;
    }

  while ((status = g_io_channel_read_line(channel, &line, NULL, &terminator_pos, &tmp_err)) == G_IO_STATUS_NORMAL)
    {
      if (terminator_pos >= 0)
	line[terminator_pos] = 0;

      st_settings.disabled_plugins = g_slist_append(st_settings.disabled_plugins, g_strdup(line));
      g_free(line);
    }

  if (status == G_IO_STATUS_EOF)
    {
      status = g_io_channel_shutdown(channel, TRUE, &tmp_err);
      g_io_channel_unref(channel);

      if (status == G_IO_STATUS_NORMAL)
	return TRUE;
      else
	{
	  g_set_error(err, 0, 0, _("unable to close %s: %s"), st_settings.disabled_plugins_file, tmp_err->message);
	  g_error_free(tmp_err);

	  return FALSE;
	}
    }
  else
    {
      g_set_error(err, 0, 0, _("unable to read %s: %s"), st_settings.disabled_plugins_file, tmp_err->message);
      g_error_free(tmp_err);

      status = g_io_channel_shutdown(channel, TRUE, NULL);
      g_io_channel_unref(channel);

      return FALSE;
    }
}

gboolean
st_settings_save_disabled_plugins_list (GError **err)
{
  GError *tmp_err = NULL;
  GIOChannel *channel;
  GSList *l;
  gboolean status = TRUE;

  channel = g_io_channel_new_file(st_settings.disabled_plugins_file, "w", &tmp_err);
  if (! channel)
    {
      g_set_error(err, 0, 0, _("unable to open %s for writing: %s"), st_settings.disabled_plugins_file, tmp_err->message);
      g_error_free(tmp_err);
      return FALSE;
    }

  SG_LIST_FOREACH(l, st_settings.disabled_plugins)
    {
      const char *filename = l->data;
      char *line;

      line = g_strconcat(filename, "\n", NULL);
      if (g_io_channel_write_chars(channel, line, -1, NULL, &tmp_err) != G_IO_STATUS_NORMAL)
	{
	  g_set_error(err, 0, 0, _("unable to write %s: %s"), st_settings.disabled_plugins_file, tmp_err->message);
	  g_error_free(tmp_err);
	  status = FALSE;
	}
      g_free(line);

      if (! status)
	break;
    }

  if (status)
    {
      status = g_io_channel_shutdown(channel, TRUE, &tmp_err) == G_IO_STATUS_NORMAL;
      g_io_channel_unref(channel);

      if (! status)
	{
	  g_set_error(err, 0, 0, _("unable to close %s: %s"), st_settings.disabled_plugins_file, tmp_err->message);
	  g_error_free(tmp_err);
	}
    }
  else
    {
      g_io_channel_shutdown(channel, TRUE, NULL);
      g_io_channel_unref(channel);
    }
  
  return status;
}
