//=========================================================================
//  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.
//=========================================================================
#include "smtk/session/aeva/plugin/pqProportionalEditPropertyWidget.h"
#include "smtk/extension/paraview/widgets/pqPointPickingVisibilityHelper.h"
#include "smtk/session/aeva/plugin/ui_pqProportionalEditPropertyWidget.h"

#include "pqCoreUtilities.h"
#include "pqPointPickingHelper.h"

#include "vtkSMNewWidgetRepresentationProxy.h"
#include "vtkSMProperty.h"
#include "vtkSMPropertyGroup.h"
#include "vtkSMPropertyHelper.h"

#include "vtkCommand.h"

class pqProportionalEditPropertyWidget::Internals
{
public:
  Ui::ProportionalEditPropertyWidget Ui;
};

pqProportionalEditPropertyWidget::pqProportionalEditPropertyWidget(vtkSMProxy* smproxy,
  vtkSMPropertyGroup* smgroup,
  QWidget* parentObj)
  : Superclass("representations",
      "ProportionalEditWidgetRepresentation",
      smproxy,
      smgroup,
      parentObj)
  , m_p(new pqProportionalEditPropertyWidget::Internals())
{
  Ui::ProportionalEditPropertyWidget& ui = m_p->Ui;
  ui.setupUi(this);

  // link show3DWidget checkbox
  this->connect(ui.show3DWidget, SIGNAL(toggled(bool)), SLOT(setWidgetVisible(bool)));
  ui.show3DWidget->connect(this, SIGNAL(widgetVisibilityToggled(bool)), SLOT(setChecked(bool)));
  this->setWidgetVisible(ui.show3DWidget->isChecked());

  // link showPreview checkbox
  this->connect(ui.showPreview, SIGNAL(toggled(bool)), SLOT(setShowPreview(bool)));
  this->setShowPreview(ui.showPreview->isChecked());

  // link Use Projection groupbox
  this->connect(ui.projectionGroupBox, SIGNAL(toggled(bool)), SLOT(setProjectionEnabled(bool)));
  this->setProjectionEnabled(ui.projectionGroupBox->isChecked());

#ifdef Q_OS_MAC
  ui.pickLabel->setText(ui.pickLabel->text().replace("Ctrl", "Cmd"));
#endif

  if (vtkSMProperty* p1 = smgroup->GetProperty("AnchorPoint"))
  {
    this->addPropertyLink(ui.centerX, "text2", SIGNAL(textChangedAndEditingFinished()), p1, 0);
    this->addPropertyLink(ui.centerY, "text2", SIGNAL(textChangedAndEditingFinished()), p1, 1);
    this->addPropertyLink(ui.centerZ, "text2", SIGNAL(textChangedAndEditingFinished()), p1, 2);
  }
  else
  {
    qCritical("Missing required property for function 'AnchorPoint'.");
  }

  if (vtkSMProperty* p2 = smgroup->GetProperty("Displacement"))
  {
    this->addPropertyLink(
      ui.displacementX, "text2", SIGNAL(textChangedAndEditingFinished()), p2, 0);
    this->addPropertyLink(
      ui.displacementY, "text2", SIGNAL(textChangedAndEditingFinished()), p2, 1);
    this->addPropertyLink(
      ui.displacementZ, "text2", SIGNAL(textChangedAndEditingFinished()), p2, 2);
  }
  else
  {
    qCritical("Missing required property for function 'Displacement'.");
  }

  if (vtkSMProperty* r = smgroup->GetProperty("InfluenceRadius"))
  {
    this->addPropertyLink(ui.radius, "text2", SIGNAL(textChangedAndEditingFinished()), r, 0);
  }
  else
  {
    qCritical("Missing required property for function 'InfluenceRadius'.");
  }

  if (vtkSMProperty* pd = smgroup->GetProperty("Projection"))
  {
    this->addPropertyLink(ui.directionX, "text2", SIGNAL(textChangedAndEditingFinished()), pd, 0);
    this->addPropertyLink(ui.directionY, "text2", SIGNAL(textChangedAndEditingFinished()), pd, 1);
    this->addPropertyLink(ui.directionZ, "text2", SIGNAL(textChangedAndEditingFinished()), pd, 2);
  }
  else
  {
    qCritical("Missing required property for function 'Projection'.");
  }

  auto* pickHelper1 = new pqPointPickingHelper(QKeySequence(tr("1")), false, this);
  pickHelper1->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper1->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper1, SIGNAL(pick(double, double, double)), SLOT(pickPoint1(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper1 };

  auto* pickHelper2 = new pqPointPickingHelper(QKeySequence(tr("Ctrl+1")), true, this);
  pickHelper2->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper2->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper2, SIGNAL(pick(double, double, double)), SLOT(pickPoint1(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper2 };

  auto* pickHelper3 = new pqPointPickingHelper(QKeySequence(tr("2")), false, this);
  pickHelper3->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper3->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper3, SIGNAL(pick(double, double, double)), SLOT(pickPoint2(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper3 };

  auto* pickHelper4 = new pqPointPickingHelper(QKeySequence(tr("Ctrl+2")), true, this);
  pickHelper4->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper4->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper4, SIGNAL(pick(double, double, double)), SLOT(pickPoint2(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper4 };

  auto* pickHelper5 = new pqPointPickingHelper(QKeySequence(tr("3")), false, this);
  pickHelper5->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper5->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper5, SIGNAL(pick(double, double, double)), SLOT(pickPoint3(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper5 };

  auto* pickHelper6 = new pqPointPickingHelper(QKeySequence(tr("Ctrl+3")), true, this);
  pickHelper6->connect(this, SIGNAL(viewChanged(pqView*)), SLOT(setView(pqView*)));
  pickHelper6->connect(this, SIGNAL(widgetVisibilityUpdated(bool)), SLOT(setShortcutEnabled(bool)));
  this->connect(
    pickHelper6, SIGNAL(pick(double, double, double)), SLOT(pickPoint3(double, double, double)));
  pqPointPickingVisibilityHelper<pqPointPickingHelper>{ *this, *pickHelper6 };
}

pqProportionalEditPropertyWidget::~pqProportionalEditPropertyWidget() = default;

void pqProportionalEditPropertyWidget::placeWidget()
{
  //nothing to do
}

void pqProportionalEditPropertyWidget::pickPoint1(double wx, double wy, double wz)
{
  double position[3] = { wx, wy, wz };
  vtkSMNewWidgetRepresentationProxy* wdgProxy = this->widgetProxy();
  vtkSMPropertyHelper(wdgProxy, "AnchorPoint").Set(position, 3);

  wdgProxy->UpdateVTKObjects();
  emit this->changeAvailable();
  this->render();
}

void pqProportionalEditPropertyWidget::pickPoint2(double wx, double wy, double wz)
{
  double displacement[3] = { wx, wy, wz };
  double position[3] = { 0, 0, 0 };
  vtkSMNewWidgetRepresentationProxy* wdgProxy = this->widgetProxy();
  // convert the point to a direction vector
  vtkSMPropertyHelper(wdgProxy, "AnchorPoint").Get(position, 3);
  for (int i = 0; i < 3; ++i)
  {
    displacement[i] -= position[i];
  }
  vtkSMPropertyHelper(wdgProxy, "Displacement").Set(displacement, 3);
  wdgProxy->UpdateVTKObjects();
  emit this->changeAvailable();
  this->render();
}

void pqProportionalEditPropertyWidget::pickPoint3(double wx, double wy, double wz)
{
  double projection[3] = { wx, wy, wz };
  double position[3] = { 0, 0, 0 };
  vtkSMNewWidgetRepresentationProxy* wdgProxy = this->widgetProxy();
  // convert the point to a direction vector
  vtkSMPropertyHelper(wdgProxy, "AnchorPoint").Get(position, 3);
  for (int i = 0; i < 3; ++i)
  {
    projection[i] -= position[i];
  }
  vtkSMPropertyHelper(wdgProxy, "Projection").Set(projection, 3);
  wdgProxy->UpdateVTKObjects();
  emit this->changeAvailable();
  this->render();
}

void pqProportionalEditPropertyWidget::setProjectionEnabled(bool isProjectionEnabled)
{
  // m_p->Ui.projectionGroupBox->setChecked(isProjectionEnabled);
  int pj = isProjectionEnabled ? 1 : 0;
  vtkSMNewWidgetRepresentationProxy* wdgProxy = this->widgetProxy();
  vtkSMPropertyHelper(wdgProxy, "ProjectionEnabled").Set(&pj, 1);
  wdgProxy->UpdateVTKObjects();
  emit this->changeAvailable();
  this->render();
}

void pqProportionalEditPropertyWidget::setShowPreview(bool showPreview)
{
  // checkbox is inverted for drawRegion var.
  int drawRegion = !showPreview ? 1 : 0;
  vtkSMNewWidgetRepresentationProxy* wdgProxy = this->widgetProxy();
  vtkSMPropertyHelper(wdgProxy, "DrawRegion").Set(&drawRegion, 1);
  wdgProxy->UpdateVTKObjects();
  emit this->changeAvailable();
  this->render();
}
