/*
 * Author:
 *         Kendy Kutzner <kutzner@ira.uka.de>
 *
 * (c) 2005 Research Group Dr. Fuhrmann, University of Karlsruhe, Germany
 * All rights reserved.
 *
 * $Id: testmetric.cc,v 1.3 2005/11/21 10:46:57 kutzner Exp $
 *
 */

#include <set>
#include <iostream>
using namespace std;
#include <assert.h>
#include "id.h"
#define _IN_MAIN_
#include "debug.h"

struct node {
	id i;
	/// make this a priority queue of ints
	set<node*> nb;
};

const int maxk = 200;
const int nodecount = 100000;
node nodes[nodecount];

void
connect(int n1, int n2){
	assert(n1!=n2);
	nodes[n1].nb.insert(&(nodes[n2]));
	nodes[n2].nb.insert(&(nodes[n1]));
}

void
connect(node * n1, node * n2){
	if (n1==n2){
		//cout << "." ;
		return;
	}
	n1->nb.insert(n2);
	n2->nb.insert(n1);
}

node*
getclosest(const node * n, const id &i){
	//cout << "getclosest " << n->i.tostring() << " with " << n->nb.size() << " neigbhors " << i.tostring() << endl;
	node * ret = NULL;
	for (set<node*>::const_iterator j = n->nb.begin();
			j != n->nb.end();
			j++){
		if (i == (**j).i)
			continue;
		if (ret == NULL){
			ret = *j;
			// cout << " set ret to " << ret->i.tostring() << endl;
		}
		if (i.closer(ret->i, (**j).i) == 1){
			ret = *j;
			// cout << " set ret to " << ret->i.tostring() << " logdist " << ret->i.lddist(i) << endl;
		}
	}
	return ret;
}

node*
getglobalclosest(const id &i){
	node * ret = &(nodes[0]);
	for (int j = 0 ; j < nodecount; j++){
		if(i.closer(ret->i, nodes[j].i) == 1){
			ret = &(nodes[j]);
		}
	}
	return ret;
}

int
main(){
	int i;
	for (i = 0; i < nodecount; i++){
		nodes[i].i.randomize();
	}
	cout << "randomize done" << endl;
	for (i = 0; i < nodecount-1; i++){
		connect(i,i+1);
	}
	cout << "connect done" << endl;
	int connected;
	for (int k = 0; k < maxk ; k++){
		connected = 0;
		cout << "run " << k << " percent " << 1.0* k / maxk << endl;
		for (i = 0; i < nodecount; i++){
			node * closest;
			// cout << "run " << k << " node " << i << " percent " << 1.0* (k*nodecount+i) / (maxk*nodecount) << endl;
			for (set<node*>::const_iterator j = nodes[i].nb.begin();
					j!=nodes[i].nb.end();
					j++){
				// ask every neighbor for id-neighbors
				closest = getclosest(*j, nodes[i].i);
				if (closest != NULL){
					connect(&(nodes[i]), closest);
					connected++;
				}
			}
			// and query for every finger from the best suited neighbor
			for (int fingers = 0 ; fingers < id::bits() ; fingers++){
				id finger = nodes[i].i;
				finger.create_log_fingerdest(fingers);
				closest = getclosest(&(nodes[i]), finger);
				assert(closest != NULL);
				closest = getclosest(closest, finger);
				assert(NULL != closest);
				connect(&(nodes[i]), closest);
				connected++;
			}
		}
		cout << connected << " connects in this round" << endl;
		// lets test it
		int tok = 0;
		int tnok = 0;
		for (int h = 0 ; h < 100; h++){
			id check;
			check.randomize();
			node * right = getglobalclosest(check);
			node * n1 = &(nodes[rand()%nodecount]);
			node * n2;
			while (true){
				n2 = getclosest(n1, check);
				if (check.closer(n1->i, n2->i) != 1)
					break;
				n1 = n2;
			}
			if (right == n1)
				tok++;
			else {
				// cout << right->i.tostring() << " and " << n2->i.tostring() << " are off by " << right->i.lddist(n2->i) << endl;
				tnok++;
			}
		}
		if (tok==100)
			cout << "yeah" << endl;
		cout << tok << " percent ok" << endl;


	}
	return 0;
}
