// Version: $Id$
//
//

// Commentary:
//
//

// Change Log:
//
//

// Code:

#pragma once

%include "carrays.i"

%array_class(double, doubleArray);

%{

#include <QtDebug>
#include <QtCore>

#include <string>

%}

// /////////////////////////////////////////////////////////////////
// Preprocessing setup
// /////////////////////////////////////////////////////////////////

#pragma SWIG nowarn=302, 389, 401, 509, 801, 472, 473, 476, 362, 503, 514, 516, 842, 845

// /////////////////////////////////////////////////////////////////
// Macro undefinition
// /////////////////////////////////////////////////////////////////

#undef Q_OBJECT
#undef signals
#undef slots

#define Q_OBJECT
#define signals public
#define slots

#undef  Q_PROPERTY(Type type MODE mode)
#define Q_PROPERTY(Type type MODE mode)

#undef  Q_DECLARE_INTERFACE(IFace, IId)
#define Q_DECLARE_INTERFACE(IFace, IId)

#undef  Q_DECLARE_METATYPE(Type type)
#define Q_DECLARE_METATYPE(Type type)

#undef  DTK_DEPRECATED
#define DTK_DEPRECATED

#undef  DTK_DECLARE_PLUGIN(type, Export)
%define DTK_DECLARE_PLUGIN(type, Export)
    class  type##Plugin : public dtkCorePluginBase {
};
%enddef

#undef  DTK_DECLARE_PLUGIN_FACTORY(type, Export)
%define DTK_DECLARE_PLUGIN_FACTORY(type, Export)
%extend QVariant {
    void setValue(type *value) {
        $self->setValue(dtkMetaType::variantFromValue(value));
    }
    type* to##type() const {
        return $self->value<type *>();
    }
 }
