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

  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.

=========================================================================*/
// .NAME vtkKW2DRenderWidget
// .SECTION Description

#ifndef __vtkKW2DRenderWidget_h
#define __vtkKW2DRenderWidget_h

#include "vtkKWRenderWidgetPro.h"
#include "XML/vtkXMLIOBaseMacros.h" // Needed for XML reader/writer macros

class vtkCamera;
class vtkImageData;
class vtkKWImageMapToWindowLevelColors;
class vtkKWInteractorStyle2DView;
class vtkKWScaleWithEntry;
class vtkSideAnnotation;

class VTK_EXPORT vtkKW2DRenderWidget : public vtkKWRenderWidgetPro
{
public:
  vtkTypeRevisionMacro(vtkKW2DRenderWidget, vtkKWRenderWidgetPro);
  void PrintSelf(ostream& os, vtkIndent indent);
  //BTX
  vtkKWGetXMLReaderWriterObjectsMacro();
  //ETX

  // Description:
  // Set/Get/Reset the window/level for those elements that support W/L
  virtual void ResetWindowLevel();
  vtkGetMacro(ResetWindowLevelForSelectedSliceOnly,int);
  vtkSetMacro(ResetWindowLevelForSelectedSliceOnly,int);
  vtkBooleanMacro(ResetWindowLevelForSelectedSliceOnly,int);

  // Description:
  // Reset the camera to display all the actors in the scene
  // Override the parent to take the slice orientation and type into account
  virtual void ResetCamera();

  // Description:
  // Set/Get to internal image map to window level colors
  virtual vtkKWImageMapToWindowLevelColors* GetImageMapToRGBA();
  virtual void SetImageMapToRGBA(vtkKWImageMapToWindowLevelColors *);

  // Description:
  // Event list
  //BTX
  enum
  {
    SideAnnotationVisibilityChangedEvent = 22000,
    SliceOrientationChangedEvent,
    UpdateDisplayExtentEvent
  };
  //ETX

  // Description:
  // Set/get the slice orientation
  //BTX
  enum
  {
    SLICE_ORIENTATION_YZ = 0, // Sagittal
    SLICE_ORIENTATION_XZ = 1, // Coronal
    SLICE_ORIENTATION_XY = 2  // Axial
  };
  //ETX
  vtkGetMacro(SliceOrientation, int);
  virtual void SetSliceOrientation(int orientation);
  virtual void SetSliceOrientationToXY()
    { this->SetSliceOrientation(vtkKW2DRenderWidget::SLICE_ORIENTATION_XY); };
  virtual void SetSliceOrientationToYZ()
    { this->SetSliceOrientation(vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ); };
  virtual void SetSliceOrientationToXZ()
    { this->SetSliceOrientation(vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ); };
  const char* GetSliceOrientationAsString();
  static const char* GetSliceOrientationAsMedicalOrientationString(int);
  static const char* GetSliceOrientationAsDefaultOrientationString(int);
  static int GetSliceOrientationFromMedicalOrientationString(const char *);
  static int GetSliceOrientationFromDefaultOrientationString(const char *);

  // Description:
  // Set/get the slice type
  //BTX
  enum
  {
    SLICE_TYPE_DEFAULT = 0,
    SLICE_TYPE_MEDICAL = 1,
    SLICE_TYPE_GENERIC = 2
  };
  //ETX
  vtkGetMacro(SliceType, int);
  virtual void SetSliceType(int type);
  virtual void SetSliceTypeToDefault()
    { this->SetSliceType(vtkKW2DRenderWidget::SLICE_TYPE_DEFAULT); };
  virtual void SetSliceTypeToMedical()
    { this->SetSliceType(vtkKW2DRenderWidget::SLICE_TYPE_MEDICAL); };
  virtual void SetSliceTypeToGeneric()
    { this->SetSliceType(vtkKW2DRenderWidget::SLICE_TYPE_GENERIC); };

  // Description:
  // Get the interactor style (if any)
  virtual vtkKWInteractorStyle2DView* GetInteractorStyle() { return 0; };

