/*
This Work is under GPL provided with this work.

This work is based on the java implementation of the Kademlia protocol.
Kademlia: Peer-to-peer routing based on the XOR metric
Copyright (C) 2002  Petar Maymounkov [petar@post.harvard.edu]
http://kademlia.scs.cs.nyu.edu
and
This work is bassed on translation from Barry Dunne to C++
Copyright (C)2003 Barry Dunne (http://www.emule-project.net)
*/


#include "cBucket.h"
#include "cPeer.h"
#include "misc.h"
#include "opcodes.h"
cBucket::~cBucket()  {{{
	cPeerList::const_iterator it;
	if (!dontDeleteContacts)
		for (it = contacts.begin(); it != contacts.end(); it++) delete *it;
	contacts.clear();
	}}}
bool  cBucket::add(class cPeer *CONTACT) {{{
	if (CONTACT == NULL) return false;
	class cPeer *c = getContact(CONTACT->get_Hash()->hash);
	if (c != NULL) {  // Move to the end of the list
		remove(c);
		contacts.push_back(c);
		return false;
		}
	if (contacts.size() < OVERNET_BUCKET) { // If not full, add to end of list
		contacts.push_back(CONTACT);
		return true;
		}
	return false;
	}}}
void  cBucket::setAlive(uint32_t IP, uint16_t PORT) {{{
	if (contacts.empty()) return;
	cPeer *c = NULL;
	cPeerList::iterator it;
	cPeerList::iterator end = contacts.end();
	for (it = contacts.begin(); it != end; it++) {
		c = *it;
		if (! ((IP == c->ip) && (PORT == c->udp))) continue;
		c->madeContact = true;
		c->expires = 0;
		// Move to the end of the list
		remove(c);
		contacts.push_back(c);
		return;
		}
	}}}
class cPeer *cBucket::getContact(const uint8_t *KEY) {{{
	cPeerList::const_iterator it;
	for (it = contacts.begin(); it != contacts.end(); it++) {
		if (0 == memcmp(KEY, ((*it)->get_Hash()), 16)) {
			return *it;
			break;
			}
		}
	return NULL;
	}}}
void  cBucket::getContacts (cPeerList *result, bool emptyFirst) {{{
	if (emptyFirst) result->clear();
	if (contacts.size() > 0)
		result->insert(result->end(), contacts.begin(), contacts.end());
	}}}
class cPeer *cBucket::getOldest    (void) {{{
	if (contacts.size() > 0) return contacts.front();
	return NULL;
	}}}
size_t cBucket::getClosest (const uint8_t *KEY, size_t maxRequired, cPeerMap *result, bool emptyFirst) {{{
	if (contacts.size() == 0) return 0;
	if (emptyFirst) result->clear();
	size_t count = 0;
	cPeerList::const_iterator it;
	for (it = contacts.begin(); it != contacts.end(); it++) {
		cHash dist;
		memcpy (dist.hash, (*it)->get_Hash()->hash, 16);
		xor_128(dist.hash, KEY);
		(*result)[dist] = *it;
		if (++count == maxRequired) return count;
		}
	return count;
	}}}

void cBucket::dumpContents(void) {{{
	cPeerList::const_iterator it;
	for (it = contacts.begin(); it != contacts.end(); it++) {
		cPeer *c = *it;
		struct in_addr ip;
		ip.s_addr = c->ip;
		printf("\t%s", hash_bin2hex(c->get_Hash()->hash));
		printf("\t%s (%u)", inet_ntoa(ip), c->udp);
		printf("\t%20s", c->get_Name());
		printf("\tDistance: %s\n", hash_bin2hex(c->get_Dist()->hash));
		}
	}}}

