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

#include "xstd/Socket.h"
#include "xstd/Ssl.h"
#include "base/ILog.h"
#include "base/OLog.h"
#include "base/StatIntvlRec.h"

#include "xstd/gadgets.h"

EmbedStats TheEmbedStats;


StatIntvlRec::StatIntvlRec(): theXactCnt(0), theXactErrCnt(0), theXactRetrCnt(0) {
}

void StatIntvlRec::restart() {
	thePopulusLvl.restart();
	theWaitLvl.restart();
	theXactLvl.restart();
	theOpenLvl.restart();
	theEstbLvl.restart();

	theConnLifeTm.reset();
	theConnUseCnt.reset();
	theConnPipelineDepth.reset();

	theIdealHR.reset();
	theRealHR.reset();
	theChbR.reset();

	theFill.reset();
	theRediredReq.reset();
	theRepToRedir.reset();
	theIms.reset();
	theReload.reset();
	theHead.reset();
	thePost.reset();
	thePut.reset();
	theAbort.reset();

	thePage.reset();

	theXactCnt = theXactErrCnt = theXactRetrCnt = 0;

	theIcpStat.reset();
	theSslStat.restart();

	theDuration = Time();
}

OLog &StatIntvlRec::store(OLog &log) const {
	Assert(theDuration >= 0);
	return log
		<< thePopulusLvl
		<< theWaitLvl << theXactLvl << theOpenLvl << theEstbLvl
		<< theConnLifeTm << theConnUseCnt
		<< theIdealHR << theRealHR << theChbR
		<< theFill 
		<< theRediredReq << theRepToRedir << theIms << theReload
		<< theHead << thePost << thePut << theAbort
		<< thePage
		<< theXactCnt
		<< theXactErrCnt
		<< theXactRetrCnt
		<< theIcpStat
		<< theSslStat
		<< theDuration
		<< theConnPipelineDepth
		;
}

ILog &StatIntvlRec::load(ILog &log) {
	return log
		>> thePopulusLvl
		>> theWaitLvl >> theXactLvl >> theOpenLvl >> theEstbLvl
		>> theConnLifeTm >> theConnUseCnt
		>> theIdealHR >> theRealHR >> theChbR
		>> theFill 
		>> theRediredReq >> theRepToRedir >> theIms >> theReload
		>> theHead >> thePost >> thePut >> theAbort
		>> thePage
		>> theXactCnt
		>> theXactErrCnt
		>> theXactRetrCnt
		>> theIcpStat
		>> theSslStat
		>> theDuration
		>> theConnPipelineDepth
		;
}

bool StatIntvlRec::sane() const {
	return
		thePopulusLvl.sane() &&
		theWaitLvl.sane() && theXactLvl.sane() &&
		theOpenLvl.sane() && theEstbLvl.sane() &&
		theConnLifeTm.sane() && theConnUseCnt.sane() &&
		theConnPipelineDepth.sane() && 
		theRediredReq.sane() && theReload.sane() &&
		theHead.sane() && thePost.sane() && thePut.sane() && theAbort.sane() &&
		thePage.sane() &&
		theSslStat.sane() && theIcpStat.sane() &&
		theXactCnt >= 0 && theXactErrCnt >= 0 && 
		theXactRetrCnt >= 0 &&
		theDuration >= 0;
}

BigSize StatIntvlRec::totFillSize() const {
	return BigSize::Byted(theFill.size().sum());
}

int StatIntvlRec::totFillCount() const {
	return theFill.size().count();
}

double StatIntvlRec::errRatio() const {
	return Ratio(theXactErrCnt, xactCnt());
}

double StatIntvlRec::errPercent() const {
	return Percent(theXactErrCnt, xactCnt());
}

// XXX: we should have Rate type, not double
double StatIntvlRec::reqRate() const {
	return theDuration > 0 ?
		Ratio(theXactLvl.incCnt(), theDuration.secd()) : -1;
}

double StatIntvlRec::repRate() const {
	return theDuration > 0 ?
		Ratio(theXactLvl.decCnt(), theDuration.secd()) : -1;
}

double StatIntvlRec::reqBwidth() const {
	return theDuration > 0 ?
		Ratio(reps().size().sum(), theDuration.secd()) : -1;
}

double StatIntvlRec::repBwidth() const {
	return theDuration > 0 ?
		Ratio(reps().size().sum(), theDuration.secd()) : -1;
}

AggrStat StatIntvlRec::repTime() const {
	return reps().time();
}

AggrStat StatIntvlRec::repSize() const {
	return reps().size();
}

TmSzStat StatIntvlRec::reps() const {
	TmSzStat reps;
	reps += theRealHR.xacts();
	reps += theRediredReq;
	reps += theRepToRedir;
	reps += theIms;
	reps += theReload;
	reps += theHead;
	reps += thePost;
	reps += thePut;
	return reps;
}

void StatIntvlRec::keepLevels(const StatIntvlRec &prevIntvl) {
	thePopulusLvl.keepLevel(prevIntvl.thePopulusLvl);
	theWaitLvl.keepLevel(prevIntvl.theWaitLvl);
	theXactLvl.keepLevel(prevIntvl.theXactLvl);
	theOpenLvl.keepLevel(prevIntvl.theOpenLvl);
	theEstbLvl.keepLevel(prevIntvl.theEstbLvl);
	theSslStat.keepLevel(prevIntvl.theSslStat);
}