  // Description:
  // Get and control the side annotation. Turn SupportSideAnnotation
  // to off (on by default) if you do not care about side annotations for
  // this render widget. The Visibility flag toggles the visibility of the
  // side annotation. The SupportSideAnnotation flag overrides the
  // visibility flag.
  virtual int  GetSideAnnotationVisibility();
  virtual void SetSideAnnotationVisibility(int v);
  virtual void ToggleSideAnnotationVisibility();
  vtkBooleanMacro(SideAnnotationVisibility, int);
  virtual void SetSideAnnotationTexts(
    const char *minusx, const char *x, const char *minusy, const char *y);
  vtkGetObjectMacro(SideAnnotation, vtkSideAnnotation);
  virtual void SetSupportSideAnnotation(int);
  vtkGetMacro(SupportSideAnnotation, int);
  vtkBooleanMacro(SupportSideAnnotation, int);

  // Description:
  // 2D widgets Don't need overlay renderer so don't use it.
  virtual void AddOverlayViewProp(vtkProp *p) {this->AddViewProp(p);};

  // Description:
  // The ComputeVisiblePropBounds() method returns the bounds of the
  // visible props for a given renderer. Override the superclass
  // to use the bounds of the whole input volume, instead of the
  // bounds of the slice (image actor) in the renderer.
  virtual void ComputeVisiblePropBounds(int index, double bounds[6]);

  // Description:
  // Slice navigation
  virtual void SetSlice(int) {};
  virtual int  GetSlice();
  virtual int  GetSliceMin();
  virtual int  GetSliceMax();
  virtual void IncrementSlice();
  virtual void DecrementSlice();
  virtual void IncrementPage() {};
  virtual void DecrementPage() {};
  virtual void GoToFirstSlice();
  virtual void GoToLastSlice();
  virtual int GoToDefaultSlice();
  virtual int  IsSliceInRange(int slice);

  // Description:
  // Set/Get the fact that this widget can control the slice actually
  // displayed.
  virtual void SetHasSliceControl(int);
  vtkBooleanMacro(HasSliceControl,int);
  vtkGetMacro(HasSliceControl, int);

  // Description:
  // Set/get the interaction style.
  // This method can be used to control which main interaction style is in
  // effect (either Pan, Zoom or Window/Level). The corresponding action
  // is triggered by the left mouse button. If set to All, all actions
  // are mapped to as many buttons as possible.
  //BTX
  enum
  {
    INTERACTION_MODE_PAN = 0,
    INTERACTION_MODE_ZOOM,
    INTERACTION_MODE_WINDOWLEVEL,
    INTERACTION_MODE_ALL,
  };
  //ETX
  vtkGetMacro(InteractionMode, int);
  virtual void SetInteractionMode(int type);
  virtual void SetInteractionModeToPan()
    { this->SetInteractionMode(INTERACTION_MODE_PAN); };
  virtual void SetInteractionModeToZoom()
    { this->SetInteractionMode(INTERACTION_MODE_ZOOM); };
  virtual void SetInteractionModeToWindowLevel()
    { this->SetInteractionMode(INTERACTION_MODE_WINDOWLEVEL); };
  virtual void SetInteractionModeToAll()
    { this->SetInteractionMode(INTERACTION_MODE_ALL); };

  // Description:
  // Get the display/world extent of a given slice (use GetSlice() as first
  // parameter to retrieve the display extent of the current slice).
  virtual void GetSliceDisplayExtent(int slice, int extent[6]);
  virtual void GetSliceWorldExtent(int slice, double extent[6]);
  virtual int GetClosestSliceToWorldPosition(double pos[3]);

  // Description:
  // Callbacks. Internal use.
  virtual void SliceSelectedCallback(double value);
  virtual void ColorMappingCallback(int disp_ch, int use_op_mod);

  // Description:
  // Update the "enable" state of the object and its internal parts.
  // Depending on different Ivars (this->Enabled, the application's
  // Limited Edition Mode, etc.), the "enable" state of the object is updated
  // and propagated to its internal parts/subwidgets. This will, for example,
  // enable/disable parts of the widget UI, enable/disable the visibility
  // of 3D widgets, etc.
  virtual void UpdateEnableState();

