//! \~\file piclientserver_client_base.h
//! \~\ingroup ClientServer
//! \brief
//! \~english Base class for client-server communication
//! \~russian Базовый класс для клиент-серверного взаимодействия
//! \details
//! \~english Provides base functionality for client-server communication with diagnostics support.
//! \~russian Обеспечивает базовую функциональность для клиент-серверного взаимодействия с поддержкой диагностики.
/*
    PIP - Platform Independent Primitives
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef piclientserver_client_base_H
#define piclientserver_client_base_H

#include "pidiagnostics.h"
#include "pip_client_server_export.h"
#include "pistreampacker.h"

class PIEthernet;

namespace PIClientServer {

class Server;

//! \~\ingroup ClientServer
//! \~\brief
//! \~english Base class for client and server-side client communication. Provides TCP connection management, diagnostics, and packet
//! streaming capabilities.
//! \~russian Базовый класс для клиентской и серверной коммуникации. Обеспечивает управление TCP-соединением, диагностику и потоковую
//! передачу пакетов.
// template<bool EnableDiagnostics = false>
class PIP_CLIENT_SERVER_EXPORT ClientBase {
	friend class Server;
	NO_COPY_CLASS(ClientBase);

public:
	//! \~english Constructs a disconnected client connection object.
	//! \~russian Создает объект клиентского соединения в отключенном состоянии.
	ClientBase();
	
	//! \~english Destroys the client connection and releases owned resources.
	//! \~russian Уничтожает клиентское соединение и освобождает связанные ресурсы.
	virtual ~ClientBase();

	
	//! \~english Returns the underlying TCP transport object.
	//! \~russian Возвращает базовый объект TCP-транспорта.
	const PIEthernet * getTCP() const { return tcp; }

	//! \~english Closes the connection immediately.
	//! \~russian Немедленно закрывает соединение.
	void close();

	//! \~english Stops the connection workflow and waits until shutdown completes.
	//! \~russian Останавливает работу соединения и ждет полного завершения.
	void stopAndWait();


	//! \~english Sends raw payload bytes through the stream packer.
	//! \~russian Отправляет сырые байты полезной нагрузки через упаковщик потока.
	int write(const void * d, const size_t s);

	//! \~english Sends payload stored in "ba".
	//! \~russian Отправляет полезную нагрузку из "ba".
	int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }


	//! \~english Enables connection diagnostics collection.
	//! \~russian Включает сбор диагностики соединения.
	void enableDiagnostics();

	//! \~english Returns a snapshot of current diagnostics counters.
	//! \~russian Возвращает снимок текущих диагностических счетчиков.
	PIDiagnostics::State diagnostics() const;


	//! \~english Returns how many payload bytes of the current packet are already received (all bytes count passed in \a receivePacketStart()).
	//! \~russian Возвращает, сколько байтов полезной нагрузки текущего пакета уже получено (общее количество передается в \a receivePacketStart()).
	int receivePacketProgress() const;

	//! \~english Returns the current packet framing configuration.
	//! \~russian Возвращает текущую конфигурацию пакетирования.
	const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
	
	//! \~english Returns the current packet framing configuration for modification.
	//! \~russian Возвращает текущую конфигурацию пакетирования для изменения.
	PIStreamPackerConfig & configuration() { return stream.configuration(); }
	
	//! \~english Replaces the packet framing configuration.
	//! \~russian Заменяет конфигурацию пакетирования.
	void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }

protected:
	//! \~english Called when a full payload packet is received.
	//! \~russian Вызывается при получении полного пакета полезной нагрузки.
	virtual void readed(PIByteArray data) {}

	//! \~english Called after the TCP connection becomes active.
	//! \~russian Вызывается после перехода TCP-соединения в активное состояние.
	virtual void connected() {}

	//! \~english Called after the connection is closed.
	//! \~russian Вызывается после закрытия соединения.
	virtual void disconnected() {}

	//! \~english Called when reception of a new packet starts.
	//! \~russian Вызывается при начале приема нового пакета.
	virtual void receivePacketStart(int size) {}

	//! \~english Called when reception of the current packet finishes.
	//! \~russian Вызывается при завершении приема текущего пакета.
	virtual void receivePacketEnd() {}

	void init();

	bool own_tcp               = false;
	std::atomic_bool can_write = {true};
	PIEthernet * tcp           = nullptr;

private:
	void destroy();

	PIStreamPacker stream;
	mutable PIMutex write_mutex;
	PIDiagnostics * diag = nullptr;
};

} // namespace PIClientServer

#endif
