/* Web Polygraph       http://www.web-polygraph.org/
 * (C) 2003-2006 The Measurement Factory
 * Licensed under the Apache License, Version 2.0 */

#include "base/polygraph.h"

#include "runtime/HostMap.h"

HostMap *TheHostMap = 0;


/* HostCfg */

HostCfg::HostCfg(const NetAddr &anAddr): theAddr(anAddr),
	theContent(0), theSslWrap(0), theServerRep(0), thePubWorld(0),
	theCookies(0) {
}


/* HostMap */

HostMap::HostMap(int aCapacity): 
	theIndex((aCapacity + aCapacity/3 + 7) | 1), theCount(0) {
	HostCfg *h = 0;
	while (!theIndex.full())
		theIndex.push(h);
}

HostMap::~HostMap() {
	while (theIndex.count())
		delete theIndex.pop();
}

HostCfg *HostMap::at(int idx) {
	return (0 <= idx && idx < capacity()) ?	theIndex[idx] : 0;
}

HostCfg *HostMap::at(const NetAddr &addr) {
	int idx = -1;
	Assert(findIdx(addr, idx));
	return theIndex[idx];
}

ServerRep *HostMap::serverRepAt(int idx) {
	if (HostCfg *cfg = at(idx))
		return cfg->theServerRep;
	return 0;
}

const SslWrap *HostMap::findSslWrap(const NetAddr &addr) const {
	int idx = -1;
	if (findIdx(addr, idx))
		return theIndex[idx]->theSslWrap;
	return 0;
}

PubWorld *HostMap::findPubWorld(const NetAddr &addr) {
	int idx = -1;
	if (findIdx(addr, idx))
		return theIndex[idx]->thePubWorld;
	return 0;
}

PubWorld *HostMap::findPubWorldAt(int idx) {
	return (0 <= idx && idx < capacity()) ? theIndex[idx]->thePubWorld : 0;
}

HostCfg *HostMap::find(const NetAddr &addr) {
	int idx = -1;
	return find(addr, idx);
}

HostCfg *HostMap::find(const NetAddr &addr, int &idx) {
	if (findIdx(addr, idx))
		return theIndex[idx];
	return 0;
}

bool HostMap::findIdx(const NetAddr &addr, int &idx) const {
	bool res = false;

	idx = hash0(addr);
	if (endSearch(addr, idx, res))
		return res;

	// try hash1 followed by linear search
	idx = hash1(addr);
	for (int i = theIndex.capacity(); i; --i) {
		if (endSearch(addr, idx, res))
			return res;
		idx++;
		idx %= capacity();
	}

	Assert(false); // no empty slots left!
	return res;
}

HostCfg *HostMap::addAt(int idx, const NetAddr &addr) {
	Assert(addr);
	Assert(!theIndex[idx]);
	theCount++;
	return (theIndex[idx] = new HostCfg(addr));
}

// returns true if there is no reason to search further (match or empty)
bool HostMap::endSearch(const NetAddr &addr, int idx, bool &res) const {
	if (HostCfg *h = theIndex[idx]) {
		if (h->theAddr == addr)
			return res = true;
		return res = false;
	}

	// found empty slot
	res = false;
	return true;
}

int HostMap::hash0(const NetAddr &addr) const {
	return addr.hash0() % capacity();
	//return abs((int)(addr.lna() + addr.port())) % capacity();
}

int HostMap::hash1(const NetAddr &addr) const {
	return addr.hash1() % capacity();
	//return abs((int)(addr.lna() ^ addr.port() + addr.net())) % capacity();
}


syntax highlighted by Code2HTML, v. 0.9.1