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

#include "pgl/pgl.h"

#include "xstd/String.h"
#include "xstd/rndDistrs.h"
#include "base/RndPermut.h"
#include "pgl/PglBoolSym.h"
#include "pgl/PglIntSym.h"
#include "pgl/PglNumSym.h"
#include "pgl/PglRateSym.h"
#include "pgl/PglRec.h"
#include "pgl/PglStringSym.h"
#include "pgl/PglNetAddrSym.h"
#include "pgl/PglArraySym.h"
#include "pgl/AclSym.h"
#include "pgl/DnsResolverSym.h"
#include "pgl/SessionSym.h"
#include "pgl/RobotSym.h"


const String RobotSym::TheType = "Robot";

static String strAcl = "acl";
static String strAddrArr = "addr[]";
static String strAuth_error = "auth_error";
static String strCredentials = "credentials";
static String strDns_resolver = "dns_resolver";
static String strEmbed_recur = "embed_recur";
static String strForeign_trace = "foreign_trace";
static String strRaw_uri_thrower = "raw_uri_thrower";
static String strIcp_port = "icp_port";
static String strInterests = "interests";
static String strMinimize_new_conn = "minimize_new_conn";
static String strOpen_conn_lmt = "open_conn_lmt";
static String strOrigins = "origins";
static String strPeer_http = "peer_http";
static String strPeer_icp = "peer_icp";
static String strPrivate_cache_cap = "private_cache_cap";
static String strProxies = "proxies";
static String strRecurrence = "recurrence";
static String strReq_inter_arrival = "req_inter_arrival";
static String strReq_methods = "req_methods";
static String strContainerTags = "container_tags";
static String strReq_rate = "req_rate";
static String strReq_types = "req_types";
static String strSession = "session";
static String strStringArr = "string[]";
static String strTime_distr = "time_distr";
static String strFloat_distr = "float_distr";
static String strSize_distr = "size_distr";
static String strUnique_urls = "unique_urls";
static String strWait_xact_lmt = "wait_xact_lmt";
static String strPipeline_depth = "pipeline_depth";
static String strCookies_keep_lmt = "cookies_keep_lmt";
static String strAcceptContentEncodings = "accept_content_encodings";


RobotSym::RobotSym(): AgentSym(TheType) {
	theRec->bAdd(strAddrArr, strProxies, 0);
	theRec->bAdd(strAddrArr, strOrigins, 0);
	theRec->bAdd(RateSym::TheType, strReq_rate, 0);
	theRec->bAdd(strTime_distr, strReq_inter_arrival, 0);
	theRec->bAdd(NumSym::TheType, strRecurrence, 0);
	theRec->bAdd(NumSym::TheType, strEmbed_recur, 0);
	theRec->bAdd(strStringArr, strInterests, 0);
	theRec->bAdd(strStringArr, strReq_types, 0);
	theRec->bAdd(strStringArr, strReq_methods, 0);
	theRec->bAdd(strStringArr, strContainerTags, 0);
	theRec->bAdd(strStringArr, strAcceptContentEncodings, 0);
	theRec->bAdd(IntSym::TheType, strPrivate_cache_cap, 0);
	theRec->bAdd(BoolSym::TheType, strUnique_urls, 0);
	theRec->bAdd(IntSym::TheType, strOpen_conn_lmt, 0);
	theRec->bAdd(IntSym::TheType, strWait_xact_lmt, 0);
	theRec->bAdd(NumSym::TheType, strMinimize_new_conn, 0);
	theRec->bAdd(strStringArr, strCredentials, 0);
	theRec->bAdd(NumSym::TheType, strAuth_error, 0);
	theRec->bAdd(AclSym::TheType, strAcl, new AclSym);
	theRec->bAdd(SessionSym::TheType, strSession, new SessionSym);
	theRec->bAdd(IntSym::TheType, strIcp_port, 0);
	theRec->bAdd(NetAddrSym::TheType, strPeer_http, 0);
	theRec->bAdd(NetAddrSym::TheType, strPeer_icp, 0);
	theRec->bAdd(DnsResolverSym::TheType, strDns_resolver, new DnsResolverSym);
	theRec->bAdd(StringSym::TheType, strForeign_trace, 0);
	theRec->bAdd(StringSym::TheType, strRaw_uri_thrower, 0);
	theRec->bAdd(strFloat_distr, strPipeline_depth, 0);
	theRec->bAdd(strFloat_distr, strCookies_keep_lmt, 0);
}

RobotSym::RobotSym(const String &aType, PglRec *aRec): AgentSym(aType, aRec) {
}

bool RobotSym::isA(const String &type) const {
	return AgentSym::isA(type) || type == TheType;
}

SynSym *RobotSym::dupe(const String &type) const {
	if (isA(type))
		return new RobotSym(this->type(), theRec->clone());
	return AgentSym::dupe(type);
}

bool RobotSym::reqRate(double &rate) const {
	return getRate(strReq_rate, rate);
}