%template(type##PluginFactorySwigTemplate) dtkCorePluginFactory<type>;
class Export type##PluginFactory : public dtkCorePluginFactory<type> {};
%enddef

#undef  DTK_DECLARE_PLUGIN_MANAGER(type, Export)
%define DTK_DECLARE_PLUGIN_MANAGER(type, Export)
%template(type##PluginManagerSwigTemplate) dtkCorePluginManager<type##Plugin>;
class Export type##PluginManager : public dtkCorePluginManager<type##Plugin> {};
%enddef

#undef  DTK_DECLARE_CONCEPT(type, Export, Namespace)
%define DTK_DECLARE_CONCEPT(type, Export, Namespace)
%rename(Namespace##_pluginFactory) Namespace::pluginFactory;
%rename(Namespace##_pluginManager) Namespace::pluginManager;
namespace Namespace {
     Export type##PluginFactory& pluginFactory();
     Export type##PluginManager& pluginManager();
}
%enddef

#undef  DTK_DECLARE_OBJECT(Type type)
#define DTK_DECLARE_OBJECT(Type type)

#undef  Q_DECL_DEPRECATED_X(msg)
#define Q_DECL_DEPRECATED_X(msg)

// /////////////////////////////////////////////////////////////////
// Ignore rules for operators
// /////////////////////////////////////////////////////////////////

%ignore operator>>;
%ignore operator<<;
%ignore operator==;
%ignore operator[];
%ignore operator!=;
%ignore operator*=;
%ignore operator/=;
%ignore operator bool;
%ignore operator int;
%ignore operator float;
%ignore operator double;
%ignore operator double *;

// /////////////////////////////////////////////////////////////////
// Typemaps
// /////////////////////////////////////////////////////////////////

#ifdef SWIGPYTHON

%typecheck(SWIG_TYPECHECK_STRING) char * {
    $1 = PyString_Check($input) ? 1 : 0;
}

// Python -> C++

// qlonglong

%typemap(in) qlonglong {
   $1 = PyInt_AsLong($input);
}

%typemap(in) const qlonglong& {
   $1 = PyInt_AsLong($input);
}

%typemap(directorout) qlonglong {
    PyObject *o = static_cast<PyObject *>($1);
    if (PyInt_Check(o)) {
        $result = PyInt_AsLong(o);
    } else {
        qDebug("Long int is expected as input. Zero integer is returned.");
        $result = 0;
    }
}

%typemap(typecheck)            qlonglong   = long long;
%typemap(typecheck)      const qlonglong&  = long long;
%typemap(typecheck)       QString  = char *;
%typemap(typecheck) const QString& = char *;
%typemap(typecheck)       QString  = const char *;
%typemap(typecheck) const QString& = const char *;


%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, noblock=1) QStringList {
    $1 = PyList_Check($input) ? 1 : 0;
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, noblock=1) const QStringList& {
    $1 = PyList_Check($input) ? 1 : 0;
}

// Python -> C++

// QString

%typemap(in) QString {
    if (PyString_Check($input)) {
        $1 = QString(PyString_AsString($input));
    } else {
        qDebug("String is expected as input. Empty QString is returned.");
    }
}

%typemap(in) const QString& {
    if (PyString_Check($input)) {
        char *t = PyString_AsString($input);
        $1 = new QString(t);
    } else {
        qDebug("String is expected as input. Empty QString is returned.");
    }
}

%typemap(freearg) const QString& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QString {
    PyObject *ps = static_cast<PyObject *>($1);
    if (PyString_Check(ps)) {
        $result = QString(PyString_AsString(ps));
    } else {
        qDebug("String is expected as input. Empty QString is returned.");
    }
}

// QStringList

%typemap(in) QStringList {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        for(int i = 0; i!=end; ++i) {
            $1 << QString(PyString_AsString(PyList_GET_ITEM($input, i)));
        }
    } else {
        qDebug("PyList of strings is expected as input. Empty QStringList is returned.");
    }
}

%typemap(in) const QStringList& {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        $1 = new QStringList;
        for(int i = 0 ;i!=end; ++i) {
            char *t = PyString_AsString(PyList_GET_ITEM($input, i));
            (*$1) << QString(t);
        }
    } else {
        qDebug("PyList of strings is expected as input. Empty QStringList is returned.");
    }
}

%typemap(freearg) const QStringList& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QStringList {
    PyObject *list = static_cast<PyObject *>($1);
    if (PyList_Check(list)) {
        int end = PyList_Size(list);
        for(int i = 0; i<end; ++i) {
            char *t = PyString_AsString(PyList_GET_ITEM(list, i));
            $result << QString(t);
        }
    } else {
        qDebug("PyList of integers is expected as input. Empty QList<long> is returned.");
    }
}

// QList<long>

%typemap(in) QList<long> {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        for(int i = 0; i!=end; ++i) {
            $1 << PyInt_AsLong(PyList_GET_ITEM($input, i));
        }
    } else {
        qDebug("PyList of integers is expected as input. Empty QList<long> is returned.");
    }
}

%typemap(in) const QList<long>& {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        $1 = new QList<long>;
        for(int i = 0; i!=end; ++i) {
            ($1)->append(PyInt_AsLong(PyList_GET_ITEM($input, i)));
        }
    } else {
        qDebug("PyList of integers is expected as input. Empty QList<long> is returned.");
    }
}

%typemap(freearg) const QList<long>& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QList<long> {
    PyObject *list = static_cast<PyObject *>($1);
    if (PyList_Check(list)) {
        int end = PyList_Size(list);
        for(int i = 0; i<end; ++i) {
            PyObject *o = PyList_GET_ITEM(list, i);
            $result << PyInt_AsLong(o);
        }
    } else {
        qDebug("PyList of integers is expected as input. Empty QList<long> is returned.");
    }
}

// QList<double>

%typemap(in) QList<double> {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        for(int i = 0; i!=end; ++i) {
            $1 << PyFloat_AsDouble(PyList_GET_ITEM($input, i));
        }
    } else {
        qDebug("PyList of double is expected as input. Empty QList<double> is returned.");
    }
}

%typemap(in) const QList<double>& {
    if (PyList_Check($input)) {
        int end = PyList_Size($input);
        $1 = new QList<double>;
        for(int i = 0; i!=end; ++i) {
            ($1)->append(PyFloat_AsDouble(PyList_GET_ITEM($input, i)));
        }
    } else {
        qDebug("PyList of double floats is expected as input. Empty QList<double> is returned.");
    }
}

