/* ui_radiance.c: user interface radiance menu */

#include <stdio.h>

#include "ui.h"
#include "uit.h"
#include "radiance.h"
#include "statistics.h"
#include "scene.h"
#include "canvas.h"
#include "render.h"
#include "error.h"


/************************** Radiance menu ********************************/

/* ++++++++++++++++++++++++ Radiance Method submenu ++++++++++++++++++ */
static void SetRadianceMethodCallback(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 */
    SetRadianceMethod((RADIANCEMETHOD *)client_data);
    CanvasPullMode();
    RenderNewDisplayList();
    RenderScene();
  }
}

static void CreateRadianceMethodMenu(Widget parent)
{
  Widget methodMenu = CreateSubMenu(parent, "radianceMethodButton", "radianceMethodMenu");

  XtVaSetValues(methodMenu,
		XmNradioBehavior, True,
		NULL);

  CreateToggleButton(methodMenu, "NoRadianceButton",
		     (!Radiance ? TRUE : FALSE),
		     SetRadianceMethodCallback, (XtPointer)NULL);

  ForAllRadianceMethods(method) {
    CreateToggleButton(methodMenu, method->buttonName, 
		       (method == Radiance ? TRUE : FALSE),
		       SetRadianceMethodCallback, (XtPointer)method);
  } EndForAll;
}

/* ++++++++++++++++++++++++ Radiance Control Panels ++++++++++++++++++ */
static Widget controlPanelParent;	/* needed for updating control panels */

static void CreateRadianceControlPanels(Widget parent)
{
  controlPanelParent = parent;

  ForAllRadianceMethods(method) {
    method->CreateControlPanel((void *)parent);
  } EndForAll;
}

/* ++++++++++++++++++++++++ Radiance Run/Stop button ++++++++++++++++++ */
static int radiance_running;
int interrupt_radiance;
void UpdateRadianceStats(void);

/* Does one step with the current radiance method. Returns TRUE
 * when the computations need to be interrupted or are converged. */
int DoRadianceOneStep(void)
{
  int done;

  renderopts.render_raytraced_image = FALSE;
  if (!World || !Radiance)
    return TRUE;

  CanvasPushMode(CANVASMODE_WORKING);
  done = Radiance->DoStep();
  CanvasPullMode();

  UpdateRadianceStats();
  RenderNewDisplayList();
  RenderScene();

  return done;
}

/* invoked when the user presses the run/stop button in the radiance menu */
static void RadianceRunStopCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  if (radiance_running)
    /* sometime in future, a Radiance-INterrupt method will be introduced that will
     * enable computation to be interrupted in the middle of an iteration step. */
    interrupt_radiance = TRUE;

  else {
    int done;

    if (!Radiance)
      Error(NULL, "Specify a radiance method first");

    radiance_running = TRUE;
    interrupt_radiance = FALSE;

    ProcessWaitingEvents();

    done = FALSE;
    while (!interrupt_radiance && !done) {
      done = DoRadianceOneStep();
      ProcessWaitingEvents();
    }

    radiance_running = FALSE;
    interrupt_radiance = FALSE;
  }
}

static void RadianceOneIterationCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  if (Radiance) {
    interrupt_radiance = FALSE;
    radiance_running = TRUE;

    DoRadianceOneStep();

    interrupt_radiance = FALSE;
    radiance_running = FALSE;
  } else
    Error(NULL, "Specify a radiance method first");
}

/* ++++++++++++++++++++++++ Radiance Control Dialog ++++++++++++++++++ */
static void RadianceControlCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  if (Radiance) {
    if (Radiance->UpdateControlPanel) 
      Radiance->UpdateControlPanel(controlPanelParent);
    Radiance->ShowControlPanel();
  } else
    Error(NULL, "Specify a radiance method first");
}

/* ++++++++++++++++++++++++ Radiance Statistics Dialog ++++++++++++++++++ */
/* The label widget used to show statistics information */
static Widget radianceStatsMessage = (Widget)NULL;

/* updates the radiance statstics */
void UpdateRadianceStats(void)
{
  char *message;

  if (!Radiance || !(message=Radiance->GetStats())) 
    message = "No statistics information available";

  SetLabelString(radianceStatsMessage, message);
}

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

/* 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 CreateRadianceStatsDialog(Widget parent, char *name)
{
  Widget statsBox = CreateDialog(parent, name);

  /* create a label widget inside the statsBox to show the statistics information. */
  radianceStatsMessage = CreateLabel(statsBox, "radianceStatsMessage");

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

  /* update and dismiss button are created automatically since a label string
   * is defined for them in the application resources file. */
  XtAddCallback(statsBox, XmNokCallback, UpdateRadianceStatsCallback, (XtPointer)NULL);
  XtAddCallback(statsBox, XmNcancelCallback, DismissStatsCallback, (XtPointer)NULL);

  return statsBox;
}

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

  UpdateRadianceStats();
  XtManageChild(statsBox);
}

/* ++++++++++++++++++++++++ Radiance Main Menu ++++++++++++++++++ */
void CreateRadianceMenu(Widget menuBar)
{
  Widget radianceMenu, radianceControlButton;

  radianceMenu = CreateSubMenu(menuBar, "radianceButton", "radianceMenu");

  CreateRadianceMethodMenu(radianceMenu);  
  radianceControlButton = CreatePushButton(radianceMenu, "radianceControlButton", RadianceControlCallback, (XtPointer)NULL);
  CreateRadianceControlPanels(radianceControlButton);
  CreateSeparator(radianceMenu, "radianceSeparator");

  CreatePushButton(radianceMenu, "radianceOneIterationButton", RadianceOneIterationCallback, (XtPointer)NULL);
  CreatePushButton(radianceMenu, "radianceRunStopButton", RadianceRunStopCallback, (XtPointer)NULL);
  radiance_running = FALSE;
  CreateSeparator(radianceMenu, "radianceSeparator");

  CreateCascadeDialog(radianceMenu, "statsButton", CreateRadianceStatsDialog, "statsBox", ShowRadianceStats, NULL);
}
