/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2024 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$
 ****************************************************************************/

// Local
#include "ChangeParent.h"

// CamiTK
#include <Property.h>
#include <Log.h>

using namespace camitk;

// --------------- constructor -------------------
ChangeParent::ChangeParent(ActionExtension* extension) : Action(extension) {
    setName("Change Parent");
    setDescription(tr("Modify the selected component's frame parent, i.e., change the parent coordinate system of the component."));
    setComponentClassName("Component");

    // Setting classification family and tags
    setFamily("Frame");
    addTag(tr("Parent"));
    addTag(tr("Coordinates"));

    currentComponent = nullptr;

    // combobox for selecting the parent's frame
    Property* componentList = new Property("Component List", 0, "List of possible parent frames", "");
    // Set the enum type
    componentList->setEnumTypeName("ComponentList");
    // Start with a default values
    QStringList componentListNames;
    componentListNames << "World";
    componentList->setAttribute("enumNames", componentListNames);

    // Add the property as an action parameter
    addParameter(componentList);

    addParameter(new Property(tr("Keep Transform From Parent"), false,
                              tr("<ul>\n<li>If checked, the local transform from parent is not recalculated. The current component frame may therefore move relatively to the world coordinate system as its local transform will be then expressed relatively to the new designated parent.</li>\n<li>If unchecked, the local transform from parent will be modified in order to leave the component at the same place and orientation relatively to the world coordinate system. </li>\n</ul>"), ""));
}

// --------------- getWidget -------------------
QWidget* ChangeParent::getWidget() {
    currentComponent = getTargets().last();

    updateComboBox();

    return Action::getWidget();
}

// --------------- apply -------------------
Action::ApplyStatus ChangeParent::apply() {
    if (currentComponent == nullptr) {
        // probably called during automatic test
        CAMITK_WARNING(tr("This action needs a user interaction to set the new parent frame"));
        return ABORTED;
    }

    bool keepTransform = property("Keep Transform From Parent").toBool();

    // Look for the parentFrame in the combobox
    Component* parentFrame = possibleParentList.value(property("Component List").toInt());
    if (parentFrame == currentComponent) {
        CAMITK_WARNING(tr("You can not set the frame itself as parent"));
        return ABORTED;
    }
    currentComponent->setParentFrame(parentFrame, keepTransform);

    Application::refresh();
    return SUCCESS;
}

// --------------- updateComboBox -------------------
void ChangeParent::updateComboBox() {
    possibleParentList.clear();

    // current parent
    InterfaceFrame* parentFrame = currentComponent->getParentFrame();
    Component* parentFrameComponent = dynamic_cast<Component*>(parentFrame);
    int currentId = 0;

    // Update the list of possible parents
    QStringList componentListNames;
    componentListNames << "World";
    possibleParentList.append(nullptr);

    ComponentList allComps = Application::getAllComponents();

    foreach (Component* comp, allComps) {
        QString itemName = "";
        if (!comp->isTopLevel()) {
            itemName += QChar(0x251C); // https://www.compart.com/en/unicode/U+251C
            itemName += " ";
        }
        itemName += comp->getName();
        if (comp == currentComponent) {
            itemName += " [*]";
        }

        componentListNames << itemName;
        possibleParentList.append(comp);

        if (comp == parentFrameComponent) {
            currentId = possibleParentList.size() - 1;
        }
    }

    Property* componentList = getProperty("Component List");
    componentList->setAttribute("enumNames", componentListNames);

    // select the current value in the combobox
    setProperty("Component List", currentId);
}
