/*
    Silky - A GTK+ client for SILC.
    Copyright (C) 2003, 2004, 2005 Toni Willberg

    - All log and debug -related stuff lives here.

    This program 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.

    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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    http://silky.sourceforge.net/

*/

#include <glib.h>
#include <glade/glade.h>
#include <gtk/gtk.h>


#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "preferences.h"

#include "ui_preferences.h"
#include "ui_console.h"

#include "xmlconfig.h"
#include "xmllayout.h"
#include "log.h"
#include "support.h"
#include "gui.h"
#include "servers.h"

extern GladeXML *xmlmain;
extern gchar *prefpath;
extern xmlDocPtr config_main;
extern SilkyServer *servers;

static struct {
  gchar *name;		/* human-readable preference name, also used by /set */
  gchar *widget;	/* widget name */
  gint widget_type;	/* type of widget */
  gint xmloption;	/* xml option number */
} preferences[] = {
  { "nickname",				"set_user_nickname",			WIDGET_ENTRY,		CM_USERINFO_NICKNAME },
  { "realname",				"set_user_realname",			WIDGET_ENTRY,		CM_USERINFO_REALNAME },
  { "quit_message",			"set_quitmessage",			WIDGET_ENTRY,		CM_USERINFO_QUITMESSAGE },
  { "highlight_words",			"set_opt_hilightwords",			WIDGET_ENTRY,		CM_GUI_HIGHLIGHTS_WORD },
  { "font",				"fontbutton",				WIDGET_FONTBUTTON,	CM_GUI_FONT },
  { "color_timestamp",			"colorbutton_timestamp",		WIDGET_COLORBUTTON,	CM_GUI_COLORS_TIMESTAMP },
  { "color_nickname",			"colorbutton_nickname",			WIDGET_COLORBUTTON, 	CM_GUI_COLORS_NICKNAMES },
  { "color_text",			"colorbutton_text",			WIDGET_COLORBUTTON, 	CM_GUI_COLORS_TEXT },
  { "color_action",			"colorbutton_action",			WIDGET_COLORBUTTON, 	CM_GUI_COLORS_ACTIONS },
  { "color_background",			"colorbutton_background",		WIDGET_COLORBUTTON, 	CM_GUI_COLORS_BACKGROUND },
  { "color_server_messages",		"colorbutton_server_messages",		WIDGET_COLORBUTTON,	CM_GUI_COLORS_SERVERMESSAGES },
  { "color_my_nickname",		"colorbutton_my_nickname",		WIDGET_COLORBUTTON, 	CM_GUI_COLORS_MYNICKNAME },
  { "color_my_text",			"colorbutton_my_text",			WIDGET_COLORBUTTON, 	CM_GUI_COLORS_MYTEXT },
  { "color_my_action",			"colorbutton_my_action",		WIDGET_COLORBUTTON, 	CM_GUI_COLORS_MYACTION },
  { "color_inputbox",			"colorbutton_input_box_text",		WIDGET_COLORBUTTON, 	CM_GUI_COLORS_INPUTBOX },
  { "highlight_own_nickname",		"set_opt_hilight_own_nick", 		WIDGET_CHECKBUTTON,	CM_GUI_HIGHLIGHTS_OWNNICK },
  { "sign_channel_messages",		"set_sign_channel_messages",		WIDGET_CHECKBUTTON,	CM_SECURITY_SIGN_CHANNEL_MESSAGES },
  { "sign_channel_actions",		"set_sign_channel_actions",		WIDGET_CHECKBUTTON,	CM_SECURITY_SIGN_CHANNEL_ACTIONS },
  { "sign_private_messages",		"set_sign_private_messages",		WIDGET_CHECKBUTTON,	CM_SECURITY_SIGN_PRIVATE_MESSAGES },
  { "sign_private_actions",		"set_sign_private_actions",		WIDGET_CHECKBUTTON,	CM_SECURITY_SIGN_PRIVATE_ACTIONS },
  { "command_history_depth",		"set_command_history_depth",		WIDGET_SPINBUTTON,	CM_GUI_CMDHISTORYDEPTH },
  { "show_tips",			"set_tips",				WIDGET_CHECKBUTTON,	CM_GUI_TIPS },
  { NULL,				NULL,					0,			0 }
};

static gchar *boolean_values[2][5] = {
  { PREF_ON,  "TRUE",  "YES", "1", NULL },
  { PREF_OFF, "FALSE", "NO",  "0", NULL }
};



/**
 * prefs_load_config:
 *
 * Attempt to load config file, first from user's homedir. If the file is not
 * found there, attempt to load config file from 'PREFIX/share/silky/'. If
 * that fails as well, create new config, using hard-coded defaults.
 *
 * Config is loaded into global variable referenced with xmlDocPtr #config_main.
 * This XML document entity is then cleaned up using xml_cleanup_config().
 *
 * Returns: true if a config was succesfully loaded, false otherwise
 **/

