/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkVVHandleWidget.h"
#include "vtkObjectFactory.h"
#include "vtkCallbackCommand.h"
#include "vtkWidgetRepresentation.h"
#include "vtkWidgetEventTranslator.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkImageActorPointHandleRepresentation3D.h"
#include "vtkEvent.h"
#include "vtkWidgetEvent.h"
#include "vtkImageData.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include "vtkImageActor.h"
#include "vtkProperty.h"

#include "vtkVVSelectionFrame.h"
#include "vtkVVDataItemVolume.h"
#include "vtkVVApplication.h"
#include "vtkVVSelectionFrameLayoutManager.h"
#include "vtkVVWindow.h"
#include "vtkKWVolumeWidget.h"
#include "vtkKW2DRenderWidget.h"
#include <vtkstd/set>
#include <vtkstd/map>

#ifndef max
#define max(x,y) ((x>y) ? (x) : (y))
#endif

vtkStandardNewMacro(vtkVVHandleWidget);
vtkCxxRevisionMacro(vtkVVHandleWidget, "$Revision: 1.16 $");

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLVVHandleWidgetReader.h"
#include "XML/vtkXMLVVHandleWidgetWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkVVHandleWidget, vtkXMLVVHandleWidgetReader, vtkXMLVVHandleWidgetWriter);

//----------------------------------------------------------------------
class vtkVVHandleWidgetCommand : public vtkCommand
{
public:
  static vtkVVHandleWidgetCommand *New(vtkVVHandleWidget *w)
    {
    vtkVVHandleWidgetCommand *c = new vtkVVHandleWidgetCommand;
    c->Widget = w;
    return c;
    }

  vtkVVHandleWidgetCommand()
    {
    this->Widget = NULL;
    }

  virtual void Execute( vtkObject *caller, unsigned long eid, void * )
    {
    if (!this->Widget)
      {
      return;
      }
    vtkVVHandleWidget *callerWidget = vtkVVHandleWidget::SafeDownCast( caller );
    vtkHandleRepresentation *callerRep = 
      vtkHandleRepresentation::SafeDownCast(callerWidget->GetRepresentation());
    vtkHandleRepresentation *rep = 
      vtkHandleRepresentation::SafeDownCast(this->Widget->GetRepresentation());
    vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(
          this->Widget->GetSelectionFrame()->GetRenderWidget());

    // If we finished placing/interacting with the active seed, set that 
    // position on all the passive seeds. If we just placed the active seed
    // for the first time, enable all the passive seeds making them visible.
    if (eid == vtkCommand::PlacePointEvent || 
        eid == vtkCommand::InteractionEvent ||
        eid == vtkCommand::EndInteractionEvent)
      {
      double seedWorldPos[3], oldWorldPos[3];
      rep->GetWorldPosition(oldWorldPos);
      callerRep->GetWorldPosition(seedWorldPos);
      rep->SetWorldPosition( seedWorldPos );

      // Render if either the seed location has changed or it has been placed
      // for the first time.
      bool needToRender = (seedWorldPos[0]-oldWorldPos[0] != 0.0 || 
                           seedWorldPos[1]-oldWorldPos[1] != 0.0 || 
                           seedWorldPos[2]-oldWorldPos[2] != 0.0);

      if (eid == vtkCommand::PlacePointEvent)
        {
        // Seed has been placed for the first time.
        needToRender = true;
        this->Widget->EnabledOn(); // enable all the slaves.

        // the widget has been placed. Take it out of the undefined state.
        this->Widget->SetWidgetState( vtkHandleWidget::Start ); 
        
        // Jump to all the slices that show the handle widget
        this->Widget->Show();
        }

      // For a volume widget, we will not render during interaction in another
      // view. We will render only at the end of the interaction, for speed.
      if (vw)
        {
        needToRender = (eid != vtkCommand::InteractionEvent);
        }

      // Render in response to changes.
      // First check if the selection frame displaying the widget is visible.
      // If it isn't there is no need to render.
      vtkVVDataItemVolume * data_item_volume = 
        vtkVVDataItemVolume::SafeDownCast(
          this->Widget->GetSelectionFrame()->GetDataItem());
      vtkKWApplication *app = data_item_volume->GetApplication();

      // Should really check which window has the dataitem
      vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(0) );
      bool selFrameVisible = win->GetDataSetWidgetLayoutManager()->
        GetWidgetVisibility( this->Widget->GetSelectionFrame() ) ? true : false;
      
      if (needToRender && selFrameVisible)
        {
        this->Widget->Render();
        }
      }
    }

  vtkVVHandleWidget *Widget;
};