void StatIntvlRec::concat(const StatIntvlRec &s) {
	if (theDuration >= 0)
		theDuration += s.theDuration;

	thePopulusLvl.concat(s.thePopulusLvl);
	theWaitLvl.concat(s.theWaitLvl);
	theXactLvl.concat(s.theXactLvl);
	theOpenLvl.concat(s.theOpenLvl);
	theEstbLvl.concat(s.theEstbLvl);
	theSslStat.concat(s.theSslStat);

	join(s);
}

void StatIntvlRec::merge(const StatIntvlRec &s) {
	if (theDuration >= 0)
		theDuration = Max(theDuration, s.theDuration);
	thePopulusLvl.merge(s.thePopulusLvl);
	theWaitLvl.merge(s.theWaitLvl);
	theXactLvl.merge(s.theXactLvl);
	theOpenLvl.merge(s.theOpenLvl);
	theEstbLvl.merge(s.theEstbLvl);
	theSslStat.merge(s.theSslStat);

	join(s);
}

void StatIntvlRec::join(const StatIntvlRec &s) {
	Assert(s.theDuration >= 0);
	if (theDuration < 0)
		theDuration = s.theDuration;

	theConnLifeTm += s.theConnLifeTm;
	theConnUseCnt += s.theConnUseCnt;
	theConnPipelineDepth += s.theConnPipelineDepth;

	theIdealHR += s.theIdealHR;
	theRealHR += s.theRealHR;
	theChbR += s.theChbR;

	theFill += s.theFill;
	theRediredReq += s.theRediredReq;
	theRepToRedir += s.theRepToRedir;
	theIms += s.theIms;
	theReload += s.theReload;
	theHead += s.theHead;
	thePost += s.thePost;
	thePut += s.thePut;
	theAbort += s.theAbort;

	thePage += s.thePage;

	theXactCnt += s.theXactCnt;
	theXactErrCnt += s.theXactErrCnt;
	theXactRetrCnt += s.theXactRetrCnt;

	theIcpStat += s.theIcpStat;
}

ostream &StatIntvlRec::print(ostream &os, const String &pfx) const {
	os << pfx << "req.rate:\t " << reqRate() << endl;
	os << pfx << "rep.rate:\t " << repRate() << endl;

	reps().print(os, pfx + "rep.");

	theRealHR.xacts().print(os, pfx + "basic.");
	theIdealHR.print(os, "hit", "miss", pfx + "offered.");
	theRealHR.print(os, "hit", "miss", pfx);
	theChbR.print(os, "cachable", "uncachable", pfx);
	theFill.print(os, pfx + "fill.");

	theRediredReq.print(os, pfx + "redired_req.");
	theRepToRedir.print(os, pfx + "rep_to_redir.");
	theIms.print(os, pfx + "ims.");
	theReload.print(os, pfx + "reload.");
	theHead.print(os, pfx + "head.");
	thePost.print(os, pfx + "post.");
	thePut.print(os, pfx + "put.");
	theAbort.print(os, pfx + "abort.");

	thePage.print(os, pfx + "page.");

	theXactLvl.print(os, pfx + "xact.");

	os << pfx << "ok_xact.count: \t " << theXactCnt << endl;
	os << pfx << "err_xact.ratio:\t " << errPercent() << endl;
	os << pfx << "err_xact.count:\t " << theXactErrCnt << endl;
	os << pfx << "retr_xact.count:\t " << theXactRetrCnt << endl;

	thePopulusLvl.print(os, pfx + "populus.");
	theWaitLvl.print(os, pfx + "wait.");
	theOpenLvl.print(os, pfx + "conn.open.");
	theEstbLvl.print(os, pfx + "conn.estb.");
	theConnLifeTm.print(os, pfx + "conn.ttl.");
	theConnUseCnt.print(os, pfx + "conn.use.");
	theConnPipelineDepth.print(os, pfx + "conn.pipeline.depth.");

	theIcpStat.print(os, pfx + "icp.", theDuration);
	theSslStat.print(os, pfx + "ssl.", theDuration);

	os << pfx << "duration:\t " << theDuration.secd() << endl;

	return os;
}

void StatIntvlRec::linePrintSsl(ostream &os, bool includeLevels) const {
	os
		<< ' ' << setw(6) << TheProgress.sslXacts()
		<< ' ' << setw(6) << theSslStat.repRate(theDuration)
		<< ' ' << setw(6) << (int)rint(theSslStat.doneXacts().xacts().time().mean())
		<< ' ' << setw(6) << theSslStat.doneXacts().dhp()
		<< ' ' << setw(3) << theSslStat.errXacts()
		;

	if (includeLevels)
		os << ' ' << setw(4) << Ssl::Level();

	os << " https";
}

void StatIntvlRec::linePrintAll(ostream &os, bool includeLevels) const {
	os
		<< ' ' << setw(6) << TheProgress.xacts()
		<< ' ' << setw(6) << repRate()
		<< ' ' << setw(6) << (int)rint(repTime().mean())
		<< ' ' << setw(6) << theRealHR.dhp()
		<< ' ' << setw(3) << theXactErrCnt
		;

	if (includeLevels)
		os << ' ' << setw(4) << Socket::Level();

	if (theSslStat.active())
		os << " all";
}


syntax highlighted by Code2HTML, v. 0.9.1