gboolean prefs_load_config() {
  gchar *globalprefpath;

  debug("checking for file '%s'", prefpath);
  if( g_file_test(prefpath, G_FILE_TEST_EXISTS) ) {
    debug("..found, trying to load and parse it");
    config_main = xml_read_config(CONFIG_MAIN, prefpath);
  } else {
    debug("..not found, trying to load a site-wide config...");
#ifdef SILKY_WIN32
    globalprefpath = ".\\data\\silky.conf";
#else
    globalprefpath = g_strconcat(GLADEDIR, "silky.conf", NULL);
#endif
    if( g_file_test(globalprefpath, G_FILE_TEST_EXISTS) ) {
      debug("..found, trying to load and parse it");
      config_main = xml_read_config(CONFIG_MAIN, globalprefpath);
    } else {
      debug("..not found, loading config from hardcoded defaults");
      if( !(config_main = xml_create_config(CONFIG_MAIN)) )
        debug("could not create new config, aborting");
      else debug("new config created, continuing");
    }
  }

  if( !config_main ) return FALSE;

  xml_cleanup_config(CONFIG_MAIN);

  return TRUE;
}

/**
 * prefs_str_to_bool:
 * @val: a string with boolean meaning
 *
 * See array boolean_values[ ][ ] (preferences.c) for list of allowed values.
 *
 * Returns: true if val contains string meaning 'true', false otherwise
 **/

gboolean prefs_str_to_bool(gchar *val) {
  gint i = 0;

  while(boolean_values[0][i]) {
    if( !g_ascii_strcasecmp(val, boolean_values[0][i]) ) return TRUE;
    i++;
  }
  return FALSE;
}

/**
 * prefs_bool_to_str:
 * @val: a boolean value
 *
 * Returns: PREF_ON macro if val is true, PREF_OFF otherwise
 **/

gchar *prefs_bool_to_str(gboolean val) {
  if(val) return PREF_ON;
  return PREF_OFF;
}

gchar *pref_type_as_string(gint type) {
  switch(type) {
    case WIDGET_ENTRY: return "entry";
    case WIDGET_CHECKBUTTON: return "checkbutton";
    case WIDGET_COLORBUTTON: return "colorbutton";
    case WIDGET_FONTBUTTON: return "fontbutton";
    case WIDGET_SPINBUTTON: return "spinbutton";
    default: return "<UNKNOWN>";
  }
}

/**
 * prefs_populate_gui:
 *
 * Take values from #xmlDocPtr #config_main and sets them to widgets in
 * preferences window.
 *
 * Should always be called before preferences window is shown.
 **/

void prefs_populate_gui() {
  GtkWidget *w;
  GdkColor color;
  gchar *val;
  gint i = 0;

  debug("Starting to populate preferences GUI");

  while( preferences[i].name ) {
    if( !preferences[i].widget ) continue;

    w = glade_xml_get_widget(xmlmain, preferences[i].widget);
    val = xml_get_option(CONFIG_MAIN, preferences[i].xmloption);

    debug("Setting %s '%s' to '%s'", pref_type_as_string(preferences[i].widget_type), preferences[i].widget, val);

    switch(preferences[i].widget_type) {
      case WIDGET_ENTRY:
	gtk_entry_set_text(GTK_ENTRY(w), val);
	break;
      case WIDGET_CHECKBUTTON:
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), prefs_str_to_bool(val));
	break;
      case WIDGET_FONTBUTTON:
	if (val && strlen(val) > 1) {
	  gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), val);
	} else {
	  debug_info("No font set in preferences, falling back to 'Sans 10'");
	  gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), "Sans 10"); /* default font, GtkFontButton requires some */
	}

        break;
      case WIDGET_COLORBUTTON:
	if (gdk_color_parse(val, &color))
	  gtk_color_button_set_color(GTK_COLOR_BUTTON(w), &color);
	break;
      case WIDGET_SPINBUTTON:
        gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), atoi(val));
	break;
      default:
        debug("!!! Unknown preference type found: '%s' !!!", preferences[i].name);
	break;
    }

    i++;
  }

  /* populate servers list */
  populate_prefs_serverlist();

  /* special cases, populating other than preferences dialog */

  /* set the "tip of the day" dialog's status */
  w = glade_xml_get_widget(xmlmain, "set_tips_dialog");
  val = xml_get_option(CONFIG_MAIN, CM_GUI_TIPS);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), prefs_str_to_bool(val));

  debug("Finished");
}

