// CamiTK includes
#include "ComputeNormals.h"
#include <Application.h>
#include <MeshComponent.h>
#include <Log.h>
#include <Property.h>

// Vtk includes
#include <vtkPolyDataNormals.h>
#include <vtkCallbackCommand.h>
#include <vtkDataSetAttributes.h>
#include <vtkPointData.h>
#include <vtkCellData.h>

using namespace camitk;

ComputeNormals::ComputeNormals(camitk::ActionExtension* ext) : Action(ext) {
    this->setName("Compute Normals");
    this->setDescription(QString(tr("Compute normals of surface mesh.")));
    this->setComponentClassName("MeshComponent");
    this->setFamily("Basic Mesh");
    this->addTag(tr("normal"));
    this->addTag(tr("surface"));
}

Action::ApplyStatus ComputeNormals::apply() {
    // set waiting cursor and status bar
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    Application::showStatusBarMessage(tr("Compute Curvatures..."));
    Application::resetProgressBar();
    vtkSmartPointer<vtkCallbackCommand> progressCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    progressCallback->SetCallback(&Application::vtkProgressFunction);

    // target must be a polydata
    MeshComponent* mesh = dynamic_cast<MeshComponent*>(getTargets().first());

    if (mesh == nullptr) {
        QApplication::restoreOverrideCursor();
        CAMITK_WARNING(tr("Mesh \"%1\" is not a MeshComponent. Action aborted.").arg(getTargets().first()->getName()))
        return ABORTED;
    }

    if (mesh->getPointSet() == nullptr) {
        QApplication::restoreOverrideCursor();
        CAMITK_WARNING(tr("The mesh point set of \"%1\" does not have a vtkPointSet. Action aborted.").arg(getTargets().first()->getName()))
        return ABORTED;
    }

    vtkSmartPointer<vtkPolyData> pData = vtkPolyData::SafeDownCast(mesh->getPointSet());

    if (pData == nullptr) {
        QApplication::restoreOverrideCursor();
        CAMITK_WARNING(tr("The mesh point set of \"%1\" is not a vtkPolyData. Action aborted.").arg(getTargets().first()->getName()))
        return ABORTED;
    }

    // compute normals
    vtkSmartPointer<vtkPolyDataNormals> polyNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
    polyNormals->SetInputData(pData);
    polyNormals->AddObserver(vtkCommand::ProgressEvent, progressCallback);
    polyNormals->Update();

    if (polyNormals->GetOutput()->GetPointData()->GetScalars("Normals") == nullptr) {
        QApplication::restoreOverrideCursor();
        CAMITK_WARNING(tr("No normals can be computed for: \"%1\" (probably no 3D surface in this mesh). Action aborted.").arg(getTargets().first()->getName()))
        return ABORTED;
    }

    mesh->addPointData("Normals", polyNormals->GetOutput()->GetPointData()->GetScalars("Normals"));

    // refresh restore the normal cursor and progress bar
    refreshApplication();
    Application::resetProgressBar();
    Application::showStatusBarMessage("");
    QApplication::restoreOverrideCursor();
    return SUCCESS;
}
