//! \~\file picloudclient.h
//! \~\ingroup Cloud
//! \~\brief
//! \~english Client-side PICloud device for one named server
//! \~russian Клиентское устройство PICloud для одного именованного сервера
/*
    PIP - Platform Independent Primitives
    PICloud Client
    Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 PICLOUDCLIENT_H
#define PICLOUDCLIENT_H

#include "picloudbase.h"
#include "piconditionvar.h"

//! \~\ingroup Cloud
//! \~\brief
//! \~english %PIIODevice implementation for a logical PICloud client.
//! \~russian Реализация %PIIODevice для логического клиента PICloud.
class PIP_CLOUD_EXPORT PICloudClient
	: public PIIODevice
	, public PICloudBase {
	PIIODEVICE(PICloudClient, "");

public:
	//! \~english Constructs a client for transport endpoint "path" and mode "mode".
	//! \~russian Создает клиент для транспортной точки "path" и режима "mode".
	explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);

	//! \~english Destroys the client and closes the underlying transport.
	//! \~russian Уничтожает клиент и закрывает нижележащий транспорт.
	virtual ~PICloudClient();


	//! \~english Sets the logical server name used during the PICloud handshake.
	//! \~russian Устанавливает логическое имя сервера, используемое при рукопожатии PICloud.
	void setServerName(const PIString & server_name);

	//! \~english Enables or disables automatic reconnect of the underlying TCP link.
	//! \~russian Включает или выключает автоматическое переподключение нижележащего TCP-соединения.
	void setKeepConnection(bool on);

	//! \~english Returns whether the logical PICloud session is established.
	//! \~russian Возвращает, установлена ли логическая сессия PICloud.
	bool isConnected() const { return is_connected; }

	//! \~english Returns the number of payload bytes buffered for \a read().
	//! \~russian Возвращает количество байтов полезной нагрузки, буферизованных для \a read().
	ssize_t bytesAvailable() const override { return buff.size(); }

	//! \~english Interrupts pending connection and read waits.
	//! \~russian Прерывает ожидающие операции подключения и чтения.
	void interrupt() override;


	//! \events
	//! \{

	//! \fn void connected()
	//! \~english Raised after the logical PICloud session becomes ready.
	//! \~russian Вызывается после того, как логическая сессия PICloud готова к работе.
	EVENT(connected);

	//! \fn void disconnected()
	//! \~english Raised when the logical PICloud session is closed.
	//! \~russian Вызывается при закрытии логической сессии PICloud.
	EVENT(disconnected);

	//! \}

protected:
	bool openDevice() override;
	bool closeDevice() override;
	ssize_t readDevice(void * read_to, ssize_t max_size) override;
	ssize_t writeDevice(const void * data, ssize_t size) override;
	DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }

private:
	EVENT_HANDLER1(void, _readed, PIByteArray &, data);
	void internalDisconnect();

	PIByteArray buff;
	PIMutex mutex_buff;
	PIMutex mutex_connect;
	PIConditionVariable cond_buff;
	PIConditionVariable cond_connect;
	std::atomic_bool is_connected;
	std::atomic_bool is_deleted;
};

#endif // PICLOUDCLIENT_H