%typemap(freearg) const QList<double>& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QList<double> {
    PyObject *list = static_cast<PyObject *>($1);
    if (PyList_Check(list)) {
        int end = PyList_Size(list);
        for(int i = 0; i<end; ++i) {
            PyObject *o = PyList_GET_ITEM(list, i);
            $result << PyFloat_AsDouble(o);
        }
    } else {
        qDebug("PyList of double floats is expected as input. Empty QList<double> is returned.");
    }
}

// QMap<long, QVariant>

%typemap(in) QMap<long, QVariant> {
    if (PyDict_Check($input)) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next($input, &pos, &key, &value)) {
            long k = PyInt_AS_LONG(key);
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $1.insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<long, QVariant> is returned.");
    }
}

%typemap(in) const QMap<long, QVariant>& {
    if (PyDict_Check($input)) {
        $1 = new QMap<long, QVariant>;
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next($input, &pos, &key, &value)) {
            long k = PyInt_AS_LONG(key);
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $1->insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<long, QVariant> is returned.");
    }
}

%typemap(freearg) const QMap<long, QVariant>& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QMap<long, QVariant> {
    PyObject *dict = static_cast<PyObject *>($1);
    if (PyDict_Check(dict)) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next(dict, &pos, &key, &value)) {
            long k = PyInt_AS_LONG(key);
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyInt_Check(value) || PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $result.insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<long, QVariant> is returned.");
    }
}

// QMap<QString, QVariant>

%typemap(in) QMap<QString, QVariant> {
    if (PyDict_Check($input)) {
        PyObect *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next($input, &pos, &key, &value)) {
            QString k = QString(PyString_AsString(key));
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $1.insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<QString, QVariant> is returned.");
    }
}

%typemap(in) const QMap<QString, QVariant>& {
    if (PyDict_Check($input)) {
        $1 = new QMap<QString, QVariant>;
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next($input, &pos, &key, &value)) {
            QString k = QString(PyString_AsString(key));
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $1->insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<QString, QVariant> is returned.");
    }
}

%typemap(freearg) const QMap<QString, QVariant>& {
    if ($1) {
        delete $1;
    }
}

%typemap(directorout) QMap<QString, QVariant> {
    PyObject *dict = static_cast<PyObject *>($1);
    if (PyDict_Check(dict)) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        QVariant v;
        while (PyDict_Next(dict, &pos, &key, &value)) {
            QString k = QString(PyString_AsString(key));
            if (PyString_Check(value)) {
                v = QVariant::fromValue(QString(PyString_AsString(value)));
            } else if (PyBool_Check(value)) {
                bool b = (value == Py_True);
                v = QVariant::fromValue(b);
            } else if (PyInt_Check(value) || PyLong_Check(value)) {
                v = QVariant::fromValue(PyInt_AsLong(value));
            } else if (PyFloat_Check(value)) {
                v = QVariant::fromValue(PyFloat_AsDouble(value));
            } else {
                qDebug("Value type is not handled. Empty QVariant is set.");
            }
            $result.insert(k, v);
        }
    } else {
        qDebug("PyDict is expected as input. Empty QMap<QString, QVariant> is returned.");
    }
}

// C++ -> Python

// qlonglong

%typemap(out) qlonglong {
   $result = PyInt_FromLong($1);
}

%typemap(out) const qlonglong& {
   $result = PyInt_FromLong($1);
}

%typemap(directorin) qlonglong {
    $input = PyInt_FromLong($1);
}

%typemap(directorin) const qlonglong& {
    $input = PyInt_FromLong($1);
}

// QString

%typemap(out) QString {
    $result = PyString_FromString($1.toUtf8().constData());
}

%typemap(out) const QString& {
    $result = PyString_FromString($1.toUtf8().constData());
}

%typemap(directorin) QString {
    $input = PyString_FromString($1.toUtf8().constData());
}

%typemap(directorin) const QString& {
    $input = PyString_FromString($1.toUtf8().constData());
}

// QVariant

