/* ui_raytracing.c: user interface raytracing menu */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "ui.h"
#include "uit.h"
#include "raytracing.h"
#include "canvas.h"
#include "camera.h"
#include "error.h"
#include "statistics.h"
#include "render.h"

/*************************** RayTracing Menu ******************************/

static int busy_raytracing = FALSE;


/**************************************************************************/

static int DoRayTracing(void /* char *filename, FILE *fp, int ispipe,
			   Widget filenamePromptBox */)
{
  /* XtUnmanageChild(filenamePromptBox); */
  CanvasPushMode(CANVASMODE_RENDER);
  /* make sure the dialog box has disappeared and the scene is redrawn
   * before starting to raytrace */
  /*  CheckForEvents();
  CanvasCancelRedraw();
  */

  Camera.changed = FALSE;
  renderopts.render_raytraced_image = TRUE;

  busy_raytracing = TRUE;
  RayTrace(NULL, NULL, FALSE/* filename, fp, ispipe */);
  busy_raytracing = FALSE;

  CanvasPullMode();

  return 0;	/* The file selection box has been unmanaged already */
}


/**************************************************************************/

static void RayTracingRunStopCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
#ifdef ASK_FOR_FILENAME
  Widget filenamePromptBox = (Widget)client_data;
#endif

  if(RayTracing == NULL)
  {
    Error(0, "Specify raytracing method first");
  }
  else
  {
    if (!busy_raytracing)
    {
#ifdef ASK_FOR_FILENAME
      XtManageChild(filenamePromptBox);
#endif
      DoRayTracing();
    } 
    else 
    {
      RayTracing->InterruptRayTracing();
    }
  }
}

/* ++++++++++++++++++++++++ RayTracing Control Dialog ++++++++++++++++++ */
static void RayTracingControlCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  if (RayTracing)
    RayTracing->ShowControlPanel();
  else
    Error(NULL, "Specify a raytracing method first");
}

/**************************************************************************/

/* format string to be used for printing statistics about the current or last
 * raytracing run. The format string is the text string assigned to the 
 * raytracingStatsMessage label at startup and is extracted in CreateRayTracingStatsBox()
 * when creating the interface. */

static char *raytracingStatsFormatString = (char *)NULL;

/* XmLabelClass widgets used to display the statstics about the current scene */

static Widget raytracingStatsMessage = (Widget)NULL;


/* updates the raytracing statstics */
void UpdateRayTracingStats(void)
{
  char buf[MAX_LABEL_STRING_LENGTH];

  if (!raytracingStatsFormatString || !raytracingStatsMessage)
    return;

  sprintf(buf, raytracingStatsFormatString,
	  rt_total_time/(float)CLOCKS_PER_SEC, 
	  rt_pixcount/(rt_total_time ? (rt_total_time/(float)CLOCKS_PER_SEC) : 1.),
	  rt_raycount/(rt_total_time ? (rt_total_time/(float)CLOCKS_PER_SEC) : 1.));

  SetLabelString(raytracingStatsMessage, buf);
}


/**************************************************************************/

/* called when the Update button on a stats dialog box is clicked: pops down the
 * statistics dialog box. */
static void UpdateRayTracingStatsCallback(Widget statsBox, XtPointer client_data, XtPointer call_data)
{
  UpdateRayTracingStats();
}


/**************************************************************************/

/* called when the Dismiss button on a stats dialog box is clicked: pops down the
 * statistics dialog box. */
static void DismissStatsCallback(Widget statsBox, XtPointer client_data, XtPointer call_data)
{
  XtUnmanageChild(statsBox);
}


/**************************************************************************/

/* Creates a dialog box for showing statistics about the current scene */
static Widget CreateRayTracingStatsBox(Widget parent, char *name)
{
  Widget statsBox = CreateDialog(parent, name);

  /* create a label widget inside the statsBox */
  raytracingStatsMessage = CreateLabel(statsBox, "raytracingStatsMessage");

  /* at startup, the text defined for the raytracingStatsMessage label widget is nothing 
   * else than the printf format string to be used for printing the statistics. */
  raytracingStatsFormatString = GetLabelString(raytracingStatsMessage);

  /* fill in the statstics for the current scene */
  UpdateRayTracingStats();

  XtAddCallback(statsBox, XmNokCallback, UpdateRayTracingStatsCallback, (XtPointer)NULL);
  XtAddCallback(statsBox, XmNcancelCallback, DismissStatsCallback, (XtPointer)NULL);

  return statsBox;
}


/**************************************************************************/

/* called when the user presses the 'Statistics' button in the raytracing menu */
static void ShowRayTracingStats(Widget statsButton, XtPointer client_data, XtPointer call_data)
{
  Widget statsBox = (Widget)client_data;

  UpdateRayTracingStats();
  XtManageChild(statsBox);
}


/**************************************************************************/

static void SetRayTracingMethodCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  int set = ((XmToggleButtonCallbackStruct *)call_data)->set;
  if (set == XmSET) {
    CanvasPushMode(CANVASMODE_WORKING);
    /* it may take a little while */
    SetRayTracing((RAYTRACINGMETHOD *)client_data);
    CanvasPullMode();
  }
}

