#include <v_lib.h>
#include "psy.h"
#include "monitor.h"
#include "psys.h"
#include "util.h"
#include "phasesp.h"

/*
 * -----------------------------------------------------------------------
 * PSY output stuff
 */
typedef struct psy_output_s
{
	u32_t       framenum;
	vboolean    noflush;
	vhandle_t   outfile;
}   psy_output_t, *psy_output_p;

V_LOCAL vboolean V_CALL
psy_save_frame(particle_system_p ps)
{
	vec_t curtime;
	u32_t i,limit = ps->num_particles-1;
	vec_p phase = ps->cur_phase, p, v;
	psy_output_p ctx = (psy_output_p)ps->monitoring_context;
	filePrintf(ctx->outfile,"frame %u\n{\n",ctx->framenum++);
	for(i=0;i<limit;i++)
	{
		vec_t *p = PS_POS(phase,i);
		vec_t *v = PS_VEL(phase,i);
		filePrintf(ctx->outfile,"\t{%g,%g,%g},{%g,%g,%g},\n",
			p[0],p[1],p[2],
			v[0],v[1],v[2]);
	}
	p = PS_POS(phase,i);
	v = PS_VEL(phase,i);
	filePrintf(ctx->outfile,"\t{%g,%g,%g},{%g,%g,%g}\n}\n",
		p[0],p[1],p[2],
		v[0],v[1],v[2]);
	curtime = timerTime(ps->rt_timer);
	if(curtime < ps->solution_realtime_limit)
	{
		conlPrintf(LOG_TRACE,
			"psy_save_frame(): saved frame %u "
			"(time %g,realtime %g,rt_limit %g)\n",
			ctx->framenum,ps->cur_time,curtime,ps->solution_realtime_limit);
		if(!ctx->noflush)
			fileControl(ctx->outfile,pctl_flush,NULL);
	}
	else
	{
		conlPrintf(LOG_TRACE,
			"psy_save_frame(): last frame %u (realtime %g,rt_limit %g)\n",
			ctx->framenum,curtime,ps->solution_realtime_limit);
		return false;
	}
	return true;
}

V_LOCAL vboolean V_CALL
psy_end_monitoring(particle_system_p ps)
{
	psy_output_p ctx = (psy_output_p)ps->monitoring_context;
	fileClose(ctx->outfile);
	memFree(ctx);
	return true;
}

vboolean
init_psy_context(particle_system_p ps)
{
	char outfile_name[_MAX_PATH] = "";
	psy_output_p ctx;
	vboolean noflush = false;
	scanner_t sc = tokParseString(ps->monitor_setup,"");
	while(tokNext(sc))
	{
		if(!strcmp(tokLast(sc),"filename"))
		{
			strCopy(outfile_name,tokNext(sc),_MAX_PATH);
			continue;
		}
		if(!strcmp(tokLast(sc),"noflush"))
		{
			noflush = true;
			continue;
		}
		conlPrintf(LOG_WARNING,"init_psy_context(): unknown token '%s'.\n",
			tokLast(sc));
	}
	tokDestroy(sc);
	ctx = (psy_output_p)memAlloc(sizeof(psy_output_t));
	memZero(ctx,sizeof(psy_output_t));
	ctx->outfile = fileOpenWrite(outfile_name);
	if(ctx->outfile == LIBV_INVALID_HANDLE)
	{
		conlPrintf(LOG_ERROR,"init_psy_context(): unable to open '%s'.\n",
			outfile_name);
		memFree(ctx);
		return false;
	}
	ctx->framenum = 0;
	ctx->noflush = noflush;
	ps->monitor = psy_save_frame;
	ps->monitoring_context = ctx;
	ps->end_monitoring = psy_end_monitoring;
	return true;
}
