
/*
 * pykcm_launcher.cpp
 *
 * Launch Control Centre modules written in Python using an embedded Python
 * interpreter.
 * Based on David Boddie's PyTDE-components.
 */

// pythonize.h must be included first.
#include <pythonize.h>
#include <tdecmodule.h>
#include <tdeglobal.h>
#include <tdelocale.h>
#include <klibloader.h>
#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <tqstring.h>
#include <sip-tqt.h>

#define MODULE_DIR "/root/TEMP5/tde-guidance-trinity-14.0.0-r131/debian/tmp/opt/trinity/share/apps/guidance"
#define EXTRA_MODULE_DIR "None"
#define MODULE_NAME "wineconfig"
#define FACTORY "create_wineconfig"
#define CPP_FACTORY create_wineconfig
#define LIB_PYTHON "libpython2.7.so"
#define debug 1

static TDECModule *report_error(char *msg) {
    if (debug) printf ("error: %s\n", msg);
    return NULL;
}

static TDECModule* return_instance( TQWidget *parent, const char *name ) {
    TDECModule* tdecmodule;
    PyObject *pyTDECModuleTuple;
    PyObject *pyTDECModule;
    Pythonize *pyize;  // Pythonize object to manage the Python interpreter.
    int isErr;

    // Try to determine what py script we're loading. Note that "name"
    // typically appears to be NULL.
    TQString script(MODULE_NAME);

    // Reload libpython, but this time tell the runtime linker to make the
    // symbols global and available for later loaded libraries/module.
    KLibLoader::self()->globalLibrary(LIB_PYTHON);

    // Start the interpreter.
    pyize = initialize();
    if (!pyize) {
        return report_error ("***Failed to start interpreter\n");
    }

    // Add the path to the python script to the interpreter search path.
    TQString path = TQString(MODULE_DIR);
    if(path == TQString::null) {
        return report_error ("***Failed to locate script path");
    }
    if(!pyize->appendToSysPath (path.latin1 ())) {
        return report_error ("***Failed to set sys.path\n");
    }

    // Add the extra path to the python script to the interpreter search path.
    TQString extrapath = TQString(EXTRA_MODULE_DIR);
    if(!pyize->appendToSysPath (extrapath.latin1 ())) {
      return report_error ("***Failed to set extra sys.path\n");
    }

    // Load the Python script.
    PyObject *pyModule = pyize->importModule ((char *)script.latin1 ());
    if(!pyModule) {
        PyErr_Print();
        return report_error ("***failed to import module\n");
    }

    // Inject a helper function
    TQString bridge = TQString("import sip_tqt\n"
                            "from PyTQt import tqt\n"
                            "def kcontrol_bridge_" FACTORY "(parent,name):\n"
                             "    if parent!=0:\n"
                             "        wparent = sip_tqt.wrapinstance(parent,tqt.TQWidget)\n"
                             "    else:\n"
                             "        wparent = None\n"
                             "    inst = " FACTORY "(wparent, name)\n"
                             "    return (inst,sip_tqt.unwrapinstance(inst))\n");
    PyRun_String(bridge.latin1(),Py_file_input,PyModule_GetDict(pyModule),PyModule_GetDict(pyModule));

    // Get the Python module's factory function.
    PyObject *kcmFactory = pyize->getNewObjectRef(pyModule, "kcontrol_bridge_" FACTORY);
    if(!kcmFactory) {
        return report_error ("***failed to find module factory\n");
    }

    // Call the factory function. Set up the args.
    PyObject *pyParent = PyLong_FromVoidPtr(parent);
    PyObject *pyName = PyBytes_FromString(MODULE_NAME);
        // Using NN here is effect gives our references to the arguement away.
    PyObject *args = Py_BuildValue ("NN", pyParent, pyName);
    if(pyName && pyParent && args) {
        // run the factory function
        pyTDECModuleTuple = pyize->runFunction(kcmFactory, args);
        if(!pyTDECModuleTuple) {
            PyErr_Print();
            return report_error ("*** runFunction failure\n;");
        }
    } else {
        return report_error ("***failed to create args\n");
    }
    // cleanup a bit
    pyize->decref(args);
    pyize->decref(kcmFactory);

    // Stop this from getting garbage collected.
    Py_INCREF(PyTuple_GET_ITEM(pyTDECModuleTuple,0));

    // convert the TDECModule PyObject to a real C++ TDECModule *.
    isErr = 0;
    pyTDECModule = PyTuple_GET_ITEM(pyTDECModuleTuple,1);
    tdecmodule = (TDECModule *)PyLong_AsVoidPtr(pyTDECModule);
    if(!tdecmodule) {
        return report_error ("***failed sip conversion to C++ pointer\n");
    }
    pyize->decref(pyTDECModuleTuple);

    // PyTDE can't run the module without this - Pythonize
    // grabs the lock at initialization and we have to give
    // it back before exiting. At this point, we no longer need
    // it.
    //pyize->releaseLock ();

    // take care of any translation info
    TDEGlobal::locale()->insertCatalogue(script);

    // Return the pointer to our new TDECModule
    return tdecmodule;
}

extern "C" {
    // Factory function that kcontrol will call.
    TDECModule* CPP_FACTORY(TQWidget *parent, const char *name) {
        return return_instance(parent, name);
    }
}
