/*
Copyright (c) 2001                      RIPE NCC


All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
-------------------------------------------------------------------------------
Module Header
Filename          : TTMStatistics.C
Author            : Rene Wilhelm
Date              : 28-JUN-2001
Description       : Implementation of TTMStatistics class
Language Version  : C++
OSs Tested        : Solaris 2.6, Solaris 8, Debian Linux 2.2

TODO		  : routing vector statistics


$Id: TTMStatistics.C,v 1.2 2003/05/16 13:57:41 ttraffic Exp $
-------------------------------------------------------------------------------
*/

#define SECONDSPERDAY 86400

#include "TTMStatistics.h"

static char const rcsid[] = "$Id: TTMStatistics.C,v 1.2 2003/05/16 13:57:41 ttraffic Exp $";
static char const *rcsid_p = rcsid;   // Prevent g++ from optimizing out rcsid


/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   TTM Statistics constructor
Comments        :   initializes parameters and pointers
-------------------------------------------------------------------------------
*/
TTMStatistics::TTMStatistics() {

	numIntervals = 0;
	secondsPerInterval = 9999999;

	delays          = NULL;
	numPacketsSent  = NULL;
	numPacketsValid = NULL;
	numLost         = NULL;

	totalPacketsSent  = 0;
	totalPacketsValid = 0;
	totalLost         = 0;

	// initialize Routevector stats

	vectorsize    = 256;
	entries = 0;
	flaps   = -1;
	lastid  = -1;
	minhops =  999;		// first entry will set real values
	maxhops = -999;
	
	// can't use "new" operator, since we want to be able to realloc 
	routevectors = (int *) malloc (sizeof(int)*vectorsize);
}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Initialize number of intervals and related data members
Comments        :
-------------------------------------------------------------------------------
*/
void TTMStatistics::SetNumIntervals(int nIntervals) {

	if (nIntervals != numIntervals) {
		numIntervals = nIntervals;
		secondsPerInterval = SECONDSPERDAY / numIntervals;

		if (delays != NULL) {
			// must delete old arrays
			delete[] delays;
			delete[] numPacketsSent;
			delete[] numPacketsValid;
			delete[] numLost;
		}

		delays          = new Percentiles[numIntervals];
		numPacketsSent  = new int[numIntervals];
		numPacketsValid = new int[numIntervals];
		numLost         = new int[numIntervals]; 

		for (int i=0; i<numIntervals; i++) {
			numPacketsSent[i] =0;
			numPacketsValid[i] =0;
			numLost[i]=0;
		}
	}
}



/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Update Statistics with info from given delay measurement
Input		:   Delay object, tinestamp at start of analysis period
Comments        :
-------------------------------------------------------------------------------
*/

void TTMStatistics::Update(Delay *packet, time_t starttime) {
	
	if (numIntervals == 0) {
		cerr << "TTMStatistics: numIntervals not initialized!" << endl;
		return;  
	}

	Float_t packetdelay = packet->GetPacketDelay();

	time_t timesent = (time_t) packet->GetPacketTime(starttime);


	int daysec = timesent % SECONDSPERDAY; // #seconds since 00:00 this day
	int interval = daysec / secondsPerInterval;   

	if ((interval<0) || (interval >= numIntervals)) {
		cerr << "Interval " << interval << " out of range!" << endl <<
		        "PacketId: " << timesent << " Source: " << 
	   	        packet->GetSourceId() << " Target: " <<
		        packet->GetTargetId() << endl;
	}

	totalPacketsSent++;
	numPacketsSent[interval]++;

        if (packet->Status() == ClockValid) {
               	allDelays.Add(packetdelay);
               	delays[interval].Add(packetdelay);
		totalPacketsValid++;
		numPacketsValid[interval]++;
	}
	else if (packet->Status() == PacketLost) {
		totalLost++;
		numLost[interval]++;
	}

/*
	if (vectorid != lastid) {
		// route changed, increase flap count
		lastid = vectorid;
		flaps++;
	}
		
	// Update: check if vector already seen, if not add it to
	// the list and update max/min hops

	for (int i=0; i<entries; i++) {
		if (routevectors[i] == vectorid) {
			// already seen
			return;
		}
	}

	// new vector
	if (entries == vectorsize) {
		//have to resize
		if (vectorsize > 4000) {
			vectorsize += 2048;
		}
		else {
			vectorsize += vectorsize; // double the size
		}
		routevectors = (int *) realloc (routevectors, 
						sizeof(int)*vectorsize);
	}
	routevectors[entries] = vectorid;
	entries++;
	if (nhops < minhops) {
		minhops = nhops;
	}
	if (nhops > maxhops) {
		maxhops = nhops;
	}
*/

}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Reset Statistics 
Comments        :
-------------------------------------------------------------------------------
*/