%typemap(out) QVariant {
    QVariant val = $1;
    PyObject *v;
    int type = val.type();
    if (type == QMetaType::Int ||
        type == QMetaType::UInt ||
        type == QMetaType::Long ||
        type == QMetaType::ULong ||
        type == QMetaType::LongLong ||
        type == QMetaType::ULongLong) {
        v = PyInt_FromLong(val.value<long>());
    } else if (type == QMetaType::Float ||
               type == QMetaType::Double) {
        v = PyFloat_FromDouble(val.value<double>());
    } else if (type == QMetaType::QString) {
        v = PyString_FromString(qPrintable(val.value<QString>()));
    } else if (type == QMetaType::Bool) {
        bool b = val.value<bool>();
        v = b ? Py_True : Py_False;
    }

    $result = v;
 }

%typemap(out) const QVariant& {
    QVariant val = *($1);
    PyObject *v;
    int type = val.type();
    if (type == QMetaType::Int ||
        type == QMetaType::UInt ||
        type == QMetaType::Long ||
        type == QMetaType::ULong ||
        type == QMetaType::LongLong ||
        type == QMetaType::ULongLong) {
        v = PyInt_FromLong(val.value<long>());
    } else if (type == QMetaType::Float ||
               type == QMetaType::Double) {
        v = PyFloat_FromDouble(val.value<double>());
    } else if (type == QMetaType::QString) {
        v = PyString_FromString(qPrintable(val.value<QString>()));
    } else if (type == QMetaType::Bool) {
        bool b = val.value<bool>();
        v = b ? Py_True : Py_False;
    }
    $result = v;
}

%typemap(directorin) QVariant {
    QVariant val = $1;
    PyObject *v;
    int type = val.type();
    if (type == QMetaType::Int ||
        type == QMetaType::UInt ||
        type == QMetaType::Long ||
        type == QMetaType::ULong ||
        type == QMetaType::LongLong ||
        type == QMetaType::ULongLong) {
        v = PyInt_FromLong(val.value<long>());
    } else if (type == QMetaType::Float ||
               type == QMetaType::Double) {
        v = PyFloat_FromDouble(val.value<double>());
    } else if (type == QMetaType::QString) {
        v = PyString_FromString(qPrintable(val.value<QString>()));
    } else if (type == QMetaType::Bool) {
        bool b = val.value<bool>();
        v = b ? Py_True : Py_False;
    }
    $input = v;
}

%typemap(directorin) const QVariant& {
    QVariant val = $1;
    PyObject *v;
    int type = val.type();
    if (type == QMetaType::Int ||
        type == QMetaType::UInt ||
        type == QMetaType::Long ||
        type == QMetaType::ULong ||
        type == QMetaType::LongLong ||
        type == QMetaType::ULongLong) {
        v = PyInt_FromLong(val.value<long>());
    } else if (type == QMetaType::Float ||
               type == QMetaType::Double) {
        v = PyFloat_FromDouble(val.value<double>());
    } else if (type == QMetaType::QString) {
        v = PyString_FromString(qPrintable(val.value<QString>()));
    } else if (type == QMetaType::Bool) {
        bool b = val.value<bool>();
        v = b ? Py_True : Py_False;
    }
    $input = v;
}

// QList<DATA_TYPE>

%define %QList_typemapsPtr(DATA_TYPE)

%typemap(out) QList<DATA_TYPE> {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0 ; it != end; ++it, ++i)  {
        PyObject* obj = SWIG_NewPointerObj((*it), $descriptor(DATA_TYPE), 0|0);
        PyList_SET_ITEM($result, i, obj);
    }
}

%typemap(directorin) QList<DATA_TYPE> {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0 ; it != end; ++it, ++i)  {
        PyObject* obj = SWIG_NewPointerObj((*it), $descriptor(DATA_TYPE), 0|0);
        PyList_SET_ITEM(list, i, obj);
    }
    $input = list;
}

%enddef // %QList_typemapsPtr()

%QList_typemapsPtr(dtkCorePlugin *)

%define %QList_typemaps(DATA_TYPE)

%typemap(out) QList<DATA_TYPE> {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0 ; it != end; ++it, ++i)  {
        DATA_TYPE *newItem = new DATA_TYPE(*it);
        PyObject* obj = SWIG_NewPointerObj(newItem, $descriptor(DATA_TYPE*), 0|0);
        PyList_SET_ITEM($result, i, obj);
    }
}

