/*
**  GXSNMP - An snmp management application
**
**  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, Cambridge, MA 02139, USA.
**
**  Subroutine to fully wire a host on the current map.  First, run
**  down the interface list and make sure that all of the networks
**  used by this host are in the network database.  Add them if necessary.
**  Then, make sure that each of those networks has a graph entry for the
**  current map, adding any that are necessary.  Finally, we create a
**  wire object for each host/graph combination.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gnome.h>
#include <netinet/in.h>

#include "dbapi.h"
#include "gxsnmp/gxsnmp_dbapi.h"
#include "gxsnmp_wire.h"
#include "iputil.h"

#include "debug.h"

/*
**  Forward references
*/

void
wire_host (GXsnmp_host * host, GXsnmp_map * map)
{
  DB_host      * dbh;
  DB_map       * dbm;
  DB_interface * dbi;
  DB_network   * dbn;
  DB_graph     * dbg;
  DB_graph     * dbhg;	/* DB_graph entry for host on current map */
  GList	       * ngl;	/* Network GList for matches */
  GList        * gl;
  guint		 offset = 20;	/* Used to position the networks */

  D_FUNC_START;
  g_return_if_fail (GXSNMP_IS_HOST (host));
  g_return_if_fail (GXSNMP_IS_MAP (map));

  dbhg = GXSNMP_MAP_ITEM (host)->DB_graph;
  dbh = dbhg->DB_host;
  dbm = map->DB_map;
  d_print (DEBUG_DUMP, "add wire to %s on the %s map\n", 
	   dbh->name, map->name);

/*
**  Run down the interface list for the host, and check each interface
*/

  gl = dbh->DB_interfaces;
  while (gl)
    {
      gchar * network;
      gulong  mask;
      gint    cidr;
      gchar   name[1024];
      struct in_addr in_address;

      dbi = (DB_interface *)gl->data;

/*
**  Determine the base address of the network that the interface is on
**  Find the network in the network database.  If there is no entry for
**  the network, then add a new entry.  There may be multiple network
**  entries in the database for any network.  This corresponds to different
**  switched segments.  In this case, just grab the first one we find.
*/

      network = host_and_netmask_to_network (dbi->address, dbi->netmask);
      d_print (DEBUG_DUMP, "dbi->address (%s), dbi->netmask (%s), "
	       "dbi->name (%s), dbh->name (%s)\n", 
	       dbi->address, dbi->netmask, dbi->name, dbh->name);
      if (!network)
	{
	  g_warning ("Invalid address/netmask %s %s for interface %s "
		   "on host %s\n", 
		   dbi->address, dbi->netmask, dbi->name, dbh->name);
	  goto ignore;
	}  
      inet_aton(dbi->netmask, &in_address);
      mask = in_address.s_addr;
      printf("mask=%d\n", mask);
      cidr = mask_to_cidr(mask);
      printf("cidr=%d\n", cidr);
      g_snprintf(name, 1024, "%s/%d", network, cidr);
      ngl = network_find_by_address (network, dbi->netmask);

      if (!ngl)		/* Network not yet registered -- register it */
	{
          dbn = network_create ();
	  if (dbn)
	    {
	      dbn->name    = g_strdup (name);
	      dbn->address = g_strdup (network);
	      dbn->netmask = g_strdup (dbi->netmask);
	      d_print (DEBUG_DUMP, "adding network (%s)\n", dbn->name);
	      network_add (dbn);
	    }
	  else
	    {
	      g_warning ("wire_host: network_create failed!\n");
	    }
        }
      else
	dbn = ngl->data;  /* Otherwise take the first matching network */

      g_free(network);
      g_list_free (ngl);  /* Done with the GList */

/*
**  At this point, dbn will be valid and will point to the correct 
**  DB_network entry for the network.  Now check and see if there is 
**  already a graph entry for the network on this map.  If not, then
**  create one.
*/
      d_print (DEBUG_DUMP, "Matched network %s\n", dbn->name);
      if ( !(dbm->rowid) && !(dbn->rowid) )
	{
	  g_warning ("wire_host: either dbm or dbn is invaild.\n");
	  goto ignore;
	}
      dbg = graph_find_network (dbm->rowid, dbn->rowid);
      
      if (!dbg)
	{
	  dbg = graph_create ();
	  if (dbg)
	    {
	      dbg->map = dbm->rowid;
	      dbg->type = DB_GRAPH_NETWORK;
	      dbg->network = dbn->rowid;
	      dbg->x = dbhg->x + offset;
	      dbg->y = dbhg->y + offset;
	      offset += 20;
	      graph_add (dbg);
	    }
	  else
	    {
	      g_warning ("wire_host: failed to create the network graph " 
                         "object.\n");
	    }
	}

/*
**  At this point, we have a valid host and network combination.  Now all
**  that is left to do is look for the corresponding wire, and insert it
**  if necessary.
*/
      if ( !(dbm->rowid) && !(dbh->rowid) && !(dbn->rowid) )
	{
	  g_warning ("wire_host: one of the dbm, dbh or dbn is not "
		     "vaild..\n");
	  goto ignore;
	}
      dbg = graph_find_wire (dbm->rowid, dbh->rowid, dbn->rowid);

      if (!dbg)
        {
	  if ( (dbg = graph_create ()) )
	    {
	      
	      dbg->type    = DB_GRAPH_WIRE;
	      dbg->map     = dbm->rowid;
	      dbg->host    = dbh->rowid;
	      dbg->network = dbn->rowid;
	      d_print (DEBUG_DUMP, "Adding new wire.\n");
	      graph_add (dbg);
	    }
	  else
	    {
	      g_warning ("wire_host: failed to create wire graph object\n");
	    }
	}

ignore:

      gl = gl->next;
    }
  D_FUNC_END;
}

/* EOF */