  // Description:
  // Given mouse coordinate, compute world coordinate, eventually return
  // the id of the renderer if the widget supports multiple renderers
  // (see vtkKWRenderWidget::GetNthRenderer,
  // vtkKWRenderWidget::GetRendererIndex)
  virtual int ComputeWorldCoordinate(
    int x, int y, double *result, int *id = 0) = 0;

  // Description:
  // Get the internal slice scale
  vtkGetObjectMacro(SliceScale, vtkKWScaleWithEntry);

  // Description:
  // Set the co-ordinate system to RAS/LPS. Note that this assumes that the
  // data has been acquired appropriately. See vtkKWLoadWizard.
  // For RAS, +x is along R, +y along A, +z along S.
  //BTX
  enum
  {
    COORDINATE_SYSTEM_MEDICAL_RAS = 0,
    COORDINATE_SYSTEM_MEDICAL_LPS = 1 // Default
  };
  //ETX
  vtkGetMacro(CoordinateSystemMedical, int);
  virtual void SetCoordinateSystemMedical(int type);
  virtual void SetCoordinateSystemMedicalToRAS()
    { this->SetCoordinateSystemMedical(
      vtkKW2DRenderWidget::COORDINATE_SYSTEM_MEDICAL_RAS); };
  virtual void SetCoordinateSystemMedicalToLPS()
    { this->SetCoordinateSystemMedical(
      vtkKW2DRenderWidget::COORDINATE_SYSTEM_MEDICAL_LPS); };

  // Description:
  // Enable/Disable linear interpolation
  virtual void SetInterpolate(int state) = 0;
  virtual int  GetInterpolate() = 0;
  vtkBooleanMacro(Interpolate, int);
  virtual void ToggleInterpolate();
    
  // Description:
  // Update the color mapping parameters
  virtual void UpdateColorMapping();

protected:
  vtkKW2DRenderWidget();
  ~vtkKW2DRenderWidget();

  // Create the widget
  virtual void CreateWidget();

  // Description:
  // Connects the internal object together given the Input.
  // Returns 1 on success, 0 on error or to signal that it is safe to abort
  virtual int ConnectInternalPipeline();

  // Description:
  // Those methods are called automatically by UpdateAccordingToInput() if:
  // - InputBoundsHaveChanged(): the input bounds have changed
  // Returns 1 on success, 0 on error or to signal that it is safe to abort
  virtual int InputBoundsHaveChanged();

  // Description:
  // Update the display extent according to what part of the Input has to
  // be displayed. It is probably the right place to adjust/place the 3D
  // widget which position depends on the display extent.
  virtual void UpdateDisplayExtent() {};

  // Description:
  // Update the image map
  virtual void UpdateImageMap() {};

  // Description:
  // Update internal objects according to the orientation and type
  virtual void UpdateSliceOrientationAndType();

  // Description:
  // Update internal objects according to the current unit
  virtual void UpdateAccordingToUnits() {};

  // Description:
  // Update the slice scale range according to the orientation
  virtual void UpdateSliceScale();

  // Description:
  // Configure the event map
  virtual void ConfigureEventMap();

  // Description:
  // Connect ImageMapToRGBA to its input (can be overriden in subclasses)
  virtual void ConnectImageMapToRGBA();

  // Description:
  // Pack/repack the slice scale
  virtual void PackSliceScale();

  vtkSideAnnotation *SideAnnotation;
  int                SupportSideAnnotation;

  int SliceOrientation;
  int SliceType;
  int InteractionMode;
  int HasSliceControl;
  int ResetWindowLevelForSelectedSliceOnly;
  int CoordinateSystemMedical;

  vtkKWScaleWithEntry *SliceScale;

  // Description:
  // Populate the context menu
  virtual void PopulateContextMenuWithOptionEntries(vtkKWMenu*);
  virtual void PopulateContextMenuWithInteractionEntries(vtkKWMenu*);
  virtual void PopulateContextMenuWithAnnotationEntries(vtkKWMenu*);
  virtual void PopulateContextMenuWithColorEntries(vtkKWMenu*);

private:

  vtkKWImageMapToWindowLevelColors *ImageMapToRGBA;

  vtkKW2DRenderWidget(const vtkKW2DRenderWidget&);  // Not implemented
  void operator=(const vtkKW2DRenderWidget&);  // Not implemented
};

#endif
