/*
 * Author: Radovan Cerveny
 */

#include "../MeasurementFrame.hpp"

namespace measurements {

void MemoryDataFrame::init ( unsigned frameIdx, measurements::stealth_vector < MeasurementFrame > & frames ) {
	MeasurementFrame & currentFrame = frames[frameIdx];
	MeasurementFrame & parentFrame	= frames[currentFrame.parentIdx];

	 // "hacky" adjustment, if this is the first user inserted frame, we reset ROOTs values to 0
	 // beacause we want the heap usage to start at 0 and also we want to be able to propagate ROOTs values between separate
	 // user OVERALL frames
	if ( ( parentFrame.type == measurements::Type::ROOT ) && ( frames.size ( ) == 2 ) ) {
		parentFrame.memory.startHeapUsage = 0;
		parentFrame.memory.currentHeapUsage = 0;
		parentFrame.memory.highWatermark = 0;
		parentFrame.memory.inFrameHighWatermark = 0;
	}

	currentFrame.memory.startHeapUsage = parentFrame.memory.currentHeapUsage;
	currentFrame.memory.currentHeapUsage = parentFrame.memory.currentHeapUsage;
	currentFrame.memory.highWatermark = parentFrame.memory.currentHeapUsage;
	currentFrame.memory.inFrameHighWatermark = parentFrame.memory.currentHeapUsage;
}

void MemoryDataFrame::update ( unsigned frameIdx, measurements::stealth_vector < MeasurementFrame > & frames ) {
	MeasurementFrame & currentFrame = frames[frameIdx];
	MeasurementFrame & parentFrame	= frames[currentFrame.parentIdx];

	currentFrame.memory.endHeapUsage = currentFrame.memory.currentHeapUsage;

	 // if we end up with more memory from children, adjust watermark
	if ( currentFrame.memory.currentHeapUsage > currentFrame.memory.inFrameHighWatermark )
		currentFrame.memory.inFrameHighWatermark = currentFrame.memory.currentHeapUsage;

	if ( currentFrame.memory.highWatermark < currentFrame.memory.inFrameHighWatermark )
		currentFrame.memory.highWatermark = currentFrame.memory.inFrameHighWatermark;

	if ( parentFrame.memory.highWatermark < currentFrame.memory.highWatermark )
		parentFrame.memory.highWatermark = currentFrame.memory.highWatermark;

	parentFrame.memory.currentHeapUsage = currentFrame.memory.currentHeapUsage;
}

void MemoryDataFrame::hint ( unsigned frameIdx, measurements::stealth_vector < MeasurementFrame > & frames, MemoryHint hint ) {

	MeasurementFrame & currentFrame = frames[frameIdx];

	switch ( hint.type ) {
	case MemoryHint::Type::NEW:
		currentFrame.memory.currentHeapUsage += hint.size;

		if ( currentFrame.memory.currentHeapUsage > currentFrame.memory.inFrameHighWatermark )
			currentFrame.memory.inFrameHighWatermark = currentFrame.memory.currentHeapUsage;

		break;

	case MemoryHint::Type::DELETE:
		currentFrame.memory.currentHeapUsage -= hint.size;
		break;
	}
}

MemoryDataFrame MemoryDataFrame::aggregate ( const std::vector < MeasurementFrame > & framesToAggregate ) {
	 // FIXME dummmy aggregation
	return framesToAggregate[0].memory;
}

std::ostream & operator <<( std::ostream & os, const MemoryDataFrame & mdf ) {
	os << mdf.startHeapUsage << "B shu, " << mdf.endHeapUsage << "B ehu, " << mdf.highWatermark << "B hw, " << mdf.inFrameHighWatermark << "B if_hw";
	return os;
}

}
