#ifndef SH_CLIENT_CHANNEL_H
#define SH_CLIENT_CHANNEL_H

#include "SH_multicast.h"
#include "SH_stream_tcp.h"
#include "SH_network_types.h"
#include <piethernet.h>
#include <picloudclient.h>


class SHClientChannel: public SHMulticast {
	PIOBJECT_SUBCLASS(SHClientChannel, SHMulticast)
public:
	SHClientChannel(bool mc_send_only = false);
	~SHClientChannel();

	void setID(uint id);

	void start();
	void stop();
	void dataStop(); // TCP and Cloud
	void connectAs(const SHClientChannel & other);
	void connectToServer(const QString & addr);
	void connectToServer(const PacketServerInfo & info);
	void connectToServer(const ServerAddress & addr);
	void dataSend(const PIByteArray & data); // TCP or Cloud
	void setReopenEnabled(bool on);

	ServerAddress address() const {return current_address;}
	bool isConnecting() const {return eth_tcp.isConnecting();}
	bool isConnected() const {return eth_tcp.isConnected() || cloud_client.isConnected();}
	bool isWaiting() const {return waiting;}
	PIStringList addresses() const {return addresses_;}

	EVENT1(disconnected, int, channel)
	EVENT1(connected, int, channel)
	EVENT1(dataReceived, PIByteArray, data)
	EVENT1(broadcastReceiveEvent, PIByteArray, data)
	EVENT(addressesChangedEvent)

	const SHStreamTCP & streamTCP() const {return packer;}

protected:
	EVENT_HANDLER(void, tcpDisconnectedH);
	EVENT_HANDLER(void, cloudDisconnectedH);
	EVENT_HANDLER(void, tcpConnectedH);
	EVENT_HANDLER(void, cloudConnectedH);

	virtual void broadcastReceived(PIByteArray data) {}

private:
	void addressesChanged() override;
	void receivedSH(PIByteArray data, uint id) override;
	EVENT_HANDLER1(void, packetReceivedSH, PIByteArray, data);
	EVENT_HANDLER2(void, timerRequest, void*, __d, int, delim);
	double keepAliveElapsed();
	void resetKeepAliveElapsed();

	void tcpSend(const PIByteArray & data);
	void cloudSend(const PIByteArray & data);
	void broadcastSend(const PIByteArray & data);

	void tcpConnect(const PINetworkAddress & a);
	void tcpConnect(const PIString & a, ushort p) {tcpConnect(PINetworkAddress(a, p));}
	void tcpStop();
	void cloudSetServerAddress(const PIString & a);
	void cloudSetServerName(const PIString & n);
	void cloudStart();
	void cloudStop();
	PIString cloudServerAddress() const;
	PIString cloudServerName() const;

	std::atomic_bool waiting, ignore_disconnect;
	PIStringList addresses_;
	SHStreamTCP packer;
	PITimer timer_req;
	PITimeMeasurer tm_ka;
	PIMutex mutex_tcp_send, mutex_ka;
	SHNetworkTypes::ChannelType active_channel;
	ServerAddress current_address;

	PIEthernet eth_tcp;
	PICloudClient cloud_client;

};

#endif // SH_CLIENT_CHANNEL_H
