/*
** SellaNMS
** $Id: topology.h,v 1.7 2005/11/07 06:12:29 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

#ifndef __DGS_MODULE_DISCOVERY_TOPOLOGY_H
#define __DGS_MODULE_DISCOVERY_TOPOLOGY_H

#ifdef HAVE_CONFIG_H
	#include "config.h"
#endif

#include "defaults.h"
#include "common/util.h"
#include "common/netblock.h"
#include "policy_framework/policy_framework.h"
#include <stdio.h>
#include <stdlib.h>
#include <stl/set>
#include <stl/list>
#include <stl/slist>
#include <stl/hash_map>

#define SYSTEM														".1.3.6.1.2.1.1"
#define INTERFACES_IFTABLE_IFENTRY 							".1.3.6.1.2.1.2.2.1"
#define INTERFACES_IFTABLE_IFENTRY_IFDESCR				".1.3.6.1.2.1.2.2.1.2"
#define IP_IPADDRTABLE_IPADDRENTRY_IPADENTADDR			".1.3.6.1.2.1.4.20.1.1"
#define IP_IPADDRTABLE_IPADDRENTRY_IPADENTIFINDEX 		".1.3.6.1.2.1.4.20.1.2"
#define IP_IPADDRTABLE_IPADDRENTRY_IPADENTNETMASK		".1.3.6.1.2.1.4.20.1.3"

#define IP_IPADDRTABLE_IPADDRENTRY_IPADENTADDR_LIKE	".1.3.6.1.2.1.4.20.1.1.%"

/* XX% must match between existing element and new element, to assume they are the same and merge them. */
#define DISCOVERY_TOPOLOGY_MERGEPERCENT_DEF		95
#define DISCOVERY_TOPOLOGY_MERGEPERCENT_MIN		1
#define DISCOVERY_TOPOLOGY_MERGEPERCENT_MAX		100

/* XX% must match between two new hosts, to assume one is a duplicate and discard one of them. */
#define DISCOVERY_TOPOLOGY_DUPLICATEPERCENT_DEF	90
#define DISCOVERY_TOPOLOGY_DUPLICATEPERCENT_MIN	1
#define DISCOVERY_TOPOLOGY_DUPLICATEPERCENT_MAX	100

#define DISCOVERY_TOPOLOGY_MAXELEMENTDELETE_DEF	500
#define DISCOVERY_TOPOLOGY_MAXELEMENTDELETE_MIN	1
#define DISCOVERY_TOPOLOGY_MAXELEMENTDELETE_MAX	2500

#define MERGEALGO_HOSTNAME_OR_MERGE_PERCENTAGE	0
#define MERGEALGO_HOSTNAME_AND_MERGE_PERCENTAGE	1
#define MERGEALGO_HOSTNAME_ONLY						2
#define MERGEALGO_MERGE_PERCENTAGE_ONLY			3

#define MATCHALGO_A_AND_B_GE_MATCH_PERCENTAGE	0
#define MATCHALGO_A_OR_B_GE_MATCH_PERCENTAGE		1

#define DISCOVERY_TOPOLOGY_MERGEALGO_DEF			MERGEALGO_HOSTNAME_OR_MERGE_PERCENTAGE
#define DISCOVERY_TOPOLOGY_MATCHALGO_DEF			MATCHALGO_A_AND_B_GE_MATCH_PERCENTAGE

typedef hash_map<unsigned long, set<unsigned long> > layer3_hash_t;
typedef hash_map<unsigned long, set<unsigned long> >::iterator layer3_hash_iter_t;

typedef struct connection_t {
	unsigned long connection;
	slist<unsigned long> points;
};

typedef hash_map<unsigned long, connection_t> connection_hash_t;
typedef hash_map<unsigned long, connection_t>::iterator connection_hash_iter_t;

typedef struct connection_builder_t {
	unsigned int element;
	unsigned long connection;
	unsigned long point;
	string network;
	string netmask;
};

typedef struct matrix_t {
	size_t added_len;
	size_t existing_len;
	int **matrix;
};

class Topology {
	public:
		Topology();
		virtual ~Topology();
		virtual RESULT readConfig();
		virtual RESULT execute();

	protected:
		virtual void printConfig();

	private:

