/*! \file pistreampacker.h
 * \ingroup IO-Utils
 * \~\brief
 * \~english Simple packet wrap aroud any PIIODevice
 * \~russian Простая фрагментация пакетов, использует любой PIIODevice
 */
/*
	PIP - Platform Independent Primitives
	Simple packet wrap aroud any PIIODevice
	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 PISTREAMPACKER_H
#define PISTREAMPACKER_H

#include "pip_io_utils_export.h"
#include "piobject.h"
#include "piethutilbase.h"


class PIIODevice;

class PIP_IO_UTILS_EXPORT PIStreamPacker: public PIObject, public PIEthUtilBase {
	PIOBJECT(PIStreamPacker)
public:
	//! Contructs packer and try to assign \"dev\"
	PIStreamPacker(PIIODevice * dev = 0);


	//! Set maximum size of single packet
	void setMaxPacketSize(int max_size) {max_packet_size = max_size;}

	//! Returns maximum size of single packet, default 1400 bytes
	int maxPacketSize() const {return max_packet_size;}


	//! Set packet sinature
	void setPacketSign(ushort sign_) {packet_sign = sign_;}

	//! Returns packet sinature, default 0xAFBE
	ushort packetSign() const {return packet_sign;}


	//! Set receive aggressive optimization. If yes then %PIStreamPacker doesn`t
	//! check every byte in incoming stream but check only begin of each read()
	//! result. Default is \b true.
	void setaAggressiveOptimization(bool yes) {aggressive_optimization = yes;}

	//! Returns aggressive optimization
	bool aggressiveOptimization() const {return aggressive_optimization;}


	bool cryptFragmentationEnabled() const {return crypt_frag;}
	void setCryptFragmentationEnabled(bool on) {crypt_frag = on;}
	int cryptFragmentationSize() const {return crypt_frag_size;}
	void setCryptFragmentationSize(int size_) {crypt_frag_size = size_;}
	bool cryptSizeEnabled() const {return crypt_size;}
	void setCryptSizeEnabled(bool on);

	void clear();


	//! Prepare data for send and raise \a sendRequest() events
	void send(const PIByteArray & data);

	//! Receive data part. If packet is ready, raise \a packetReceiveEvent() event
	//! and \a packetReceived() virtual method
	void received(const PIByteArray & data);

	EVENT_HANDLER2(void, received, const uchar * , readed, ssize_t, size);

	//! Connect \"dev\" \a PIIODevice::threadedReadEvent() event to \a received() handler
	//! and \a sendRequest() event to \"dev\" \a PIIODevice::write() handler
	void assignDevice(PIIODevice * dev);

	EVENT1(packetReceiveEvent, PIByteArray &, data);
	EVENT1(sendRequest, PIByteArray, data);

	//! \handlers
	//! \{

		//! \fn void received(uchar * readed, int size)
		//! \brief Handler to receive data. \a PIIODevice::threadedReadEvent()
		//! can be connected to this handler

	//! \}

	//! \events
	//! \{

		//! \fn void packetReceiveEvent(PIByteArray data)
		//! \brief Raise on packet successfully received

		//! \fn void sendRequest(PIByteArray data)
		//! \brief Raise from \a send() function. This data should
		//! be directly sended to your device. You can
		//! connect this event to \a PIIODevice::write() handler

	//! \}

protected:

	//! Packet successfully received, by default does nothing
	virtual void packetReceived(PIByteArray data) {}

private:
	PIByteArray stream, packet;
	bool crypt_frag, crypt_size, aggressive_optimization;
	int packet_size, crypt_frag_size;
	ushort packet_sign;
	int max_packet_size, size_crypted_size;
	mutable PIMutex prog_s_mutex, prog_r_mutex;

};

#endif // PISTREAMPACKER_H