//----------------------------------------------------------------------
vtkVVHandleWidget::vtkVVHandleWidget()
{
  this->WidgetState        = -1; // Undefined
  this->ID                 = -1; // Unassigned
  this->SelectionFrame     = NULL;
  this->HandleCommand      = vtkVVHandleWidgetCommand::New(this);
  this->PlaceInteractively = 0;
  this->Description        = "Handle";

  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
                                          vtkWidgetEvent::Select,
                                          this, vtkVVHandleWidget::AddPointAction);
}

//----------------------------------------------------------------------
vtkVVHandleWidget::~vtkVVHandleWidget()
{
  this->HandleCommand->Widget = NULL;
  this->HandleCommand->Delete();
  this->HandleCommand = NULL;
  this->ID = -1;
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::WidgetIsDefined()
{
  this->WidgetState = vtkHandleWidget::Start; // we are now defined.
  this->ReleaseFocus();
  this->GetRepresentation()->BuildRepresentation(); // update this->Handle
  this->SetEnabled(this->GetEnabled()); // show/hide the handles properly
  this->Render();
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::IsWidgetDefined()
{
  return this->WidgetState != -1;
}

//-------------------------------------------------------------------------
void vtkVVHandleWidget::AddPointAction(vtkAbstractWidget *w)
{
  vtkVVHandleWidget *self = reinterpret_cast<vtkVVHandleWidget*>(w);

  if ( self->GetWidgetState() != -1)
    {
    // We have already been defined. Let the superclass handle everything else
    vtkHandleWidget::SelectAction(w);
    return;
    }

  // A master widget can be placed interactively by clicking with the mouse on
  // the renderwindow
  if (!self->PlaceInteractively)
    {
    return;
    }

  // At the current location, we will place this seed.
  int X = self->Interactor->GetEventPosition()[0];
  int Y = self->Interactor->GetEventPosition()[1];

  self->WidgetState = vtkHandleWidget::Start; // we are now defined.

  double e[3]; 
  e[0] = static_cast<double>(X);
  e[1] = static_cast<double>(Y);
  e[2] = 0.0;

  vtkHandleRepresentation *rep =
    reinterpret_cast<vtkHandleRepresentation*>(self->WidgetRep);

  // if the handle representation is constrained, check to see if
  // the position follows the constraint.
  if ( !rep->CheckConstraint( self->GetCurrentRenderer(), e ) )
    {
    return;
    }

  // Place the handle at the position given by the mouse cursor.
  rep->SetDisplayPosition(e);

  self->InvokeEvent(vtkCommand::PlacePointEvent);
  self->InvokeEvent(vtkCommand::EndInteractionEvent);

  self->EventCallbackCommand->SetAbortFlag(1);
  self->Render();
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetID( int id )
{
  if (id == this->ID)
    {
    return;
    }

  this->ID = id;
  if (this->SelectionFrame)
    {
    this->Sync();
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetDescription( const char *s )
{
  if (this->Description == s)
    {
    return;
    }

  this->Description = s;

  const int nHandlesInGroup = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < nHandlesInGroup; i++)
    {
    vtkVVHandleWidget *w = this->GetNthHandleInGroup(i);
    w->Description = s;
    }  
}

//----------------------------------------------------------------------
const char * vtkVVHandleWidget::GetDescription()
{
  return this->Description.c_str();
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::Sync()
{
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast(
        this->SelectionFrame->GetDataItem());
  vtkKWApplication *app = data_item_volume->GetApplication();
  int nb_windows = app->GetNumberOfWindows();
  for (int i = 0; i < nb_windows; i++)
    {
    vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(i) );
    vtkVVSelectionFrameLayoutManager *layout_mgr = 
                  win->GetDataSetWidgetLayoutManager();
    int nSelectionFrames = layout_mgr->
      GetNumberOfWidgetsWithGroup(data_item_volume->GetName());
    for (int j = 0; j < nSelectionFrames; j++)
      {
      if (vtkVVSelectionFrame *sel_frame = 
          vtkVVSelectionFrame::SafeDownCast(
            layout_mgr->GetNthWidgetWithGroup( 
              j, data_item_volume->GetName() )))
        {

        if (sel_frame && sel_frame != this->SelectionFrame)
          {
          int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
          for (int k = 0; k < nb_interactors; k++)
            {
            vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
                sel_frame->GetNthInteractorWidget(k));
            if (hw && hw->GetID() == this->ID)
              {
              // This handle represents the same seed point on another view.
              // Both should observe each other for changes.

              if (!hw->HasObserver( 
                    vtkCommand::InteractionEvent, this->HandleCommand ))
                {
                if (hw->GetPlaceInteractively() && !this->GetPlaceInteractively())
                  {
                  // The widget which is enabled is the master seed, which 
                  // when placed, will cause the other seeds to appear at the
                  // same location in their respective views.
                  hw->AddObserver(vtkCommand::PlacePointEvent, this->HandleCommand);
                  }
                hw->AddObserver(vtkCommand::InteractionEvent, this->HandleCommand);
                hw->AddObserver(vtkCommand::EndInteractionEvent, this->HandleCommand);
                }

              if (!this->HasObserver(
                    vtkCommand::InteractionEvent, hw->HandleCommand ))
                {
                if (!hw->GetPlaceInteractively() && this->GetPlaceInteractively())
                  {
                  // The widget which is enabled is the master seed, which 
                  // when placed, will cause the other seeds to appear at the
                  // same location in their respective views.
                  this->AddObserver(vtkCommand::PlacePointEvent, hw->HandleCommand);
                  }
                this->AddObserver(vtkCommand::InteractionEvent, hw->HandleCommand);
                this->AddObserver(vtkCommand::EndInteractionEvent, hw->HandleCommand);
                }
              }
            } // end for each handle in the selection frame
          } 
        }
      } // end for each selection frame
    } // end for each window
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetNumberOfHandlesInGroup()
{
  if (this->ID == -1 || this->SelectionFrame == NULL)
    {
    return 0;
    }

  int n = 0;
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast(
        this->SelectionFrame->GetDataItem());
  vtkKWApplication *app = data_item_volume->GetApplication();
  int nb_windows = app->GetNumberOfWindows();
  for (int i = 0; i < nb_windows; i++)
    {
    vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(i) );
    vtkVVSelectionFrameLayoutManager *layout_mgr = 
                  win->GetDataSetWidgetLayoutManager();
    int nSelectionFrames = layout_mgr->
      GetNumberOfWidgetsWithGroup(data_item_volume->GetName());
    for (int j = 0; j < nSelectionFrames; j++)
      {
      if (vtkVVSelectionFrame *sel_frame = 
          vtkVVSelectionFrame::SafeDownCast(
            layout_mgr->GetNthWidgetWithGroup( 
              j, data_item_volume->GetName() )))
        {

        int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
        for (int k = 0; k < nb_interactors; k++)
          {
          vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
              sel_frame->GetNthInteractorWidget(k));
          if (hw && hw->GetID() == this->ID)
            {
            n++;
            }
          }
        }
      }
    }

  return n;
}

//----------------------------------------------------------------------
vtkVVHandleWidget * vtkVVHandleWidget::GetNthHandleInGroup( int num )
{
  if (this->ID == -1 || this->SelectionFrame == NULL)
    {
    return NULL;
    }

  int n = 0;
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast(
        this->SelectionFrame->GetDataItem());
  vtkKWApplication *app = data_item_volume->GetApplication();
  int nb_windows = app->GetNumberOfWindows();
  for (int i = 0; i < nb_windows; i++)
    {
    vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(i) );
    vtkVVSelectionFrameLayoutManager *layout_mgr = 
                  win->GetDataSetWidgetLayoutManager();
    int nSelectionFrames = layout_mgr->
      GetNumberOfWidgetsWithGroup(data_item_volume->GetName());
    for (int j = 0; j < nSelectionFrames; j++)
      {
      if (vtkVVSelectionFrame *sel_frame = 
          vtkVVSelectionFrame::SafeDownCast(
            layout_mgr->GetNthWidgetWithGroup( 
              j, data_item_volume->GetName() )))
        {

        int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
        for (int k = 0; k < nb_interactors; k++)
          {
          vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
              sel_frame->GetNthInteractorWidget(k));
          if (hw && hw->GetID() == this->ID)
            {
            if (n == num)
              {
              return hw;
              }
            n++;
            }
          }
        }
      }
    }

  return NULL;
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetNumberOfHandlesInDataItem(vtkVVDataItem *data_item)
{
  vtkstd::set< int > ids;
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast( data_item );
  vtkKWApplication *app = data_item_volume->GetApplication();
  int nb_windows = app->GetNumberOfWindows();
  for (int i = 0; i < nb_windows; i++)
    {
    vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(i) );
    vtkVVSelectionFrameLayoutManager *layout_mgr = 
                  win->GetDataSetWidgetLayoutManager();
    int nSelectionFrames = layout_mgr->
      GetNumberOfWidgetsWithGroup(data_item_volume->GetName());
    for (int j = 0; j < nSelectionFrames; j++)
      {
      if (vtkVVSelectionFrame *sel_frame = 
          vtkVVSelectionFrame::SafeDownCast(
            layout_mgr->GetNthWidgetWithGroup( 
              j, data_item_volume->GetName() )))
        {

        int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
        for (int k = 0; k < nb_interactors; k++)
          {
          vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
              sel_frame->GetNthInteractorWidget(k));
          if (hw && hw->IsWidgetDefined())
            {
            ids.insert(hw->GetID());
            } // if widget is a handle widget
          } // loop over each widget in selection frame
        } 
      } // loop over each selection frame in this volume
    } // loop over each windown in the scene

  // return number of handle groups. 
  return (int)ids.size();
}