bool RobotSym::reqInterArrival(RndDistr *&iad) const {
	iad = getDistr(strReq_inter_arrival);
	double rr = -1;
	const bool hasRR = reqRate(rr);
	if (hasRR && iad)
		cerr << loc() << ": cannot specify both request rate"
			<< " and inter-arrival distribution" << endl << xexit;

	if (iad)
		return true;

	if (!hasRR)
		return false;

	if (rr <= 0)
		return true; // iad is nil

	// poisson request stream (default) is modeled using an exponential
	// distribution with a mean of a given request rate
	// all clients should share one rng
	static RndGen rng(GlbPermut(rndRobotSymReqInterArrival));
	iad = new ExpDistr(&rng, 1/rr);
	return true;
}

bool RobotSym::recurRatio(double &ratio) const {
	return getDouble(strRecurrence, ratio);
}

bool RobotSym::embedRecurRatio(double &ratio) const {
	return getDouble(strEmbed_recur, ratio);
}

bool RobotSym::uniqueUrls(bool &set) const {
	return getBool(strUnique_urls, set);
}

bool RobotSym::openConnLimit(int &lmt) const {
	return getInt(strOpen_conn_lmt, lmt);
}

bool RobotSym::waitXactLimit(int &lmt) const {
	return getInt(strWait_xact_lmt, lmt);
}

bool RobotSym::minimizeNewConn(double &prob) const {
	return getDouble(strMinimize_new_conn, prob);
}

SessionSym *RobotSym::session() const {
	const SynSym *ss = getRecSym(strSession);
	return ss ?
		&((SessionSym&)ss->cast(SessionSym::TheType)) : 0;
}

bool RobotSym::authError(double &prob) const {
	return getDouble(strAuth_error, prob);
}

bool RobotSym::icpPort(int &port) const {
	return getInt(strIcp_port, port);
}

NetAddr RobotSym::peerHttp() const {
	return getNetAddr(strPeer_http);
}

NetAddr RobotSym::peerIcp() const {
	return getNetAddr(strPeer_icp);
}

AclSym *RobotSym::acl() const {
	SynSymTblItem *i = 0;
	Assert(theRec->find(strAcl, i));
	return i->sym() ?
		&((AclSym&)i->sym()->cast(AclSym::TheType)) : 0;
}

DnsResolverSym *RobotSym::dnsResolver() const {
	SynSymTblItem *di = 0;
	Assert(theRec->find(strDns_resolver, di));
	return di->sym() ?
		&((DnsResolverSym&)di->sym()->cast(DnsResolverSym::TheType)) : 0;
}

bool RobotSym::privCache(int &capacity) const {
	return getInt(strPrivate_cache_cap, capacity);
}

bool RobotSym::proxies(Array<NetAddr*> &addrs) const {
	return getNetAddrs(strProxies, addrs);
}

bool RobotSym::origins(Array<NetAddr*> &addrs) const {
	return getNetAddrs(strOrigins, addrs);
}

bool RobotSym::origins(Array<NetAddr*> &addrs, RndDistr *&selector) const {
	SynSymTblItem *oi = 0;
	Assert(theRec->find(strOrigins, oi));
	if (!oi->sym())
		return false; // undefined

	// build address array and selector
	origins(addrs);
	ArraySym &os = (ArraySym&)oi->sym()->cast(ArraySym::TheType);
	selector = os.makeSelector(kind() + "-origins");
	return true;
}

String RobotSym::msgTypesField() const {
	return strReq_types;
}

bool RobotSym::credentials(Array<String*> &creds) const {
	return getStrings(strCredentials, creds);
}

bool RobotSym::containerTags(Array<String*> &tags) const {
	return getStrings(strContainerTags, tags);
}

bool RobotSym::acceptedContentCodings(Array<String*> &codings) const {
	return getStrings(strAcceptContentEncodings, codings);
}


bool RobotSym::interests(Array<StringSym*> &istrs, Array<double> &iprobs) const {
	if (ArraySym *a = getArraySym(strInterests)) {
		a->copyProbs(iprobs);
		ArraySymExportM(StringSym, *a, StringSym::TheType, istrs);
		return true;
	}
	return false;
}

RndDistr *RobotSym::interests(const StrIdentifier &interestKinds) const {
	return namesToDistr(strInterests, interestKinds);
}

RndDistr *RobotSym::reqMethods(const StrIdentifier &reqMethodNames) const {
	return namesToDistr(strReq_methods, reqMethodNames);
}

RndDistr *RobotSym::pipelineDepth() const {
	return getDistr(strPipeline_depth);
}

String RobotSym::foreignTrace() const {
	return getString(strForeign_trace);
}

String RobotSym::rawUriThrower() const {
	return getString(strRaw_uri_thrower);
}

RndDistr *RobotSym::cookiesKeepLimit() const {
	return getDistr(strCookies_keep_lmt);
}



syntax highlighted by Code2HTML, v. 0.9.1