/* 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 "xstd/h/iostream.h"
#include "xstd/h/iomanip.h"

#include "xstd/NetAddr.h"
#include "base/RndPermut.h"
#include "base/AddrParsers.h"
#include "base/ObjId.h"
#include "runtime/httpHdrs.h"
#include "runtime/HostMap.h"
#include "csm/ContentCfg.h"
#include "csm/ContentMgr.h"
#include "csm/ContentSel.h"
#include "csm/oid2Url.h"

static
void oidDumpHttpHost(const NetAddr &host, ostream &os) {
	if (host.port() == 80)
		os << host.addrA();
	else
		os << host;
}

NetAddr Oid2UrlHost(const ObjId &oid) {
	if (oid.foreignUrl()) {
		const char *furi = oid.foreignUrl().data();
		NetAddr host;
		if (Should(SkipHostInUri(furi, furi+oid.foreignUrl().len(), host)))
			return host;
	} else
	if (Should(oid.viserv() >= 0)) {
		const HostCfg *host = TheHostMap->at(oid.viserv());
		if (Should(host))
			return host->theAddr;
	}
	return NetAddr();
}

ostream &Oid2UrlHost(const ObjId &oid, ostream &os) {
	const NetAddr host = Oid2UrlHost(oid);
	if (host)
		oidDumpHttpHost(host, os);
	else
	if (oid.foreignUrl())
		os << '?';
	else
		os << oid.viserv();
	return os;
}

ostream &Oid2UrlPath(const ObjId &oid, ostream &os) {
	if (oid.foreignUrl()) {
		const char *p = 0;
		if ((p = oid.foreignUrl().chr(':'))) { // proto
			while (*++p == '/');
		} else {
			p = oid.foreignUrl().cstr();
		}
		if (const char *path = strchr(p, '/'))
			os << path;
		else
			os << '/';
		return os;
	}

	const ContentCfg *ccfg = 0;
	if (oid.type() > 0) {
		ccfg = TheContentMgr.get(oid.type());
		Assert(ccfg);
	}

	os << '/';

	if (ccfg) {
		const int seed = GlbPermut(oid.hash(), rndContentPfx);
		if (const String &pfx = ccfg->url_pfx(seed))
			os << pfx;
	}

	os << 'w' << oid.world() << '/';

	// use non-default formatting to save space and reduce length variation
	{
		const ios_fmtflags flags = os.flags();
		const char fill = os.fill('0');
		os << hex << setfill('0');
		os << 't' << setw(2) << oid.type() << '/';
		os << '_' << setw(8) << oid.name();
		os.fill(fill);
		os.flags(flags);
	}

	if (ccfg) {
		const int seed = GlbPermut(oid.hash(), rndContentExt);
		if (const String &ext = ccfg->url_ext(seed))
			os << ext;
	}
	return os;
}

ostream &Oid2Url(const ObjId &oid, ostream &os) {
	if (oid.foreignUrl())
		return os << oid.foreignUrl();

	os << "http://";
	Oid2UrlHost(oid, os);
	Oid2UrlPath(oid, os);
	return os;
}

int Oid2ContType(const ObjId &oid) {
	Assert(!oid.foreignUrl());
	const HostCfg *hcfg = TheHostMap->at(oid.target());
	Assert(hcfg);
	Assert(hcfg->theContent);
	const ContentCfg *ccfg = hcfg->theContent->getDir(oid);
	return ccfg->id();
}

bool OidImpliesMarkup(const ObjId &oid, const ContentCfg *cfg) {
	String urlSfx = oid.foreignUrl();
	if (!urlSfx) {
		Assert(cfg); // add code to compute if needed
		const int seed = GlbPermut(oid.hash(), rndContentExt);
		urlSfx = cfg->url_ext(seed);
	}

	return urlSfx && (urlSfx.last() == '/' || urlSfx.caseEndsWith("ml", 2));
}


syntax highlighted by Code2HTML, v. 0.9.1