/*
    PIQt - PIP <-> Qt convertions

    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PIQT_MACROS_H
#define PIQT_MACROS_H

#include "qad_piqt_export.h"

#include <QObject>
#include <piobject.h>


/// connect PIP event "event" of object "src" directly to Qt slot "slot" of object "tgt"
/// e.g. PIQCONNECT(&pip_obj, someEvent, &qt_obj, someSlot)
#define PIQCONNECT(src, event, tgt, slot) \
	PIQt::piqConnect(src, #event, &(src)->__stat_eh_##event##__, tgt, &decltype(PIQt::removePtr(tgt))::slot);

/// connect PIP event "event" of object "src" to Qt slot "slot" of object "tgt" via Qt::QueuedConnection
/// Note! All argument types must be registered in Qt meta-system!
/// e.g. PIQCONNECT_QUEUED(&pip_obj, someEvent, &qt_obj, someSlot)
#define PIQCONNECT_QUEUED(src, event, tgt, slot) PIQt::piqConnectQ(src, #event, &(src)->__stat_eh_##event##__, tgt, #slot);


/// connect Qt signal "sig" of object "src" directly to PIP event handler "handler" of object "tgt"
/// e.g. QPICONNECT(&qt_obj, someSignal, &pip_obj, someHandler)
/// Returns QMetaObject::Connection
#define QPICONNECT(src, sig, tgt, handler) \
	PIQt::qpiConnect(src, &decltype(PIQt::removePtr(src))::sig, tgt, &(tgt)->__stat_eh_##handler##__);


namespace PIQt {

template<typename T>
T removePtr(T *) {}
template<typename T>
QArgument<T> qargument(const T & v) {
	return QArgument<T>(
#if QT_VERSION_MAJOR <= 5
		QMetaType::typeName(qMetaTypeId<T>())
#else
		QMetaType::fromType<T>().name()
#endif
			,
		v);
}

template<typename SR, typename O, typename... ARGS>
PIObject::Connection piqConnect(PIObject * source, const char * event, void (*func)(void *, ARGS...), O * target, SR (O::*slot)(ARGS...)) {
	PIObject::Connection ret =
		PIObject::piConnectLS(source,
							  PIStringAscii(event),
							  PIObject::__newFunctor(func, [target, slot](ARGS... args) { (target->*slot)(args...); }),
							  LOCATION);
	QObject::connect(target, &QObject::destroyed, [ret]() { ret.disconnect(); });
	return ret;
}

template<typename... ARGS>
PIObject::Connection
piqConnectQ(PIObject * source, const char * event, void (*func)(void *, ARGS...), QObject * target, const char * slot) {
	PIObject::Connection ret =
		PIObject::piConnectLS(source,
							  PIStringAscii(event),
							  PIObject::__newFunctor(func,
													 [target, slot](ARGS... args) {
														 QMetaObject::invokeMethod(target, slot, Qt::QueuedConnection, qargument(args)...);
													 }),
							  LOCATION);
	QObject::connect(target, &QObject::destroyed, [ret]() { ret.disconnect(); });
	return ret;
}

template<typename SR, typename O, typename... ARGS>
QMetaObject::Connection qpiConnect(O * source, SR (O::*signal)(ARGS...), PIObject * target, void (*handler)(void *, ARGS...)) {
	auto ret = QObject::connect(source, signal, source, [target, handler](ARGS... args) { handler(target, args...); });
	CONNECTL(target, deleted, [ret](PIObject *) { QObject::disconnect(ret); });
	return ret;
}

} // namespace PIQt

#endif // PIQT_MACROS_H
