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

  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 vtkSplineSurface2DWidget - 3D widget for manipulating the intersection of 
//  a spline surface patch with a plane.
// .SECTION Description
//
// This class was created as a variation of the vtkSplineSurfaceWidget.  The
// purpose of this class is to present the intersection of a SplineSurface with
// a plane. In particular for display in orthogonal 2D windows like the ones
// used in VolView.
//

// .SECTION See Also
// vtkSplineSurfaceWidget vtkCut vtkPlane


#ifndef __vtkSplineSurface2DWidget_h
#define __vtkSplineSurface2DWidget_h

#include "vtk3DWidget.h"

#include <vector> // used for keeping track of the SplineSurfaces

class vtkActor;
class vtkCellPicker;
class vtkPoints;
class vtkPolyData;
class vtkPolyDataMapper;
class vtkProp;
class vtkProperty;
class vtkCylinderSource;
class vtkSplineSurfaceWidget;
class vtkTransform;
class vtkCutter;
class vtkPlane;


class VTK_EXPORT vtkSplineSurface2DWidget : public vtk3DWidget
{
public:
  // Description:
  // Instantiate the object.
  static vtkSplineSurface2DWidget *New();

  vtkTypeRevisionMacro(vtkSplineSurface2DWidget,vtk3DWidget);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description:
  // Methods that satisfy the superclass' API.
  virtual void SetEnabled(int);
  virtual void PlaceWidget(double bounds[6]);
  void PlaceWidget()
    {this->Superclass::PlaceWidget();}
  void PlaceWidget(double xmin, double xmax, double ymin, double ymax, 
                   double zmin, double zmax)
    {this->Superclass::PlaceWidget(xmin,xmax,ymin,ymax,zmin,zmax);}

  // Description:
  // Set/Get the handle properties (the little balls are the handles). The
  // properties of the handles when selected and normal can be manipulated.
  virtual void SetHandleProperty(vtkProperty*);
  vtkGetObjectMacro(HandleProperty, vtkProperty);
  virtual void SetSelectedHandleProperty(vtkProperty*);
  vtkGetObjectMacro(SelectedHandleProperty, vtkProperty);

  // Description:
  // Set/Get the line properties. The properties of the line when selected
  // and unselected can be manipulated.
  virtual void SetSurfaceProperty(vtkProperty*);
  vtkGetObjectMacro(SurfaceProperty, vtkProperty);
  virtual void SetSelectedSurfaceProperty(vtkProperty*);
  vtkGetObjectMacro(SelectedSurfaceProperty, vtkProperty);

  // Description:
  // Get the Visibility property of the surface actor
  virtual int GetSurfaceVisibility();
  
  // Description:
  // Set/Get the flag indicating whether the widget is used in Remote mode or
  // not. In this mode, whenever a handle is modified, instead of recomputing
  // the surface directly with the BuildRepresentation() method, the spline
  // invokes an event. Another class in the application must listen to those
  // events and invoke the local BuildRepresentation() method in all the
  // remotely controlled splines. If the controlling class does not invoke the
  // BuildRepresentation() method in this spline, then its state will be
  // inconsistent. This may be risky but seems to be better that having to keep
  // track of what changes actually occurred and figure out whether the spline
  // surface should be  recomputed or not.
  vtkSetMacro(RemoteMode,int);
  vtkGetMacro(RemoteMode,int);

  // Description:
  // Set/Get the associated vtkSplineSurfaceWidget
  virtual void SetSplineSurfaceWidget( vtkSplineSurfaceWidget * spline );
  virtual vtkSplineSurfaceWidget * GetSplineSurfaceWidget();

  // Description:
  // Get the representation of the surface in the form of a vtkPolyData.
  virtual vtkPolyData * GetSurfaceData();

  // Description:
  // Set the normal of the image plane
  // Set the origin of the image plane
  void SetNormal( double normal[3] );
  void SetOrigin( double origin[3] );

  // Description:
  // Events. 
  //BTX
  enum
  {
    SplineSurfaceHandlePositionChangedEvent = 10000,
    SplineSurfaceHandleChangedEvent,
    SplineSurface2DHandlePositionChangedEvent,
    SplineSurface2DHandleChangedEvent,
    SplineSurfaceNumberOfHandlesChangedEvent
  };
  //ETX

protected:
  vtkSplineSurface2DWidget();
  ~vtkSplineSurface2DWidget();

//BTX - manage the state of the widget
  int State;
  enum WidgetState
  {
    Start=0,
    Moving,
    Scaling,
    Spinning,
    Outside,
    ApplyingForce
  };
//ETX

  //handles the events
  static void ProcessEvents(vtkObject* object,
                            unsigned long event,
                            void* clientdata,
                            void* calldata);

  // ProcessEvents() dispatches to these methods.
  void OnLeftButtonDown();
  void OnLeftButtonUp();
  void OnMiddleButtonDown();
  void OnMiddleButtonUp();
  void OnRightButtonDown();
  void OnRightButtonUp();
  void OnMouseMove();
  void OnStartRender();

  // Associated vtkSplineSurfaceWidget
  vtkSplineSurfaceWidget * Spline;

  // The line segments
  vtkActor          *SurfaceActor;
  vtkPolyDataMapper *SurfaceMapper;
  void HighlightSurface(int highlight);

  // Glyphs representing hot spots (e.g., handles)
//BTX
  typedef vtkstd::vector<vtkActor *> ActorsArrayType;
  ActorsArrayType Handle;
//ETX

  vtkPolyDataMapper  *HandleMapper;
  vtkCylinderSource  *HandleGeometry;
  void Initialize();
  int  HighlightHandle(vtkProp *prop); //returns handle index or -1 on fail

  // to be called when handles change in number or position.
  void UpdateHandlesFromSpline(); 
  void BuildRepresentation();

  // Do the picking
  vtkCellPicker *HandlePicker;
  vtkCellPicker *SurfacePicker;
  vtkActor *CurrentHandle;
  int CurrentHandleIndex;

  // Methods to manipulate the spline.
  void MovePoint(double *p1, double *p2);
  void Scale(double *p1, double *p2, int X, int Y);
  void Translate(double *p1, double *p2);
  void Spin(double *p1, double *p2, double *vpn);
  void ApplyForce(double *p1, double *p2);

  // Transform the control points (used for spinning)
  vtkTransform *Transform;

  // Properties used to control the appearance of selected objects and
  // the manipulator in general.
  vtkProperty *HandleProperty;
  vtkProperty *SelectedHandleProperty;
  vtkProperty *SurfaceProperty;
  vtkProperty *SelectedSurfaceProperty;
  void CreateDefaultProperties();

  // For efficient spinning
  double Centroid[3];
  void CalculateCentroid();

  // Flag indicating wheter the spline is being used in remote mode.   
  int RemoteMode;

  // Small pipeline for cutting the Spline Surface with the image plane
  vtkCutter                  *CutFilter;
  vtkPlane                   *ImplicitPlane;

private:
  vtkSplineSurface2DWidget(const vtkSplineSurface2DWidget&);  //Not implemented
  void operator=(const vtkSplineSurface2DWidget&);  //Not implemented
};

#endif
