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

    - Server list management functions

    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 <silcincludes.h>
#include <silcclient.h>

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

#include "servers.h"
#include "xmllayout.h"
#include "xmlconfig.h" 
#include "preferences.h"
#include "log.h"

extern xmlDocPtr config_servers;

extern SilkyXMLElement xml_elements[NUM_CONFIG][NUM_CM];

SilkyServer *servers = NULL;

/* this one should be called from main.c, it takes care of everything
   necessary to load server list into silky */
gboolean init_servers(gchar *serverspath) {
  debug("Trying to load servers from config: %s", serverspath);
  if( g_file_test(serverspath, G_FILE_TEST_EXISTS) ) {
    debug("...file found");

    if( !(config_servers = xml_read_config(CONFIG_SERVERS, serverspath)) ) {
      debug("Failed to load servers from file '%s'!", serverspath);
      return FALSE;
    }

    if( !parse_servers() ) {
      debug("Failed to parse servers, none loaded");
      return TRUE;
    }

    debug("Servers loaded, continuing");

    return TRUE;
  }

  return FALSE;
}

/* this one parses the loaded xmlDoc and populates our internal SilkyServer
   linked list with servers found there */
gboolean parse_servers() {
  xmlXPathObjectPtr result;
  xmlXPathContextPtr context;
  xmlNodePtr node, n;

  gchar *host = NULL;
  gchar *port_str = NULL;
  gint port = -1, i;

  xml_cleanup_config(CONFIG_SERVERS);

  debug("Populating SilkyServer list...");

  context = xmlXPathNewContext(config_servers);

  result = xmlXPathEval(g_strdup_printf("/%s/%s", xml_elements[CONFIG_SERVERS][CS_ROOT].name, xml_elements[CONFIG_SERVERS][CS_SERVER].name), context);
  if( !result ) {
    debug("No result found for servers!");
    return FALSE;
  }

  if( xmlXPathNodeSetIsEmpty(result->nodesetval) ) {
    debug("Zaroo servers found.");
    return TRUE;
  }

  xmlXPathFreeContext(context);
  for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
    node = result->nodesetval->nodeTab[i];

    port = 706;
    for( n = node->children; n && strcmp(n->name, xml_elements[CONFIG_SERVERS][CS_SERVER].name) ; n = n->next ) {
      if( !strcmp(n->name, xml_elements[CONFIG_SERVERS][CS_SERVER_HOSTNAME].name) ) {
        host = g_strdup(xmlNodeGetContent(n));
      }
      if( !strcmp(n->name, xml_elements[CONFIG_SERVERS][CS_SERVER_PORT].name) ) {
	port_str = g_strdup(xmlNodeGetContent(n));
	port = atoi(port_str);
      }
    }

    if( !host || !g_utf8_strlen(host, -1) ) {
      debug("Hostname empty, ignoring server");
    } else if ( port <= 0 ) {
      debug("Port number incorrect: %d", port);
    } else {
      debug("Adding server %s:%d", host, port);
      server_add(host, port);
    }
  }

  xmlXPathFreeObject(result);
  if( !i ) debug("Zaroo servers found.");
  return TRUE;
}

SilkyServer *server_find_by_hostport(gchar *host, gint port) {
  SilkyServer *s;

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

  for( s = servers; s; s = s->next ) {
    if( !strcmp(s->hostname, host) && (port == s->port) ) {
      debug("found server '%s:%d'", host, port);
      return s;
    }
  }

  debug("server '%s:%d' not found", host, port);
  return NULL;
}

SilkyServer *server_add(gchar *hostname, gint port) {
  SilkyServer *s, *news;

  if( (!hostname || !g_utf8_strlen(hostname, -1)) ||
      (port < 1 || port > 65535) ) {
    debug("(!!) some server info is missing, cannot add");
    return NULL;
  }

  if( server_find_by_hostport(hostname, port) ) {
    debug("server '%s:%d' already exists", hostname, port);
    return NULL;
  }

  debug("creating SilkyServer struct for '%s:%d'", hostname, port);
  news = malloc( sizeof( SilkyServer ) );
  news->next = NULL;
  news->hostname = g_strdup(hostname);
  news->port = port;
  news->autoconnect = FALSE;

  if( !servers ) {
    debug("first server, creating linked list");
    servers = news;
  } else {
    debug("there are already some servers, appending to linked list");
    for( s = servers; s->next; s = s->next ) {}
    s->next = news;
  }

  return news;
}

/**
 * server_remove:
 * @server: #SilkyServer to remove from linked list of servers
 *
 * Removes specified #SilkyServer struct from list of servers, if it is there.
 *
 * Returns: TRUE if specified server was found in list and removed, FALSE
 * otherwise
 **/

gboolean server_remove( SilkyServer *server ) {
  SilkyServer *s, *prevs;
  gint found = 0;

  if( !servers ) {
    debug("No servers found, not removing anything");
    return FALSE;
  }

  for( s = servers, prevs = servers; s; s = s->next ) {
    if( server == s ) {
      debug("found our server");
      found++;
      break;
    }
    prevs = s;
  }

  if( !found ) {
    debug("server not in list, cannot remove");
    return FALSE;
  }

  debug("removing server from list");
  if( s == servers ) {
    debug("it is first server in list");
    servers = servers->next;
  } else {
    debug("not first server in list");
    prevs->next = s->next;
  }

  debug("freeing server struct from memory");
  g_free(s);

  return TRUE;
}

/**
 * servers_store_to_xml:
 *
 * Recreates servers' xmlDoc structure, filling it with servers from stored
 * linked list.
 *
 * Returns: TRUE if succesful, false otherwise
 **/

gboolean servers_store_to_xml() {
  SilkyServer *s;
  xmlNodePtr node;

  debug("freeing servers xmlDoc");
  if( config_servers ) {
    xmlFreeDoc(config_servers);
    config_servers = NULL;
  }

  if( !servers ) {
    debug("no servers to store");
    return FALSE;
  }

  if( !(config_servers = xml_create_config(CONFIG_SERVERS)) ) {
    debug("Couldn't create config_servers");
    return FALSE;
  }

  for( s = servers; s; s = s->next ) {
    node = xmlNewTextChild(xml_get_node(CONFIG_SERVERS, xml_doc(CONFIG_SERVERS), CS_ROOT), NULL, xml_elements[CONFIG_SERVERS][CS_SERVER].name, NULL);
//    node = xml_create_node(CONFIG_SERVERS, CS_SERVER);
    if( s->hostname && g_utf8_strlen(s->hostname, -1) ) {
      debug("Saving server '%s:%d'", s->hostname, s->port);
      xmlNewTextChild(node, NULL, xml_elements[CONFIG_SERVERS][CS_SERVER_HOSTNAME].name, s->hostname);
      xmlNewTextChild(node, NULL, xml_elements[CONFIG_SERVERS][CS_SERVER_PORT].name, g_strdup_printf("%d", s->port));
      xmlNewTextChild(node, NULL, xml_elements[CONFIG_SERVERS][CS_SERVER_AUTOCONNECT].name, (s->autoconnect ? PREF_ON : PREF_OFF));
    }
  }
  return TRUE;
}


syntax highlighted by Code2HTML, v. 0.9.1