//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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.
//=========================================================================
#ifndef vtk_aeva_ext_vtkProportionalEditElements_h
#define vtk_aeva_ext_vtkProportionalEditElements_h

#include "vtk/aeva/ext/AEVAExtModule.h"
#include "vtkPolyDataAlgorithm.h"

#include "vtkCell.h" // Needed for VTK_CELL_SIZE

class vtkSphereSource;
class vtkTubeFilter;

/**
 * @class   vtkProportionalEditElements
 * @brief   Generate polygonal elements of the vtkProportionalEditRepresentation
 *
 * vtkProportionalEditElements creates the geometry necessary for the
 * vtkProportionalEditRepresentation of the vtkProportionalEditWidget
 */
class AEVAEXT_EXPORT vtkProportionalEditElements : public vtkPolyDataAlgorithm
{
public:
  vtkTypeMacro(vtkProportionalEditElements, vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  vtkProportionalEditElements(const vtkProportionalEditElements&) = delete;
  vtkProportionalEditElements& operator=(const vtkProportionalEditElements&) = delete;

  /// An enum indexing data present at each output.
  enum OutputPorts
  {
    AnchorVertex = 0,   //!< A single vertex at the anchor.
    DisplacementVertex, //!< A single vertex at the end of the displacement vector.
    ProjectionVertex,   //!< A single vertex at the end of the cylindrical influence region.
    Axis,               //!< Line from the anchor to the displacemnt-point.
    Sphere,             //!< Sphere representing the influence radius
    Cylinder,           //!< Cylinder representing the influence region under projection mode.
    NumberOfOutputs
  };

  /**
   * Construct with default parameters.
   */
  static vtkProportionalEditElements* New();

  //@{
  /**
   * Set/get the radius at the bottom of the cone.
   *
   * It must be non-negative.
   * It may be 0.
   */
  vtkSetClampMacro(InfluenceRadius, double, 0.0, VTK_DOUBLE_MAX);
  vtkGetMacro(InfluenceRadius, double);
  //@}

  //@{
  /**
   * Set/get the anchor point.
   * The default is 0,0,0.
   */
  vtkSetVector3Macro(AnchorPoint, double);
  vtkGetVectorMacro(AnchorPoint, double, 3);
  //@}

  //@{
  /**
   * Set/get the displacement point.
   * The default is 0,0,1.
   */
  vtkSetVector3Macro(DisplacementPoint, double);
  vtkGetVectorMacro(DisplacementPoint, double, 3);
  //@}

  //@{
  /**
   * Set/get the projection point.
   * The default is 0,1,0.
   */
  vtkSetVector3Macro(ProjectionPoint, double);
  vtkGetVectorMacro(ProjectionPoint, double, 3);
  //@}

  //@{
  /**
   * Set/get the number of facets used to represent the sphere or cylinder.
   *
   * This defaults to 16 and has a minimum of 3.
   */
  vtkSetClampMacro(Resolution, int, 3, VTK_CELL_SIZE);
  vtkGetMacro(Resolution, int);
  //@}

  //@{
  /**
   * Set/get the desired precision for the output points.
   * vtkAlgorithm::SINGLE_PRECISION - Output single-precision floating point.
   * vtkAlgorithm::DOUBLE_PRECISION - Output double-precision floating point.
   */
  vtkSetMacro(OutputPointsPrecision, int);
  vtkGetMacro(OutputPointsPrecision, int);
  //@}

protected:
  vtkProportionalEditElements(int res = 16);
  ~vtkProportionalEditElements() override;

  // int RequestInformation(vtkInformation* , vtkInformationVector** , vtkInformationVector* ) override;
  int RequestData(vtkInformation* request,
    vtkInformationVector** inputVector,
    vtkInformationVector* outputVector) override;

  double AnchorPoint[3];
  double InfluenceRadius{ 1.5 };
  double DisplacementPoint[3];
  double ProjectionPoint[3];
  int Resolution;
  int OutputPointsPrecision{ SINGLE_PRECISION };

  vtkNew<vtkSphereSource> SphereSrc;
  vtkNew<vtkTubeFilter> CylinderSrc;
};

#endif