//----------------------------------------------------------------------
vtkVVHandleWidget * 
vtkVVHandleWidget::GetNthHandleInDataItem(vtkVVDataItem *data_item, int n)
{
  typedef vtkstd::map< int, vtkVVHandleWidget * > HandleIdsToHandleMap;
  HandleIdsToHandleMap ids;
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast( data_item );
  vtkKWApplication *app = data_item_volume->GetApplication();
  int nb_windows = app->GetNumberOfWindows();
  for (int i = 0; i < nb_windows; i++)
    {
    vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(i) );
    vtkVVSelectionFrameLayoutManager *layout_mgr = 
                  win->GetDataSetWidgetLayoutManager();
    int nSelectionFrames = layout_mgr->
      GetNumberOfWidgetsWithGroup(data_item_volume->GetName());
    for (int j = 0; j < nSelectionFrames; j++)
      {
      if (vtkVVSelectionFrame *sel_frame = 
          vtkVVSelectionFrame::SafeDownCast(
            layout_mgr->GetNthWidgetWithGroup( 
              j, data_item_volume->GetName() )))
        {

        int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
        for (int k = 0; k < nb_interactors; k++)
          {
          vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
              sel_frame->GetNthInteractorWidget(k));
          if (hw && hw->IsWidgetDefined())
            {
            ids[hw->GetID()] = hw;
            } // if widget is a handle widget
          } // loop over each widget in selection frame
        } 
      } // loop over each selection frame in this volume
    } // loop over each windown in the scene

  // return number of handle groups. 
  if (ids.size() > (unsigned int)n)
    {
    HandleIdsToHandleMap::iterator it = ids.begin();
    for (int i = 0; i < n; i++, ++it);
    return it->second;
    }

  return NULL;
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetEnabled(int e)
{
  this->Superclass::SetEnabled(e);

  // Now enable all the other widgets in the group.
  const int nHandlesInGroup = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < nHandlesInGroup; i++)
    {
    vtkVVHandleWidget *w = this->GetNthHandleInGroup(i);
    if (w->GetEnabled() != e)
      {
      w->SetEnabled(e);
      }
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetProcessEvents(int e)
{
  this->Superclass::SetProcessEvents(e);

  // Now enable all the other widgets in the group.
  const int nHandlesInGroup = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < nHandlesInGroup; i++)
    {
    vtkVVHandleWidget *w = this->GetNthHandleInGroup(i);
    if (w->GetProcessEvents() != e)
      {
      w->SetProcessEvents(e);
      }
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetDisplayForAllSlices(int e)
{
  int need_render = 0;
  const int nHandlesInGroup = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < nHandlesInGroup; i++)
    {
    vtkImageActorPointHandleRepresentation3D *im_rep = 
      vtkImageActorPointHandleRepresentation3D::SafeDownCast(
        this->GetNthHandleInGroup(i)->GetRepresentation());
    if (im_rep && im_rep->GetDisplayForAllSlices() != e)
      {
      im_rep->SetDisplayForAllSlices(e);
      need_render++;
      }
    }
  if (need_render)
    {
    this->RenderAllWidgetsInGroup();
    }
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetDisplayForAllSlices()
{
  const int nHandlesInGroup = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < nHandlesInGroup; i++)
    {
    vtkImageActorPointHandleRepresentation3D *im_rep = 
      vtkImageActorPointHandleRepresentation3D::SafeDownCast(
        this->GetNthHandleInGroup(i)->GetRepresentation());
    if (im_rep)
      {
      return im_rep->GetDisplayForAllSlices();
      }
    }
  return 0;
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::GetWorldPosition(double worldPos[3])
{
  if (vtkHandleRepresentation *rep = 
      vtkHandleRepresentation::SafeDownCast(this->GetRepresentation()))
    {
    rep->GetWorldPosition(worldPos);
    }
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetPixelPosition(int ijk[3])
{
  double x[3];
  this->GetWorldPosition(x);
  vtkVVDataItemVolume *vol = vtkVVDataItemVolume::SafeDownCast(
                     this->SelectionFrame->GetDataItem());
  vtkImageData *image = vol->GetImageData();

  double origin[3], spacing[3];
  int extent[6];
  image->GetOrigin(origin);
  image->GetSpacing(spacing);
  image->GetExtent(extent);

  //  Compute the ijk location
  //
  for (int i=0; i<3; i++)
    {
    double d = x[i] - origin[i];
    double doubleLoc = d / spacing[i];

    // Floor for negative indexes.
    ijk[i] = static_cast<int>(doubleLoc+0.5);
    
    if ( ijk[i] < extent[i*2] || ijk[i] > extent[i*2+1] )
      {
      return 0;
      }

    // We now need to subtract the lower extent to shift to
    // the correct location in the image (mapping {extent[0],
    // extent[2], extent[4]) to (0, 0, 0)
    ijk[i] -= extent[i*2];
    }

  return 1;
}

//----------------------------------------------------------------------
vtkstd::string vtkVVHandleWidget::GetWorldPositionAsString()
{
  double location[3];
  this->GetWorldPosition(location);
  char locationStr[1024];
  vtkVVDataItemVolume *vol = vtkVVDataItemVolume::SafeDownCast(
                     this->SelectionFrame->GetDataItem());
  const char *distance_units = 
    vol->GetDistanceUnits() ? vol->GetDistanceUnits() : "unknown units";
  sprintf(locationStr, "(%.5g, %.5g, %.5g) (%s)",
      location[0], location[1], location[2], distance_units);  
  vtkstd::string s = locationStr;
  return s;
}

//----------------------------------------------------------------------
vtkstd::string vtkVVHandleWidget::GetPixelPositionAsString()
{
  int location[3];
  vtkstd::string s = "Outside volume";
  if (this->GetPixelPosition(location))
    {
    char locationStr[1024];
    sprintf(locationStr, "(%d, %d, %d)",
        location[0], location[1], location[2]);  
    s = locationStr;
    }

  return s;
}

//----------------------------------------------------------------------
vtkstd::string vtkVVHandleWidget::GetPixelValueAsString()
{
  vtkstd::string s = "Outside volume";
  int pos[3];
  if (this->GetPixelPosition(pos))
    {
    vtkVVDataItemVolume *vol = vtkVVDataItemVolume::SafeDownCast(
                       this->SelectionFrame->GetDataItem());
    vtkImageData *image = vol->GetImageData(); 
    const int numComps = image->GetNumberOfScalarComponents();
    double *vals = new double[numComps];

    for (int idx = 0; idx < numComps;  idx++) 
      {
      vals[idx] =
        image->GetScalarComponentAsDouble(pos[0], pos[1], pos[2], idx);
      }

    char valueStr[1024];
    const char *pattern;
    int scalar_type = image->GetScalarType();
    int double_type = (scalar_type == VTK_FLOAT || scalar_type == VTK_DOUBLE);
    pattern = (double_type ? "%.8g (%s)" : "%.0f (%s)");
    for (int i = 0; i < numComps; i++)
      {
      const char *scalar_units = 
        vol->GetScalarUnits(i) ? vol->GetScalarUnits(i) : "unknown units";
      sprintf(valueStr, pattern, vals[i], scalar_units);
      }

    s = valueStr;
    }
 
  return s;
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetSlice( vtkVVSelectionFrame *sel_frame, 
                                 int sliceOrientation )
{
  int nb_interactors = sel_frame->GetNumberOfInteractorWidgets();
  for (int k = 0; k < nb_interactors; k++)
    {
    vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(
        sel_frame->GetNthInteractorWidget(k));
    if (hw && hw->GetID() == this->ID)
      {
      vtkPointHandleRepresentation3D *rep = 
        vtkPointHandleRepresentation3D::SafeDownCast(
              hw->GetRepresentation());
      
      if (rep && this->IsWidgetDefined())
        {
        int pos[3];
        double worldPos[3], spacing[3], origin[3];
        this->GetWorldPosition(worldPos);

        vtkVVDataItemVolume *vol = vtkVVDataItemVolume::SafeDownCast(
                         this->SelectionFrame->GetDataItem());
        vtkImageData *image = vol->GetImageData();
        image->GetSpacing(spacing);
        image->GetOrigin(origin);

        if (rep->GetRenderer()->GetActiveCamera())
          {
          double directionOfProjection = 
            rep->GetRenderer()->GetActiveCamera()->
              GetDirectionOfProjection()[sliceOrientation];
          double x = (worldPos[sliceOrientation] - 
            origin[sliceOrientation]) / spacing[sliceOrientation];

          // Ideally simply saying :
          //   x = (directionOfProjection < 0 ? floor(x) : ceil(x));
          // should work. However there seems to be a precision issue with 
          // ceil / floor. For instance ceil(55) = 56. Hence we resort to some
          // hacking below.. We check if x is nearly an integer, (within some 
          // tolerance measure). If so, we simply return the value "x". 
          // 
          const double tolerance = 0.001 * spacing[sliceOrientation];
          if (fabs(x- static_cast< double >(static_cast< int >(x))) < tolerance)
            {
            return x;
            }

          x = (directionOfProjection < 0 ? floor(x) : ceil(x));
          
          return (int)x;
          }

        pos[sliceOrientation] = (int)(((worldPos[sliceOrientation] - 
                origin[sliceOrientation]) / spacing[sliceOrientation]) + .5);

        // Return pixel position + 1 ? (pixel pos is 0 index based).
        return (pos[sliceOrientation]);
        }
      }
    }
  
  return -1;
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetSelectionFrame( vtkVVSelectionFrame * s )
{
  if (s == this->SelectionFrame)
    {
    return;
    }

  this->SelectionFrame = s;

  if (this->ID != -1)
    {
    this->Sync();
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::Show()
{
  vtkVVDataItemVolume * data_item_volume = 
    vtkVVDataItemVolume::SafeDownCast(
        this->SelectionFrame->GetDataItem());
  vtkKWApplication *app = data_item_volume->GetApplication();

  // Should really check which window has the dataitem
  vtkVVWindow *win = vtkVVWindow::SafeDownCast( app->GetNthWindow(0) );

  int nRenderWidgetsShowingThisSeed = 
    win->GetDataSetWidgetLayoutManager()->GetNumberOfWidgetsWithGroup(
      data_item_volume->GetName());

  for (int i = 0; i < nRenderWidgetsShowingThisSeed; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      win->GetDataSetWidgetLayoutManager()->GetNthWidgetWithGroup(
        i, data_item_volume->GetName()));
    if (sel_frame->HandleWidgetIsSupported())
      {
      if (vtkKW2DRenderWidget *rw2d = 
          vtkKW2DRenderWidget::SafeDownCast(sel_frame->GetRenderWidget()))
        {
        rw2d->SetSlice(this->GetSlice(sel_frame, rw2d->GetSliceOrientation()));
        }
      }
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetColor( double r, double g, double b )
{
  double rgb[3] = {r,g,b};
  this->SetColor(rgb);
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::SetColor( double rgb[3] )
{
  const int n = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < n; i++)
    {
    if (vtkVVHandleWidget *hw = this->GetNthHandleInGroup(i))
      {
      if (vtkPointHandleRepresentation3D *rep = 
          vtkPointHandleRepresentation3D::SafeDownCast(hw->GetRepresentation()))
        {
        rep->GetProperty()->SetColor(rgb);
        }
      }
    }
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::RenderAllWidgetsInGroup()
{
  const int n = this->GetNumberOfHandlesInGroup();
  for (int i = 0; i < n; i++)
    {
    if (vtkVVHandleWidget *hw = this->GetNthHandleInGroup(i))
      {
      hw->Render();
      }
    }
}

//----------------------------------------------------------------------
int vtkVVHandleWidget::GetNewUniqueID( vtkVVSelectionFrame * sel_frame )
{
  int id = -1, newId;
  const int nInteractors = sel_frame->GetNumberOfInteractorWidgets();
  for (int j = 0; j < nInteractors; j++)
    {
    if (vtkVVHandleWidget *hw = vtkVVHandleWidget::SafeDownCast(
             sel_frame->GetNthInteractorWidget(j)))
      {
      id = max(id, hw->GetID());
      }
    }
  newId = id + 1;
  return newId;
}

//----------------------------------------------------------------------
void vtkVVHandleWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

