#ifndef TEST_CLIENT_HELPER_H
#define TEST_CLIENT_HELPER_H

#include "piclientserver_client.h"
#include "piclientserver_server.h"
#include "piethernet.h"
#include "piliterals.h"
#include "pithread.h"


template<ullong WriteSize = 64_KiB, bool WithPong = false>
class TestClientBase {
public:
	int pongCnt() const { return pong_cnt; }

	int pingCnt() const { return ping_cnt; }

	void ping() {
		const auto data = PIByteArray(WriteSize);
		writeInternal(data);
		ping_cnt++;
	}

protected:
	virtual void writeInternal(const PIByteArray & ba) = 0;

	void readInternal(const PIByteArray & ba) {
		last_read_size = ba.size();
		pong_cnt++;
		if (WithPong) ping();
	}

private:
	int pong_cnt          = 0;
	int ping_cnt          = 0;
	ullong last_read_size = 0;
};


template<bool WithConnectPing = false, bool WithPong = false, ullong WriteSize = 64_KiB>
class TestServerClient
	: public PIClientServer::ServerClient
	, public TestClientBase<WriteSize, WithPong> {
	using Base = TestClientBase<WriteSize, WithPong>;

public:
	~TestServerClient() {
		close();
		stopAndWait();
	}

private:
	void readed(PIByteArray data) override { Base::readInternal(data); }

	void connected() override {
		if (WithConnectPing) {
			Base::ping();
		}
	}

	void writeInternal(const PIByteArray & ba) override { write(ba); }
};


template<bool WithConnectPing = false, bool WithPong = false, ullong WriteSize = 64_KiB>
class TestClient
	: public PIClientServer::Client
	, public TestClientBase<WriteSize, WithPong> {
	using Base = TestClientBase<WriteSize, WithPong>;

public:
	~TestClient() {
		close();
		stopAndWait();
	}

private:
	void readed(PIByteArray data) override { Base::readInternal(data); }

	void connected() override {
		if (WithConnectPing) {
			Base::ping();
		}
	}

	void writeInternal(const PIByteArray & ba) override { write(ba); }
};

#endif // TEST_CLIENT_HELPER_H
