/*
** SellaNMS
** $Id: topology.h,v 1.12 2008/01/31 22:31:08 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_DISCOVERY_TOPOLOGY_H
#define __DGS_DISCOVERY_TOPOLOGY_H

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

#include "defaults.h"
#include "main.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_MAXENTRYDELETE_DEF	500
#define DISCOVERY_TOPOLOGY_MAXENTRYDELETE_MIN	1
#define DISCOVERY_TOPOLOGY_MAXENTRYDELETE_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 DUPLICATEALGO_A_AND_B_GE_MATCH_PERCENTAGE	0
#define DUPLICATEALGO_A_OR_B_GE_MATCH_PERCENTAGE	1

#define DISCOVERY_TOPOLOGY_MERGEALGO_DEF			MERGEALGO_HOSTNAME_OR_MERGE_PERCENTAGE
#define DISCOVERY_TOPOLOGY_DUPLICATEALGO_DEF		DUPLICATEALGO_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 link_t {
	unsigned long link;
	slist<unsigned long> points;
};

typedef hash_map<unsigned long, link_t> link_hash_t;
typedef hash_map<unsigned long, link_t>::iterator link_hash_iter_t;

typedef struct link_builder_t {
	unsigned int element;
	unsigned long link;
	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 processLinks(); /* Inserts new link. */
		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 buildLinks(link_hash_t &link);
		RESULT loadExistingLinks(link_hash_t &existing_link);
		RESULT insertNewLinks(link_hash_t &link);
		RESULT isolateNewLinks(link_hash_t &new_link, link_hash_t &existing_link);

		RESULT removeUnusedIPs();
		RESULT removeUnusedLinks();
		RESULT removeOrphanLinkPoints();

		void printLayer3Hash(layer3_hash_t&, long n = -1);
		void printLinkHash(link_hash_t &link_hash, long n = -1);

		slist<Netblock> linkFilters;
		layer3_hash_t new_discovery;
		layer3_hash_t existing_discovery;
		link_hash_t link;
		matrix_t matrix;
		
		float mergePercent;
		float duplicatePercent;
		unsigned long maxEntryDelete;

		unsigned long duplicateAlgo;
		unsigned long mergeAlgo;

		PolicyFramework	inputPolicy;
		PolicyFramework	outputPolicy;

		vector<string> netblocks;

		Storage storage;
};

#endif

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