/* 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/rndDistrs.h"
#include "xstd/StrIdentifier.h"
#include "xstd/h/iomanip.h"
#include "base/RndPermut.h"
#include "base/polyLogCats.h"
#include "runtime/PopModel.h"
#include "runtime/ErrorMgr.h"
#include "runtime/XactAbortCoord.h"
#include "runtime/LogComment.h"
#include "runtime/polyErrors.h"
#include "csm/ContentCfg.h"
#include "csm/ContentMgr.h"
#include "pgl/ServerSym.h"
#include "server/Server.h"
#include "server/SrvCfg.h"

SrvCfg::SrvCfg(): theServer(0), thePopModel(0), theRepTypeSel(0),
	theCookieCounts(0), theCookieSizes(0), theCookieSendProb(0),
	theAbortProb(0) {
}

SrvCfg::~SrvCfg() {
	delete thePopModel;
	delete theRepTypeSel;
}

void SrvCfg::configure(const ServerSym *aServer) {
	AgentCfg::configure(aServer);

	Assert(!theServer && aServer);
	theServer = aServer;

	if (PopModelSym *pms = theServer->popModel()) {
		thePopModel = new PopModel;
		thePopModel->configure(pms);
	}

	configureRepTypes();

	// configure content distributions
	Array<ContentSym*> csyms;
	Array<double> cprobs;
	Assert(theServer->contents(csyms, cprobs) && csyms.count());
	Array<ContentCfg*> ccfgs;
	TheContentMgr.get(csyms, ccfgs);
	theTypes.configure(ccfgs);

	configureCookies();

	theServer->abortProb(theAbortProb);
}

void SrvCfg::configureRepTypes() {
	static StrIdentifier sidf;
	if (!sidf.count()) {
		sidf.add("Basic", Server::rptBasic);
		sidf.add("302 Found", Server::rpt302Found);
	}

	theRepTypeSel = theServer->msgTypes(sidf);
	if (theRepTypeSel) {
		if (!theServer->popModel()) {
			cerr << theServer->loc() << "warning: some rep_types may require "
				<< "server popularity model and none was configured" << endl;
		}
	} else {
		// set to default
		theRepTypeSel = new ConstDistr(new RndGen, Server::rptBasic);
	}
	theRepTypeSel->rndGen(LclRndGen("server_req_types"));
}

void SrvCfg::configureCookies() {
	theCookieCounts = theServer->cookieSetCount();
	theCookieSizes = theServer->cookieValueSize();
	if (theServer->cookieSetProb(theCookieSendProb)) {
		if (theCookieSendProb > 0 && (!theCookieCounts || !theCookieSizes)) {
			Comment << "error: cookie count and size distributions not " <<
				"specified but cookie_send probability is positive" << endc <<
				xexit;
		}
	} else {
		theCookieSendProb = 0; // no cookies by default
		if (theCookieCounts || theCookieSizes) {
			Comment << "error: cookie count and size distributions " <<
				"specified but cookie_send probability is not" << endc <<
				xexit;
		}
	}
}

// merge this with CltCfg::selectAbortCfg() if more methods can be shared
void SrvCfg::selectAbortCoord(XactAbortCoord &coord) {
	static RndGen rng1, rng2; // uncorrelated unless theAbortProb is 1
	if (rng1.event(theAbortProb)) {
		const int whether = rng2.state();
		(void)rng2.trial();
		coord.configure(rng2.state(), whether);
	} else {
		const int whether = rng1.state();
		(void)rng1.trial();
		coord.configure(whether, rng1.state());
	}
}

bool SrvCfg::setEmbedContType(ObjId &oid, const Area &category) const {
	int etype = -1;
	if (theTypes.findEmbedContType(category, etype)) {
		oid.type(etype);
		return true;
	}

	if (ReportError2(errUnknownEmbedCategory, lgcSrvSide))
		Comment << "requested category: " << category << endc;
	return false;
}


/* SrvSharedCfgs */

SrvCfg *SrvSharedCfgs::getConfig(const ServerSym *rs) {
	for (int i = 0; i < count(); ++i) {
		if (item(i)->theServer == rs)
			return item(i);
	}
	return addConfig(rs);
}

SrvCfg *SrvSharedCfgs::addConfig(const ServerSym *rs) {
	SrvCfg *cfg = new SrvCfg;
	cfg->configure(rs);
	append(cfg);
	return cfg;
}



syntax highlighted by Code2HTML, v. 0.9.1