/**
 * prefs_save_gui:
 *
 * Take values from appropriate widgets in preferences window  and sets
 * corresponding #xmlDoc nodes in #xmlDocPtr #config_main.
 *
 * Should be called when user pressed Save button in preferences window.
 * A call to xml_save_config() should follow.
 **/

void prefs_save_gui() {
  GtkWidget *w;
  gchar *val = NULL;
  gint i = 0;
  GdkColor color;

  debug("Starting to save values from preferences GUI");

  while( preferences[i].name ) {
    if( !preferences[i].widget ) continue;

    w = glade_xml_get_widget(xmlmain, preferences[i].widget);

    switch(preferences[i].widget_type) {
      case WIDGET_ENTRY:
        val = (gchar *)gtk_entry_get_text(GTK_ENTRY(w));
	break;
      case WIDGET_CHECKBUTTON:
        val = prefs_bool_to_str(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
	break;
      case WIDGET_FONTBUTTON:
        val = (gchar *)gtk_font_button_get_font_name(GTK_FONT_BUTTON(w));
        break;
      case WIDGET_COLORBUTTON:
	gtk_color_button_get_color(GTK_COLOR_BUTTON(w), &color);
	val = gtk_color_selection_palette_to_string(&color, 1);
	break;
      case WIDGET_SPINBUTTON:
        val = g_strdup_printf("%g", gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
	break;
      default:
        debug("!!! Unknown preference type found: '%s' !!!", preferences[i].name);
	val = "";
	break;
    }

    debug("Value of %s '%s' is '%s'", pref_type_as_string(preferences[i].widget_type), preferences[i].widget, val);
    xml_set_option(CONFIG_MAIN, preferences[i].xmloption, val);

    i++;
  }

  debug("Finished");
}

/**
 * prefs_show_to_console:
 *
 * Take values from #xmlDocPtr #config_main and displays them to console
 * window.
 **/

void prefs_show_to_console() {
  GtkWidget *w;
  gchar *val;
  gint i = 0;

  debug("Starting to populate preferences GUI");

  while( preferences[i].name ) {
    if( !preferences[i].widget ) continue;

    w = glade_xml_get_widget(xmlmain, preferences[i].widget);
    val = xml_get_option(CONFIG_MAIN, preferences[i].xmloption);

    printconsole(g_strdup_printf("%s = %s", preferences[i].name, val));

    i++;
  }

  debug("Finished");
}

/**
 * prefs_get:
 * @name: name of config option to be retrieved
 *
 * Use this to retrieve preference values from user config in memory.
 *
 * Returns: value of requested preference, or NULL if name is invalid
 **/

gchar *prefs_get(gchar *name) {
  gint i = 0;

  if(!name) {
    debug("name == NULL");
    return NULL;
  }

  while( preferences[i].name ) {
    if( !g_ascii_strcasecmp(preferences[i].name, name) ) {
      debug("found preference option '%s' = \"%s\"", preferences[i].name, xml_get_option(CONFIG_MAIN, preferences[i].xmloption) );
      return xml_get_option(CONFIG_MAIN, preferences[i].xmloption);
    }
    i++;
  }
  debug("Non-existent preference option requested");
  return NULL;
}

/**
 * prefs_set:
 * @name: name of config option to be set
 * @value: desired value
 *
 * Use this to retrieve preference values from user config in memory.
 *
 * Returns: true if new value was succesfully set, false otherwise
 **/

gboolean prefs_set(gchar *name, gchar *value) {
  gint i = 0;

  if(!name) {
    debug("name == NULL");
    return FALSE;
  }

  if(!value) {
    debug("val == NULL");
    return FALSE;
  }

  while( preferences[i].name ) {
    if( !g_ascii_strcasecmp(preferences[i].name, name) ) {
      debug("found preference option '%s'", preferences[i].name);
      if( !xml_set_option(CONFIG_MAIN, preferences[i].xmloption, value) ) {
        debug("couln't set option '%s'", name);
	return FALSE;
      }
      debug("succesfully set '%s' to '%s'", name, value);
      return TRUE;
    }
    i++;
  }
  debug("Non-existent preference option requested");
  return FALSE;
}

/**
 * prefs_widget_type:
 * @name: name of preference in question
 *
 * Returns: Arbitrary widget type number, from PrefWidgetTypes enum, or 0
 * if requested preference does not exist
 **/

gint prefs_widget_type(gchar *name) {
  gint i = 0;

  if(!name) {
    debug("name == NULL");
    return 0;
  }

  while( preferences[i].name ) {
    if( !g_ascii_strcasecmp(preferences[i].name, name) ) {
      debug("found preference option '%s'", preferences[i].name);
      return preferences[i].widget_type;
    }
    i++;
  }
  debug("Non-existent preference option requested");
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1