#include "client_messages.h"
#include "notifications.h"
#include "SH_base.h"
#include "SH_network_types.h"
#include <QDir>
#include <QTimer>
#include <QDebug>
#include <QTimerEvent>
#include <qad_locations.h>
#include <piqt.h>
#include <pistreampacker.h>
#include "ccm_SHS_shared.h"
#ifdef ANDROID
#  include "client.h"
#endif


RemoteClientMessages::RemoteClientMessages(): QObject(), PIObject(), channel(true), peth(PIEthernet::TCP_Client), settings("SHS", "Pult") {
	channel.setID(generateID());
	CONNECTU_QUEUED(&channel, disconnected, this, disconnectedP, this);
	CONNECTU_QUEUED(&channel, connected, this, connectedP, this);
	CONNECTU_QUEUED(&channel, dataReceived, this, receiveEvent, this);
	CONNECTU_QUEUED(&channel, addressesChangedEvent, this, addressesChangedEvent, this);
	//CONNECTU(&channel, disconnected, this, disconnectedPD);
	server_info = PacketServerInfo::fromByteArray(Q2PIByteArray(settings.value("messages.last_server").toByteArray()));
	if (server_info.isValid())
		connect();
	NOTIFICATIONS->init();
#ifdef ANDROID
	interface.setReadAddress("127.0.0.1", SHNetworkTypes::interfacePort + 1);
	interface.setSendAddress("127.0.0.1", SHNetworkTypes::interfacePort);
	interface.startThreadedRead();
	CONNECTU(&interface, threadedReadEvent, this, interfaceReceived);
	CONNECTU_QUEUED(this, interfaceReceivedE, this, interfaceReceivedQ, this);
	timer = startTimer(500);
	requestLang();
#else
	timer = startTimer(50);
#endif
	timer_10s = startTimer(10000);
	QObject::connect(&qeth, SIGNAL(disconnected()), this, SLOT(disconn()));
}


RemoteClientMessages::~RemoteClientMessages() {
#ifdef ANDROID
	interface.stopThreadedRead();
#endif
	killTimer(timer);
	killTimer(timer_10s);
	channel.stop();
}


void RemoteClientMessages::connect() {
	if (channel.isConnecting() || channel.isConnected()) return;
	if (server_info.connect_address.isEmpty()) return;
	//piCoutObj << "connect to" << server_info.connect_address << "," << channel.isConnecting() << channel.isConnected();
	//emit tcpConnecting();
	channel.dataStop();
	channel.connectToServer(server_info);
}


void RemoteClientMessages::disconnect() {
	//disconnecting = true;
	QTimer::singleShot(1000, this, SLOT(connect()));
}


void RemoteClientMessages::timerEvent(QTimerEvent * e) {
	if (e) {
		if (e->timerId() == timer) {
			maybeCallQueuedEvents();
		}
		if (e->timerId() == timer_10s) {
			connect();
		}
	}
}


void RemoteClientMessages::connectedP() {
	//piCoutObj << "connected";
	//emit tcpConnected(server_info);
	settings.setValue("messages.last_server", PI2QByteArray(server_info.toByteArray()));
	PIByteArray ba = SHNetworkTypes::makeHeader(SHNetworkTypes::Identification);
	PacketIdentification p = PacketIdentification::makeLocal(SHServer::RoleMessages, SHS_NETWORK_VERSION, SHS_UISYNC_VERSION);
	ba << p;
	channel.dataSend(ba);

	emit status(tr("Connected to ") + "\"" + PI2QString(server_info.name) + "\" (" + PI2QString(server_info.connect_address) + ")");

	/*ret = getsockopt(sock, IPPROTO_IP, IP_MTU, &sv, (socklen_t*)sizeof(sv));
	qDebug() << "opt IP_MTU" << ret << sv << errorString();
	sv = 0;
	ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &sv, (socklen_t*)sizeof(sv));
	qDebug() << "opt TCP_KEEPCNT" << ret << sv << errorString();
	sv = 0;
	ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &sv, (socklen_t*)sizeof(sv));
	qDebug() << "opt TCP_KEEPIDLE" << ret << sv << errorString();*/

}


void RemoteClientMessages::disconnectedP() {
	//piCoutObj << "disconnected";
	//connect();

	emit status(tr("Idle"));
}


void RemoteClientMessages::disconnectedPD() {
	/*QMetaObject::invokeMethod(this, "connect", Qt::QueuedConnection);
	peth.close();
	peth.connect(server_info.connect_address, SHNetworkTypes::clientPort, false);*/
	//QMetaObject::invokeMethod(NOTIFICATIONS, "notify", Qt::QueuedConnection, Q_ARG(QString, PI2QString("D: " + errorString())));
}


void RemoteClientMessages::addressesChangedEvent() {
	connect();
}


void RemoteClientMessages::messageReceived(const PacketMessage & m) {
	qDebug() << "msg:" << PI2QString(m.text);
	NOTIFICATIONS->notify(PI2QString(m.text));
}


void RemoteClientMessages::requestLang() {
#ifdef ANDROID
	PIByteArray ba;
	ba << int(3);
	interface.send(ba);
	//NOTIFICATIONS->notify("request");
#endif
}


void RemoteClientMessages::disconn() {
	//NOTIFICATIONS->notify("QD: " + qeth.errorString());
	qeth.connectToHost(PI2QString(server_info.connect_address), SHNetworkTypes::clientPort);
}


#ifdef ANDROID
void RemoteClientMessages::interfaceReceived(THREADED_READ_TYPE data, ssize_t size) {
	interfaceReceivedE(PIByteArray(data, size));
}


void RemoteClientMessages::interfaceReceivedQ(PIByteArray ba) {
	int type = 0;
	ba >> type;
	switch (type) {
	case 1: {
		PacketServerInfo si = PacketServerInfo::fromByteArray(ba);
		//qDebug() << "connected to server" << PI2QString(si.name);
		connectedToServer(si);
		} break;
	case 2: {
		PIString lang;
		ba >> lang;
		QAD::loadTranslations(PI2QString(lang));
		} break;
	default: break;
	}
}
#endif


void RemoteClientMessages::receiveEvent(PIByteArray data) {
	PacketHeader hdr = SHNetworkTypes::takeHeader(data);
	if (hdr.type < 0) return;
	//qDebug() << "packet type" << type;
	switch ((SHNetworkTypes::PacketType)hdr.type) {
	case SHNetworkTypes::Message: {
		PacketMessage msg;
		data >> msg;
		messageReceived(msg);
		} break;
	default: break;
	}
}


void RemoteClientMessages::connectedToServer(const PacketServerInfo & si) {
	server_info = si;
	channel.dataStop();
	if (server_info.connect_address.isEmpty()) {
		return;
	}
	connect();
	/*peth.close();
	peth.connect(server_info.connect_address, SHNetworkTypes::clientPort, false);
	qeth.disconnectFromHost();
	qeth.connectToHost(PI2QString(server_info.connect_address), SHNetworkTypes::clientPort);*/
}
