/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#include "VtkMeshComponent.h"

// -- CamiTK stuff
#include <Application.h>
#include <Property.h>
#include <AbortException.h>

// -- vtk stuff
// disable warning generated by clang about the surrounded headers
#include <CamiTKDisableWarnings>
#include <vtkProperty.h>
#include <CamiTKReEnableWarnings>

#include <vtkPointData.h>
#include <vtkCellData.h>

using namespace camitk;

// -------------------- default constructor  --------------------
VtkMeshComponent::VtkMeshComponent(const QString& fileName) : MeshComponent(fileName) {

    whatIsIt = VtkMeshUtil::typeOf(myFileName.toStdString());

    if (whatIsIt == VtkMeshUtil::UNKNOWN) {
        throw AbortException("Unable to recognize this vtk file\n(it is neither an unstructured grid nor a poly data).");
    }

    QString nameInHeader = VtkMeshUtil::getVtkPointSetHeaderString(myFileName.toStdString()).c_str();
    if (getName() != nameInHeader) {
        setName(Application::getUniqueComponentName(nameInHeader));
    }

    myProperties = nullptr;

    // build the vtk data structure from the file
    vtkSmartPointer<vtkPointSet> data = VtkMeshUtil::buildVtkPointSet(myFileName.toStdString().c_str(), whatIsIt);

    // instantiate the Geometry
    initRepresentation(data);
}

// -------------------- destructor --------------------
VtkMeshComponent::~VtkMeshComponent() {
    // no active data by default
    setDataRepresentationOff();
}

//------------------------ getPixmap ---------------------
#include "vtklogo_20x20.xpm"
QPixmap* VtkMeshComponent::myPixmap = nullptr;
QPixmap VtkMeshComponent::getIcon() {
    if (!myPixmap) {
        myPixmap = new QPixmap(vtklogo_20x20);
    }
    return (*myPixmap);
}

// -------------------- initDynamicProperties --------------------
void VtkMeshComponent::initDynamicProperties() {

    MeshComponent::initDynamicProperties();

    // add a dynamic property to manage the surface color
    double initialValue = 0.0;
    if (getActor(InterfaceGeometry::Surface)) {
        initialValue = getActor(InterfaceGeometry::Surface)->GetProperty()->GetAmbient();
    }
    Property* ambient = new Property("Ambient", initialValue, tr("Ambient Lightning Coefficient. Warning: this cannot be saved in the VTK file."), "%");
    ambient->setAttribute("minimum", 0.0);
    ambient->setAttribute("maximum", 1.0);
    ambient->setAttribute("decimals", 2);
    ambient->setAttribute("singleStep", 0.1);
    addProperty(ambient);

    if (getActor(InterfaceGeometry::Surface)) {
        initialValue = getActor(InterfaceGeometry::Surface)->GetProperty()->GetDiffuse();
    }
    Property* diffuse = new Property("Diffuse", initialValue, tr("Diffuse Lightning Coefficient. Warning: this cannot be saved in the VTK file."), "%");
    diffuse->setAttribute("minimum", 0.0);
    diffuse->setAttribute("maximum", 1.0);
    diffuse->setAttribute("decimals", 2);
    diffuse->setAttribute("singleStep", 0.1);
    addProperty(diffuse);

    if (getActor(InterfaceGeometry::Surface)) {
        initialValue = getActor(InterfaceGeometry::Surface)->GetProperty()->GetSpecular();
    }
    Property* specular = new Property("Specular", initialValue, tr("Specular Lightning Coefficient. Warning: this cannot be saved in the VTK file."), "%");
    specular->setAttribute("minimum", 0.0);
    specular->setAttribute("maximum", 1.0);
    specular->setAttribute("decimals", 2);
    specular->setAttribute("singleStep", 0.1);
    addProperty(specular);

    if (getActor(InterfaceGeometry::Surface)) {
        initialValue = getActor(InterfaceGeometry::Surface)->GetProperty()->GetSpecularPower();
    }
    Property* specularPower = new Property("Specular Power", initialValue, tr("Specular Power. Warning: this cannot be saved in the VTK file."), "%");
    specularPower->setAttribute("minimum", 0.0);
    specularPower->setAttribute("maximum", 128.0);
    addProperty(specularPower);

    if (getActor(InterfaceGeometry::Surface)) {
        initialValue = getActor(InterfaceGeometry::Surface)->GetProperty()->GetOpacity();
    }
    Property* opacity = new Property("Opacity", initialValue, tr("The object's opacity. 1.0 is totally opaque and 0.0 is completely transparent. Warning: this cannot be saved in the VTK file."), "%");
    opacity->setAttribute("minimum", 0.0);
    opacity->setAttribute("maximum", 1.0);
    opacity->setAttribute("decimals", 2);
    opacity->setAttribute("singleStep", 0.1);
    addProperty(opacity);

    double initialColor[3] = {0.8, 0.8, 0.8};
    if (getActor(InterfaceGeometry::Surface)) {
        getActor(InterfaceGeometry::Surface)->GetProperty()->GetColor(initialColor);
    }
    QColor initialQColor;
    initialQColor.setRgbF(initialColor[0], initialColor[1], initialColor[2]);
    addProperty(new Property("Specular Color", initialQColor, tr("Specular Surface Color"), "RGB"));

}

// -------------------- propertyValueChanged  --------------------
void VtkMeshComponent::propertyValueChanged(QString name) {
    if (name == "Ambient") {
        if (getActor(InterfaceGeometry::Surface)) {
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetAmbient(getPropertyValue(name).toDouble());
        }
    }
    else if (name == "Diffuse") {
        if (getActor(InterfaceGeometry::Surface)) {
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetDiffuse(getPropertyValue(name).toDouble());
        }
    }
    else if (name == "Specular") {
        if (getActor(InterfaceGeometry::Surface)) {
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetSpecular(getPropertyValue(name).toDouble());
        }
    }
    else if (name == "Specular Power") {
        if (getActor(InterfaceGeometry::Surface)) {
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetSpecularPower(getPropertyValue(name).toDouble());
        }
    }
    else if (name == "Opacity") {
        if (getActor(InterfaceGeometry::Surface)) {
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetOpacity(getPropertyValue(name).toDouble());
        }
    }
    else if (name == "Specular Color") {
        if (getActor(InterfaceGeometry::Surface)) {
            QColor newColor = getPropertyValue(name).value<QColor>();
            getActor(InterfaceGeometry::Surface)->GetProperty()->SetSpecularColor(newColor.redF(), newColor.greenF(), newColor.blueF());
        }
    }
    else {
        // just in case there is an inherited property to manage
        MeshComponent::propertyValueChanged(name);
    }

    // refresh the viewers
    refresh();
}


