#include "picli.h"
#include "picloudclient.h"
#include "picloudserver.h"
#include "pikbdlistener.h"
#include "piliterals_time.h"
#include "pitimer.h"

int main(int argc, char * argv[]) {
	PIByteArray rnd;
	rnd.resize(1024 * 1024, 'x');
	PICLI cli(argc, argv);
	PITimer tm;
	cli.addArgument("connect", true);
	cli.addArgument("name", true);
	PICloudClient c("127.0.0.1:10101");
	//	c.setReopenEnabled(true);
	PICloudServer s("127.0.0.1:10101");
	auto clients = new PIVector<PICloudServer::Client *>();
	CONNECTL(&tm, tickEvent, ([&](int) {
		if (c.isConnected()) {
			PIString str = "ping";
			piCout << "[Client] send:" << str;
			c.write(str.toByteArray());
		}
		if (s.isThreadedRead()) {
			for (auto cl: *clients) {
				if (cl->isOpened()) {
					PIString str = "ping_S";
					piCout << "[Server] send to" << cl << ":" << str;
					cl->write(str.toByteArray());
				}
			}
		}
	}));
	CONNECTL(&c, threadedReadEvent, ([&](const uchar * readed, ssize_t size) {
		PIByteArray ba(readed, size);
		if (size < 1024) {
			PIString str = PIString::fromUTF8(ba);
			piCout << "[Client] data:" << str;
			if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
		} else
			piCout << "[Client] blob:" << size;
	}));
	CONNECTL(&c, connected, ([]() { piCout << "connected"; }));
	CONNECTL(&c, disconnected, ([]() { piCout << "disconnected"; }));
	CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl) {
		piCout << "[Server] new client:" << cl;
		clients->append(cl);
		CONNECTL(cl, threadedReadEvent, ([cl, &rnd](const uchar * readed, ssize_t size) {
					 PIByteArray ba(readed, size);
					 PIString str = PIString::fromUTF8(ba);
					 piCout << "[Server] data from" << cl << ":" << str;
					 if (str == "ping") {
						 cl->write(PIString("pong").toByteArray());
						 cl->write(rnd);
					 }
				 }));
		CONNECTL(cl, closed, ([&clients, cl]() {
					 piCout << "[Server] client closed ..." << cl;
					 cl->stop();
					 clients->removeAll(cl);
					 piCout << "[Server] client closed ok" << cl;
					 // cl->deleteLater();
				 }));
		cl->startThreadedRead();
	}));
	if (cli.hasArgument("name")) s.setServerName(cli.argumentValue("name"));
	if (cli.hasArgument("connect")) {
		c.setServerName(cli.argumentValue("connect"));
		c.startThreadedRead();
	} else {
		s.startThreadedRead();
	}
	tm.start(1_Hz);
	PIKbdListener ls;
	ls.enableExitCapture(PIKbdListener::F10);
	ls.start();
	WAIT_FOR_EXIT
	return 0;
}