void TTMStatistics::Reset() { 

	// Reset Percentile objects and counters
	for (int i=0;i<numIntervals; i++) {
		delays[i].Reset();
		numPacketsSent[i] = 0;
		numPacketsValid[i] = 0;
		numLost[i] = 0;
	}
	allDelays.Reset();
	totalPacketsSent  = 0;
	totalPacketsValid = 0;
	totalLost = 0;
	
	// Reset Routevector stats
	entries = 0;
	flaps   = -1;		// first vector will set this to 0
				// after that count real changes
	lastid  = -1;		// guaranteed to be different from real vector
	minhops =  999;		// first entry will set real values
	maxhops = -999;
};

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Return requested percentile of Delay distribution
Input		:   interval number (0 = complete dataset),
		    percentile requested (e.g. 50 := median)
Output		:   delay value at requested percent level
Comments        :
-------------------------------------------------------------------------------
*/

float TTMStatistics::GetDelayPerc(int interval, float percentile) { 
	
	// double check input parameters

	if ((percentile < 0) || (percentile > 100)) {
		cerr << "TTMStatistics::GetDelayPerc: percentile "
		     << percentile << " out of range [0-100]" << endl; 
		return(-1);
	}

	if ((interval < 0) || (interval > numIntervals)) {
		cerr << "TTMStatistics::GetDelayPerc: interval no "
		     << interval << " out of range [0-" << numIntervals << "]"
		     << endl;
		return(-1);
	}

	if (interval == 0) {
		return(allDelays.GetLevel(percentile));
	}
	else {
		return(delays[interval-1].GetLevel(percentile));
	}
}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Return packet loss rate of requested interval
Comments	:   interval number 0 means complete dataset
-------------------------------------------------------------------------------
*/

float TTMStatistics::GetLossRate(int interval) {
	
	int nLost, nSent;

	// double check input parameter

	if ((interval < 0) || (interval > numIntervals)) {
		cerr << "TTMStatistics::GetDelayPerc: interval no "
		     << interval << " out of range [0-" << numIntervals << "]"
		     << endl;
		return(-1);
	}

	if (totalPacketsSent == 0) {
		 return(-1); // no packets send, loss rate undefined
	}

	if (interval == 0) {
		nLost = totalLost;
		nSent = totalPacketsSent;
	}
	else {
		nLost = numLost[interval-1];
		nSent = numPacketsSent[interval-1];
	}
	return( (nSent>0) ? nLost/float(nSent) : -1 );
}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Return number of packets sent in requested interval
Comments	:   interval number 0 means complete dataset
-------------------------------------------------------------------------------
*/

int TTMStatistics::GetNumPacketsSent(int interval) {
	
	// double check input parameter

	if ((interval < 0) || (interval > numIntervals)) {
		cerr << "TTMStatistics::GetDelayPerc: interval no "
		     << interval << " out of range [0-" << numIntervals << "]"
		     << endl;
		return(-1);
	}

	if (interval == 0) {
		return(totalPacketsSent);
	}
	else {
		return(numPacketsSent[interval-1]);
	}
}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   Return number of valid packets seen in requested interval
Comments	:   interval number 0 means complete dataset
-------------------------------------------------------------------------------
*/

int TTMStatistics::GetNumPacketsValid(int interval) {
	
	// double check input parameter

	if ((interval < 0) || (interval > numIntervals)) {
		cerr << "TTMStatistics::GetDelayPerc: interval no "
		     << interval << " out of range [0-" << numIntervals << "]"
		     << endl;
		return(-1);
	}

	if (interval == 0) {
		return(totalPacketsValid);
	}
	else {
		return(numPacketsValid[interval-1]);
	}
}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose         :   TTM Statistics destructor
Comments        :
-------------------------------------------------------------------------------
*/

TTMStatistics::~TTMStatistics() { 

	delete[] delays;
	delete[] numPacketsSent;
	delete[] numPacketsValid;
	delete[] numLost;

	free(routevectors);  // directly assigned by malloc!

};
