/*****************************************************************************
* $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 "ViewerExtension.h"
#include "Viewer.h"
#include "Application.h"
#include "Core.h"
#include "Log.h"

#include <QDir>
#include <QMetaType>

namespace camitk {

// -------------------- constructor --------------------
ViewerExtension::ViewerExtension() {
    managedMetaObject = nullptr;
    translator = nullptr;
}

// -------------------- destructor --------------------
ViewerExtension::~ViewerExtension() {
    while (!viewers.empty()) {
        Viewer* toDelete = viewers.takeFirst();
        delete toDelete;
    }

    // delete internationalization instance
    if (translator) {
        delete translator;
    }
}

// -------------------- initResources --------------------
void ViewerExtension::initResources() {
    // Get the selected language
    QString selectedLanguage = Application::getSelectedLanguage();

    // if a language is defined, then try to load the translation file
    if (!selectedLanguage.isEmpty()) {
        QString viewerExtensionDirName = QDir(this->getLocation()).dirName();
        // remove any occurence of "-debug.dll" or ".so" or ".dylib" on the extension file name
        viewerExtensionDirName.remove("-debug.dll").remove(".so").remove(".dylib");
        QString languageFile = ":/translate_" + viewerExtensionDirName + "/translate/translate_" + selectedLanguage + ".qm";
        translator = new QTranslator();

        if (translator->load(languageFile)) {
            QCoreApplication::installTranslator(translator);
        }
        else {
            CAMITK_INFO(tr("Cannot load resource file: %1").arg(languageFile))
        }
    }
}

// -------------------- setLocation --------------------
void ViewerExtension::setLocation(const QString loc) {
    dynamicLibraryFileName = loc;
}

// -------------------- getLocation --------------------
QString ViewerExtension::getLocation() const {
    return dynamicLibraryFileName;
}

// -------------------- getViewerClassName --------------------
QString ViewerExtension::getViewerClassName() const {
    if (managedMetaObject == nullptr) {
        return "";
    }
    else {
        return managedMetaObject->className();
    }
}

// -------------------- setManagedMetaObject --------------------
void ViewerExtension::setManagedMetaObject(const QMetaObject* metaObject) {
    // first call, set the viewer class meta object
    if (managedMetaObject == nullptr) {
        managedMetaObject = metaObject;
    }
}

// -------------------- registerViewer --------------------
bool ViewerExtension::registerViewer(Viewer* viewer) {
    /* QString reg = "([^A-Z\\s])([A-Z])"; // ;
     //QString reg = "([A-Z]*)|([A-Z][a-z]*)";
     QString repl = "\\1 \\2";
     // "((?<=\\p{Ll})\\p{Lu})|((?!\\A)\\p{Lu}(?>\\p{Ll}))";  // " \\1"
     QString formatted1 = QString("Medical Image Viewer").replace(QRegularExpression(reg),repl);
     QString formatted2 = QString("Medical ImageViewer").replace(QRegularExpression(reg),repl);
     QString formatted3 = QString("TestACRONYMViewer").replace(QRegularExpression(reg),repl);
     QString formatted4 = formatted3;
     formatted4.replace(QRegularExpression("([A-Z]+)([A-Z][a-z])"),repl);
     QString formatted5 = formatted2;
     formatted5.replace(QRegularExpression("([A-Z]+)([A-Z][a-z])"),repl);
     QString formatted6 = viewer->getName();
     formatted6.replace(QRegularExpression("([^A-Z\\s])([A-Z])"),"\\1 \\2").replace(QRegularExpression("([A-Z]+)([A-Z][a-z])"),"\\1 \\2");
         //"([a-z])([A-Z])"),"\\1 \\2");
     //formatted2.replace("([A-Z])([A-Z][a-z])","\\1 \\2");
     CAMITK_INFO(tr("\n%1\n%2\n%3\n%4\n%5\n%6").arg(formatted1).arg(formatted2).arg(formatted3).arg(formatted4).arg(formatted5).arg(formatted6))*/
    // only one type of viewer is managed by a viewer extension
    if (getViewerClassName() != viewer->metaObject()->className()) {
        CAMITK_ERROR(tr("Cannot register viewer \"%1\" as it is an instance of \"%2\" (extension \"%3\" only manages the \"%4\" viewer class)").arg(viewer->getName(), viewer->metaObject()->className(), getName(), getViewerClassName()))
        return false;
    }

    // simply add the viewer in the list
    viewers.append(viewer);

    // all OK
    return true;
}

// -------------------- getNewInstance --------------------
Viewer* ViewerExtension::getNewInstance(QString name) {
    // check if a viewer of the same name exists
    int i = 0;

    while (i < viewers.size() && viewers.at(i)->getName() != name) {
        i++;
    }

    if (i != viewers.size()) {
        CAMITK_INFO(tr("No new instance created, returning already instantiated and registered \"%1\" viewer.\nViewer instance names should be unique.\n").arg(name))
        return viewers.at(i);
    }

    // if the viewer does not already exist, instantiate it
    QObject* instance = managedMetaObject->newInstance(Q_ARG(QString, name)); // add constructor arguments as needed
    Viewer* viewerInstance = qobject_cast<Viewer*>(instance);

    if (viewerInstance != nullptr) {
        // register it in the list
        registerViewer(viewerInstance);
    }
    else {
        CAMITK_ERROR(tr("Cannot instantiate %1 from static meta object").arg(getViewerClassName()));
    }

    return viewerInstance;
}

// -------------------- getViewers --------------------
const ViewerList& ViewerExtension::getViewers() {
    return viewers;
}


}
