#include "base.h"

FILE *logfile = NULL;

//
// Attempt to determine what the operating system sees in terms of the memory used by this process.
// This is system-dependent; OSX does not have the /proc/<pid>/status file, so we query the kernel
// directly. Linux systems have a /proc/<pid>/status file for each running process, so parse that.
//

#ifdef __MACH__
	// source: http://blog.kuriositaet.de/?p=257 - I think the author is Tim Becker, based on some slides on the same blog!
	int getmem( unsigned int *rss, unsigned int *vs )
	{
		struct task_basic_info t_info;
		mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

		if( KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count) ) return -1;
		*rss = t_info.resident_size;
		*vs  = t_info.virtual_size;
		return 0;
	}
#else
	// based on example code on the Lockless Inc. website: http://locklessinc.com/articles/memory_usage/
	int getmem( unsigned int *rss, unsigned int *vs )
	{
		char line[128], buf[64];
		char *strings[2];
		FILE *f;

		*rss = *vs = 0;

		for( int i=0; i<2; i++ ) strings[i] = NULL;

		sprintf( buf, "/proc/%d/status", getpid() );
		if( (f = fopen( buf, "r" )) == NULL ) return 0;

		while( !strings[0] || !strings[1] )
		{
			if( fgets( line, sizeof(line), f ) == NULL )
			{
				fclose( f );
				return 0;
			}
			if(      strncmp( line, "VmSize:", 7 ) == 0 ) strings[0] = strdup( &line[7] );
			else if( strncmp( line, "VmRSS:",  6 ) == 0 ) strings[1] = strdup( &line[6] );
		}
		fclose( f );

		for( int i=0; i<2; i++ )
		{
			int len = strlen( strings[i] );
			strings[i][ len - 4 ] = 0;
		}

		*vs = atoi( strings[0] ) * 1024;
		*rss = atoi( strings[1] ) * 1024;

		for( int i=0; i<2; i++ ) free( strings[i] );

		return 0;
	}
#endif


double GetTime()
{
	return MPI_Wtime();
}
void Log( const char *format, ... )
{
	char buffer[512]; // you know what they say about assumptions, right?
	va_list args;

	va_start( args, format );
	vsprintf( buffer, format, args );
	va_end( args );

	if( logfile != NULL ) fprintf( logfile, "%s", buffer );
}

void Error( const char *called_from, const char *in_file, int on_line, const char *format, ... )
{
	int rank, nranks;
	va_list args;
	char buffer[1024]; // <- Turing weeps gently
	
	MPI_Comm_rank( MPI_COMM_WORLD, &rank );
	MPI_Comm_size( MPI_COMM_WORLD, &nranks );

	Log( "\n***** ERROR: rank %d/%d *****\n", rank, nranks );
	Log( "\nSource: %s(), %s:%d\n", called_from, in_file, on_line );
	
	va_start( args, format );
	vsprintf( buffer, format, args );
	va_end( args );
	
	Log( "\nMessage: %s\n\n", buffer );
	
	Log( "******************\n" );

	if( logfile != NULL ) fflush( logfile );

	MPI_Abort( MPI_COMM_WORLD, -1 );
}