static void CreateRayTracingMethodMenu(Widget parent)
{
  Widget methodMenu = CreateSubMenu(parent, "raytracingMethodButton", "raytracingMethodMenu");

  XtVaSetValues(methodMenu,
		XmNradioBehavior, True,
		NULL);

  CreateToggleButton(methodMenu, "NoRayTracingButton",
		     (!RayTracing ? TRUE : FALSE),
		     SetRayTracingMethodCallback, (XtPointer)NULL);

  ForAllRayTracingMethods(method) {
    CreateToggleButton(methodMenu, method->buttonName, 
		       (method == RayTracing ? TRUE : FALSE),
		       SetRayTracingMethodCallback, (XtPointer)method);
  } EndForAll;
}

/**************************************************************************/

static void CreateRayTracingControlPanels(void *parent_widget)
{
  ForAllRayTracingMethods(method) {
    method->CreateControlPanel(parent_widget);
  } EndForAll;
}

/**************************************************************************/

static void RayTracingRedisplayCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  /* make sure the dialog box has disappeared and the scene is redrawn
   * before starting to raytrace */  
  CanvasPushMode(CANVASMODE_RENDER);
  /*  CheckForEvents();
      CanvasRedraw(); */

  if (!RayTracing)
    Warning(NULL, "No ray tracing method active");
  else if (!RayTracing->Redisplay || !RayTracing->Redisplay())
    Warning(NULL, "No previous %s image available", RayTracing->fullName);
  else {	/* redisplay was succesful */
    Camera.changed = FALSE;
    renderopts.render_raytraced_image = TRUE;
  }

  CanvasPullMode();
}

static void RayTracingReprojectCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  /* make sure the dialog box has disappeared and the scene is redrawn
   * before starting to raytrace */  
  CanvasPushMode(CANVASMODE_RENDER);
  /*  CheckForEvents();
      CanvasRedraw(); */

  if (!RayTracing)
    Warning(NULL, "No ray tracing method active");
  else if (!RayTracing->Reproject || !RayTracing->Reproject())
    Warning(NULL, "No previous %s image available", RayTracing->fullName);
  else {	/* reproject was succesful */
    Camera.changed = FALSE;
    renderopts.render_raytraced_image = TRUE;
  }

  CanvasPullMode();
}

static int RayTracingSaveImage(char *fname, FILE *fp, int ispipe, Widget fsbox)
{
  ImageOutputHandle *img = NULL;

  if (fp) {
    img = CreateRadianceImageOutputHandle(fname, fp, ispipe, 
					  Camera.hres, Camera.vres, reference_luminance/179.);
    if (!img) return 0;
  }

  if (!RayTracing)
    Warning(NULL, "No ray tracing method active");
  else if (!RayTracing->SaveImage || !RayTracing->SaveImage(img))
    Warning(NULL, "No previous %s image available", RayTracing->fullName);

  if (img)
    DeleteImageOutputHandle(img);

  return 1;	/* unmanage the file section dialog */
}

static Widget CreateSaveImageDialog(Widget parent, char *name)
{
  return CreateFileSelectionDialog(parent, name, RayTracingSaveImage, "w");
}

/**************************************************************************/

void CreateRayTracingMenu(Widget menuBar)
{
  Widget raytracingMenu, raytracingControlButton;
#ifdef ASK_FOR_FILENAME
  Widget filenamePromptBox;
#endif

  raytracingMenu = CreateSubMenu(menuBar, "raytracingButton", "raytracingMenu");

  CreateRayTracingMethodMenu(raytracingMenu);

  raytracingControlButton = CreatePushButton(raytracingMenu, "raytracingControlButton",
					     RayTracingControlCallback, (XtPointer)NULL);
  CreateRayTracingControlPanels(raytracingControlButton);
  CreateSeparator(raytracingMenu, "raytracingSeparator");

#ifdef ASK_FOR_FILENAME
  /* dialog asking for a filename etc... */
  filenamePromptBox = CreateFileSelectionDialog(raytracingMenu, "filenamePromptBox", 
						DoRayTracing, "w");
#endif

  CreatePushButton(raytracingMenu, "raytracingRunStopButton", 
		   RayTracingRunStopCallback, (XtPointer)NULL /* filenamePromptBox */);

  busy_raytracing = FALSE;
  CreateSeparator(raytracingMenu, "raytracingSeparator");

  /* redisplay last image button */
  CreatePushButton(raytracingMenu, "raytracingRedisplayButton",
		   RayTracingRedisplayCallback, NULL);
#ifdef RT_REPROJECT_BUTTON
  CreatePushButton(raytracingMenu, "raytracingReprojectButton",
		   RayTracingReprojectCallback, NULL);
#endif
  /* save last image */
  CreateCascadeDialog(raytracingMenu, "raytracingSaveImageButton", 
		      CreateSaveImageDialog, "filenamePromptBox",
		      NULL, NULL);

  CreateSeparator(raytracingMenu, "raytracingSeparator");
  CreateCascadeDialog(raytracingMenu, "statsButton", CreateRayTracingStatsBox, "statsBox", 
		      ShowRayTracingStats, NULL);
}




