#include "dispatcherclient.h"

#include "picloudtcp.h"


DispatcherClient::DispatcherClient(PIEthernet * eth_, int id)
	: authorised(false)
	, eth(eth_)
	, streampacker(eth_)
	, tcp(&streampacker)
	, client_id(id) {
	eth->setName(PIString::fromNumber(id));
	CONNECTU(&streampacker, packetReceiveEvent, this, readed);
	CONNECTU(eth, disconnected, this, disconnected);
	piCoutObj << "client connected" << client_id << eth->sendAddress();
}


void DispatcherClient::start() {
	eth->startThreadedRead();
}


DispatcherClient::~DispatcherClient() {
	PIMutexLocker send_lock(mutex_send);
	piDeleteSafety(eth);
}


PIString DispatcherClient::address() {
	return eth->path();
}


void DispatcherClient::close() {
	eth->stopAndWait();
}


void DispatcherClient::stop() {
	eth->stop();
}


void DispatcherClient::sendConnected(uint client_id) {
	piCoutObj << "sendConnected" << client_id;
	PIMutexLocker send_lock(mutex_send);
	tcp.sendConnected(client_id);
}


void DispatcherClient::sendDisconnected(uint client_id) {
	piCoutObj << "sendDisconnected" << client_id;
	PIMutexLocker send_lock(mutex_send);
	tcp.sendDisconnected(client_id);
}


void DispatcherClient::sendData(const PIByteArray & data) {
	if (tcp.role() == PICloud::TCP::Client) {
		PIMutexLocker send_lock(mutex_send);
		tcp.sendData(data);
	} else
		piCoutObj << "error sendData, invalid role";
}


void DispatcherClient::sendDataToClient(const PIByteArray & data, uint client_id) {
	if (tcp.role() == PICloud::TCP::Server) {
		PIMutexLocker send_lock(mutex_send);
		tcp.sendData(data, client_id);
	} else
		piCoutObj << "error sendDataToClient, invalid role";
}


void DispatcherClient::authorise(bool ok) {
	authorised = ok;
}


void DispatcherClient::disconnected(bool withError) {
	piCoutObj << "client disconnected" << withError << eth->sendAddress();
	disconnectEvent(this);
}


void DispatcherClient::readed(PIByteArray & ba) {
	PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
	//	piCoutObj << "readed" << hdr.first << hdr.second;
	if (hdr.first == PICloud::TCP::InvalidType) {
		piCoutObj << "invalid message";
		disconnected(true);
		return;
	}
	if (authorised) {
		if (hdr.second == tcp.role()) {
			switch (hdr.first) {
			case PICloud::TCP::Connect: piCoutObj << "PICloud::TCP::Connect"; return;
			case PICloud::TCP::Disconnect:
				piCoutObj << "PICloud::TCP::Disconnect";
				disconnected(false);
				return;
			case PICloud::TCP::Data:
				// piCoutObj << "TCP::Data" << tcp.role();
				if (tcp.role() == PICloud::TCP::Client) {
					if (tcp.canParseData(ba))
						dataReaded(ba);
					else
						piCoutObj << "invalid data from client";
				}
				if (tcp.role() == PICloud::TCP::Server) {
					PIPair<uint, PIByteArray> dp = tcp.parseDataServer(ba);
					if (!dp.second.isEmpty())
						dataReadedServer(dp.first, dp.second);
					else
						piCoutObj << "invalid data from server";
				}
				return;
			case PICloud::TCP::Ping: pingReceived(); return;
			default:
				piCoutObj << "unknown data";
				// disconnected(true);
				return;
			}
		} else
			piCoutObj << "invalid role";
	} else {
		switch (hdr.first) {
		case PICloud::TCP::Connect: {
			tcp.setRole(hdr.second);
			PIByteArray sn = tcp.parseConnect_d(ba);
			if (hdr.second == PICloud::TCP::Server) registerServer(sn, this);
			if (hdr.second == PICloud::TCP::Client) registerClient(sn, this);
			return;
		}
		case PICloud::TCP::Disconnect:
			piCoutObj << "unauthorised PICloud::TCP::Disconnect";
			disconnected(false);
			return;
		default:
			piCoutObj << "authorised invalid message";
			disconnected(true);
			return;
		}
	}
}