%typemap(directorin) QList<DATA_TYPE> {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0 ; it != end; ++it, ++i)  {
        DATA_TYPE *newItem = new DATA_TYPE(*it);
        PyObject* obj = SWIG_NewPointerObj(newItem, $descriptor(DATA_TYPE*), 0|0);
        PyList_SET_ITEM(list, i, obj);
    }
    $input = list;
}

%enddef // %QList_typemaps()

// QStringList

%typemap(out) QStringList {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject *st = PyString_FromString((*it).toUtf8().constData());
        PyList_SET_ITEM($result, i, st);
    }
}

%typemap(out) const QStringList& {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject *st = PyString_FromString((*it).toUtf8().constData());
        PyList_SET_ITEM($result, i, st);
    }
}

%typemap(directorin) QStringList {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject *st = PyString_FromString((*it).toUtf8().constData());
        PyList_SET_ITEM(list, i, st);
    }
    $input = list;
}

%typemap(directorin) const QStringList& {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject *st = PyString_FromString((*it).toUtf8().constData());
        PyList_SET_ITEM(list, i, st);
    }
    $input = list;
}

// QList<long>

%typemap(out) QList<long> {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject* v = PyInt_FromLong(*it);
        PyList_SET_ITEM($result, i, v);
    }
}

%typemap(out) const QList<long>& {
    $result = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject* v = PyInt_FromLong(*it);
        PyList_SET_ITEM($result, i, v);
    }
}

%typemap(directorin) QList<long> {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject* v = PyInt_FromLong(*it);
        PyList_SET_ITEM(list, i, v);
    }
    $input = list;
}

%typemap(directorin) const QList<long>& {
    PyObject *list = PyList_New($1.size());
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(int i = 0; it != end; ++it, ++i) {
        PyObject* v = PyInt_FromLong(*it);
        PyList_SET_ITEM(list, i, v);
    }
    $input = list;
}

// QMap<long, QVariant>

%typemap(out) QMap<long, QVariant> {
    $result = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyInt_FromLong(it.key());
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem($result, k, v);
    }
}

%typemap(out) const QMap<long, QVariant>& {
    $result = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyInt_FromLong(it.key());
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem($result, k, v);
    }
}

%typemap(directorin) QMap<long, QVariant> {
    PyObject *map = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyInt_FromLong(it.key());
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem(map, k, v);
    }
    $input = map;
}

%typemap(directorin) const QMap<long, QVariant>& {
    PyObject *map = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyInt_FromLong(it.key());
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem(map, k, v);
    }
    $input = map;
}

// QMap<QString, QVariant>

%typemap(out) QMap<QString, QVariant> {
    $result = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyString_FromString(qPrintable(it.key()));
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem($result, k, v);
    }
}

%typemap(out) const QMap<QString, QVariant>& {
    $result = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyString_FromString(qPrintable(it.key()));
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem($result, k, v);
    }
}

%typemap(directorin) QMap<QString, QVariant> {
    PyObject *map = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyString_FromString(qPrintable(it.key()));
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem(map, k, v);
    }
    $input = map;
}

%typemap(directorin) const QMap<QString, QVariant>& {
    PyObject *map = PyDict_New();
    PyObject *k;
    PyObject *v;
    auto it  = $1.cbegin();
    auto end = $1.cend();
    for(; it != end; ++it) {
        k = PyString_FromString(qPrintable(it.key()));
        QVariant val = it.value();
        int type = val.type();
        if (type == QMetaType::Int ||
            type == QMetaType::UInt ||
            type == QMetaType::Long ||
            type == QMetaType::ULong ||
            type == QMetaType::LongLong ||
            type == QMetaType::ULongLong) {
            v = PyInt_FromLong(val.value<long>());
        } else if (type == QMetaType::Float ||
                   type == QMetaType::Double) {
            v = PyFloat_FromDouble(val.value<double>());
        } else if (type == QMetaType::QString) {
            v = PyString_FromString(qPrintable(val.value<QString>()));
        } else if (type == QMetaType::Bool) {
            bool b = val.value<bool>();
            v = b ? Py_True : Py_False;
        }
        PyDict_SetItem(map, k, v);
    }
    $input = map;
}

// QPair

template <class T1, class T2> class QPair
{
public:
    T1 first;
    T2 second;
};