		/* Major Functions */
		RESULT correlateIpToElement(); /* Read in new and existing discovery and correlates their IPs to Elements. */
		RESULT compareNewToExistingDiscovery(); /* Returns "The Matrix" */
		RESULT processDiscoveryResults(); /* Updates and Inserts all data as needed. */
		RESULT processConnections(); /* Inserts new connections. */
		RESULT optimizeDatabase(); /* Optimizes the database after the discovery. */

		/* Minor Functions */
		bool compareSetsIP(set<unsigned long> &a, set<unsigned long> &b, float &match_percent);
		bool compareSetsHostname(unsigned long existing_host, unsigned long new_host);

		RESULT classifyElements(list<unsigned long> &added_elements, list<unsigned long> &existing_elements);
		RESULT processAddedElements(list<unsigned long> &added_elements);
		RESULT processRemovedElements(list<unsigned long> &removed_elements);
		RESULT processExistingElements(list<unsigned long> &existing_elements);

		RESULT updateElement(long unsigned int);

		RESULT insertElement(const unsigned long key);
		RESULT insertElementInterface(unsigned long key, unsigned long id);
		RESULT insertElementInterfaceIp(const unsigned long key, unsigned long id, const unsigned long if_index);

		RESULT getExistingInterfaces(unsigned long &element, hash_map<string, unsigned long> &interfaces, unsigned long key);
		RESULT getExistingIPAddresses(unsigned long &element, hash_map<string, unsigned long> &ip_addresses, unsigned long key);

		RESULT getDiscoveryInformation(slist<unsigned long> &discovery_id, slist<pair<string, string> > &element_data, hash_map<string, hash_map<string, string> > &interface_data, hash_map<string, hash_map<string, string> > &ipaddress_data, unsigned long key);

		RESULT deleteDiscoveryInformation(slist<unsigned long> &information_ids);
		RESULT updateElementData(unsigned long element, slist<pair<string, string> > &element_data);
		RESULT insertElementData(unsigned long element, slist<pair<string, string> > &element_data);
		RESULT updateInterfaceData(unsigned long element, hash_map<string, hash_map<string, string> > &interface_data, hash_map<string, unsigned long> &interface_map);
		RESULT insertInterfaceData(slist<pair<string, unsigned long> > &interface_list, hash_map<string, hash_map<string, string> > &interface_data);
		RESULT updateIPAddressData(unsigned long element, hash_map<string, hash_map<string, string> > &ipaddress_data, hash_map<string, unsigned long> &ipaddress_map);
		RESULT insertIPAddressData(slist<pair<string, unsigned long> > &ipaddress_list, hash_map<string, hash_map<string, string> > &ipaddress_data);

		RESULT insertNewElement(long unsigned int &, long unsigned int);
		RESULT insertNewInterface(unsigned long element, unsigned long &interface_id);
		RESULT insertNewIP(unsigned long interface, unsigned long &ipaddress_id);

		RESULT mapIfIndexToInterfaceId(unsigned long element, hash_map<string, unsigned long> &ifidx_map);
//		RESULT getIpIdList(unsigned long element, unsigned long intrface, slist<unsigned long> &ip_id_list);

		RESULT loadNewDiscovery();
		RESULT loadExistingDiscovery();
		RESULT removeDuplicateElement(layer3_hash_t&);

		RESULT buildConnections(connection_hash_t &connection);
		RESULT loadExistingConnections(connection_hash_t &existing_connection);
		RESULT insertNewConnections(connection_hash_t &connection);
		RESULT isolateNewConnections(connection_hash_t &new_connection, connection_hash_t &existing_connection);

		RESULT removeUnusedIPs();
		RESULT removeUnusedConnections();
		RESULT removeOrphanConnectionPoints();

		void printLayer3Hash(layer3_hash_t&, long n = -1);
		void printConnectionHash(connection_hash_t &conn_hash, long n = -1);

		slist<Netblock> connectionFilters;
		layer3_hash_t new_discovery;
		layer3_hash_t existing_discovery;
		connection_hash_t connection;
		matrix_t matrix;
		
		unsigned long maxElementDelete;
		float mergePercent;
		float duplicatePercent;

		unsigned long matchAlgo;
		unsigned long mergeAlgo;

		PolicyFramework	inputPolicy;
		PolicyFramework	outputPolicy;

		vector<string> netblocks;

		Storage storage;
};

#endif

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3
*/
