#include "qsingleapplication.h"

#include <QDebug>


#define QSA_SHMSIZE 4096
#define QSA_MSGSIZE (QSA_SHMSIZE - sizeof(quint32) - sizeof(quint32))


QSingleApplication::QSingleApplication(const QString & app_name): QThread() {
	shm.setKey(app_name);
	exiting = false;
	first   = !shm.attach();
	if (!first) {
		shm.detach();
		first = !shm.attach();
		if (!first) return;
	}
	shm.create(QSA_SHMSIZE);
	shm.attach();
	shm.lock();
	void * d = shm.data();
	if (d) memset(d, 0, sizeof(quint32));
	shm.unlock();
	start();
	// qDebug() << "start listen";
}


QSingleApplication::~QSingleApplication() {
	if (first) {
		exiting = true;
		quit();
		if (!wait(100)) terminate();
	}
	if (shm.isAttached()) shm.detach();
}


void QSingleApplication::sendMessage(const QByteArray & m) {
	// qDebug() << "send message" << first << shm.isAttached();
	if (first || !shm.isAttached()) return;
	if (m.size() > int(QSA_MSGSIZE)) {
		qDebug() << "[QSingleApplication] Too large message:" << m.size() << ">" << QSA_MSGSIZE;
		return;
	}
	shm.lock();
	quint32 num(0), size = m.size();
	void * d = shm.data();
	if (d) {
		memcpy(&num, d, sizeof(quint32));
		num++;
		memcpy(d, &num, sizeof(quint32));
		memcpy((((char *)d) + sizeof(quint32)), &size, sizeof(quint32));
		memcpy((((char *)d) + sizeof(quint32) + sizeof(quint32)), m.constData(), size);
	}
	shm.unlock();
}


void QSingleApplication::run() {
	quint32 num(0), pnum(0), size(0);
	while (!exiting) {
		shm.lock();
		const void * d = shm.constData();
		if (d) {
			memcpy(&num, d, sizeof(quint32));
			if (pnum != num) {
				pnum = num;
				// qDebug() << "new message" << num;
				memcpy(&size, (((const char *)d) + sizeof(quint32)), sizeof(quint32));
				if (size <= int(QSA_MSGSIZE)) {
					QByteArray msg;
					msg.resize(size);
					memcpy(msg.data(), (((const char *)d) + sizeof(quint32) + sizeof(quint32)), size);
					emit messageReceived(msg);
				} else {
					qDebug() << "[QSingleApplication] Invalid message size:" << size;
				}
			}
		}
		shm.unlock();
		if (exiting) break;
		msleep(10);
	}
}