%define %QPair_typemaps(DATA_TYPE_1, DATA_TYPE_2)

%typemap(out) QPair<DATA_TYPE_1, DATA_TYPE_2> {
    $result = PyTuple_New(2);
    PyObject* obj1 = SWIG_NewPointerObj(*$1.first, $descriptor(DATA_TYPE_1), 0|0);
    PyObject* obj2 = SWIG_NewPointerObj(*$1.second, $descriptor(DATA_TYPE_2), 0|0);
    PyTuple_SET_ITEM($result, 0, obj1);
    PyTuple_SET_ITEM($result, 1, obj2);
}

%enddef // %QPair_typemaps()

%template(QPairStrStrList) QPair<QString, QStringList>;

%QPair_typemaps(QString, QStringList)

#elif SWIGTCL

// Tcl -> C++

%typemap(in) QString {
    $1 = QString(Tcl_GetString($input));
}

%typemap(in) const QString& {
    char *t = Tcl_GetString($input);
    $1 = new QString(t);
}

// C++ -> Tcl

%typemap(out) QString {
    Tcl_SetStringObj($result, $1.toUtf8().constData(), $1.size());
}

%typemap(out) const QString& {
    Tcl_SetStringObj($result, $1.toUtf8().constData(), $1.size());
}

#elif SWIGCSHARP

// /////////////////////////////////////////////////////////////////
// C#
// /////////////////////////////////////////////////////////////////

%typemap(ctype) QString "char *"
%typemap(imtype) QString "string"
%typemap(cstype) QString "string"
%typemap(csdirectorin) QString "$iminput"
%typemap(csdirectorout) QString "$cscall"

%typemap(in, canthrow=1) QString {
    if (!$input) {
        SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
        return $null;
    }

    $1 = QString($input);
}

%typemap(out) QString {
    $result = SWIG_csharp_string_callback($1.toUtf8().constData());
}

%typemap(directorout, canthrow=1) QString {
    if (!$input) {
        SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
        return $null;
    }

    $result = string($input);
}

%typemap(directorin) QString {
    $input = SWIG_csharp_string_callback($1.toUtf8().constData());
}

%typemap(csin) QString "$csinput"

%typemap(csout, excode=SWIGEXCODE) QString {
    string ret = $imcall;$excode;
    return ret;
}

%typemap(csvarin, excode=SWIGEXCODE2) QString {
    set {
      $imcall;$excode
    }
}

%typemap(csvarout, excode=SWIGEXCODE2) QString {
    get {
      string ret = $imcall;$excode
      return ret;
    }
}

%typemap(typecheck) QString = char *;

%typemap(throws, canthrow=1) QString {
    SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, $1.c_str());
    return $null;
}

%typemap(ctype) const QString & "char *"
%typemap(imtype) const QString & "string"
%typemap(cstype) const QString & "string"
%typemap(csdirectorin) const QString & "$iminput"
%typemap(csdirectorout) const QString & "$cscall"

%typemap(in, canthrow=1) const QString & {
    if (!$input) {
        SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
        return $null;
    }
    QString $1_str($input);
    $1 = &$1_str;
}

%typemap(out) const QString & {
    $result = SWIG_csharp_string_callback($1->toUtf8().constData());
}

%typemap(csin) const QString & "$csinput"

%typemap(csout, excode=SWIGEXCODE) const QString & {
    string ret = $imcall;$excode
    return ret;
}

%typemap(directorout, canthrow=1, warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const QString & {
    if (!$input) {
        SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
        return $null;
   }
   static string $1_str;
   $1_str = $input;
   $result = &$1_str;
}

%typemap(directorin) const QString & {
    $input = SWIG_csharp_string_callback($1.toUtf8().constData());
}

%typemap(csvarin, excode=SWIGEXCODE2) const QString & {
    set {
      $imcall;$excode
    }
}

%typemap(csvarout, excode=SWIGEXCODE2) const QString & {
    get {
        string ret = $imcall;$excode;
        return ret;
    }
}

%typemap(typecheck) const QString & = char *;

%typemap(throws, canthrow=1) const QString & {
    SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, $1.c_str());
    return $null;
}

#endif

//
// dtk_base.i ends here
