/*
 * Author: Radovan Cerveny
 */
#include "MeasurementResults.hpp"

namespace measurements {

MeasurementResults::MeasurementResults ( ) = default;

MeasurementResults::MeasurementResults ( const measurements::stealth_vector < MeasurementFrame > & resultFrames ) : frames ( resultFrames ) {
}

void MeasurementResults::printAsList ( std::ostream & os ) const {
	printAsList ( os, 0 );
}

void MeasurementResults::printAsList ( std::ostream & os, unsigned idx ) const {
	const MeasurementFrame & frame = frames[idx];

	if ( frame.type != measurements::Type::ROOT ) {
		os << frame;

		if ( idx != frames.size ( ) - 1 )
			os << ", ";
	}

	for ( unsigned subIdx : frame.subIdxs )
		printAsList ( os, subIdx );
}

void MeasurementResults::printAsTree ( std::ostream & os ) const {
	std::string prefix;

	printAsTree ( os, 0, prefix, false );
}

void MeasurementResults::printAsTree ( std::ostream & os, unsigned idx, std::string & prefix, bool lastInParent ) const {
	const MeasurementFrame & frame = frames[idx];

	if ( frame.type == measurements::Type::ROOT ) {
		if ( !frame.subIdxs.empty ( ) ) {
			prefix = "|-";

			lastInParent = false;

			for ( unsigned subIdx : frame.subIdxs ) {

				prefix[prefix.size ( ) - 2] = '|';
				prefix[prefix.size ( ) - 1] = '-';

				if ( subIdx == frame.subIdxs.front ( ) )
					prefix[prefix.size ( ) - 2] = '+';

				if ( subIdx == frame.subIdxs.back ( ) ) {
					prefix[prefix.size ( ) - 2] = '\\';
					lastInParent = true;
				}

				printAsTree ( os, subIdx, prefix, lastInParent );
			}
		}
	} else {
		if ( !frame.subIdxs.empty ( ) ) {
			prefix += '+';
			os << prefix << frame << std::endl;
			prefix += '-';

			prefix[prefix.size ( ) - 3] = ' ';

			if ( lastInParent )
				prefix[prefix.size ( ) - 4] = ' ';
			else
				prefix[prefix.size ( ) - 4] = '|';

			lastInParent = false;

			for ( unsigned subIdx : frame.subIdxs ) {

				prefix[prefix.size ( ) - 2] = '|';
				prefix[prefix.size ( ) - 1] = '-';

				if ( subIdx == frame.subIdxs.back ( ) ) {
					prefix[prefix.size ( ) - 2] = '\\';
					lastInParent = true;
				}

				printAsTree ( os, subIdx, prefix, lastInParent );
			}

			prefix.erase ( prefix.size ( ) - 2 );

		} else {
			os << prefix << frame << std::endl;
		}
	}
}

MeasurementResults MeasurementResults::aggregate ( const std::vector < MeasurementResults > & resultsToAggregate ) {
	MeasurementResults aggregatedResults;

	size_t frameCount = resultsToAggregate[0].frames.size ( );

	for ( size_t frameIdx = 0; frameIdx < frameCount; ++frameIdx ) {
		std::vector < MeasurementFrame > framesToAggregate;

		for ( const MeasurementResults & measurementResults : resultsToAggregate )
			framesToAggregate.push_back ( measurementResults.frames[frameIdx] );

		aggregatedResults.frames.push_back ( MeasurementFrame::aggregate ( framesToAggregate ) );
	}

	return aggregatedResults;
}

const int MeasurementXalloc::FORMAT = std::ios::xalloc ( );

std::ostream & operator <<( std::ostream & os, const MeasurementResults & mr ) {
	MeasurementFormat mf = MeasurementFormat::LIST;

	int os_format = os.iword ( MeasurementXalloc::FORMAT );

	 // if format was set, use that format, otherwise default to XML
	if ( os_format )
		mf = static_cast < MeasurementFormat > ( os_format );

	switch ( mf ) {
	case MeasurementFormat::LIST:
		mr.printAsList ( os );
		break;
	case MeasurementFormat::TREE:
		mr.printAsTree ( os );
		break;
	}

	return os;
}

}
