/* Copyright (C) 2005 Martin Koegler
 * Copyright (C) 2010 TigerVNC Team
 * Copyright (C) 2015-2024 m-privacy GmbH
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 */

#ifndef __RDR_MULTIOUTSTREAM_H__
#define __RDR_MULTIOUTSTREAM_H__

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <queue>

#include <rdr/OutStream.h>
#include <rdr/MultiStream.h>
#include <rfb/Configuration.h>

#define MULTIKEY 2

namespace rdr {

	typedef struct {
		rdr::U8* data;
		size_t len;
	} queueData;

	class MultiOutStream : public OutStream {
	public:
		MultiOutStream(OutStream* out);
		virtual ~MultiOutStream();

		void flush(int key=0, QPrio prio=QPRIOMEDIUM, bool wait=false);
		void writeBuffer(const U8* buf, const U32 len, const U8 streamId, bool flush=true);
		static THREAD_FUNC outWriterThread(void* myself);
		void setBigMulti();
		static void setMultiMaxVNCChunk(bool small);
		inline void setMultiPart() {multiPartSupport = true;}
		inline void setRemoteSupportsPulseZstd(bool value) {remoteSupportsPulseZstd = value;}
		inline bool getMultiPartSupport () { return multiPartSupport; }
		bool sendSignal(U16 sigId, const void* data = NULL, U16 dataLength = 0, int key=0, QPrio prio=QPRIOMEDIUM);
		bool submitQueueBuffer(struct queueBuffer * firstBuffer, struct queueBuffer * lastBuffer, int key=0, QPrio prio=QPRIOMEDIUM);
		void printBufferUsage();
		static time_t lastAudioTime;
		static rfb::IntParameter videoBoostDelay;
		static rfb::IntParameter multiMaxVNCChunk;
		static rfb::IntParameter multiMaxVNCChunkSmall;
		static rfb::IntParameter pingThresh;
		static rfb::IntParameter pulseZstdLevel;
		static rfb::BoolParameter pulseZstdEnabled;

	protected:
		void check(size_t length, int key=0, QPrio prio=QPRIOMEDIUM);
		virtual void overrun(size_t needed, int key=0, QPrio prio=QPRIOMEDIUM);
		void cork(bool enable, int key=0, QPrio prio=QPRIOMEDIUM) { out->cork(enable, MULTIKEY, prio); }
		void writeU8(U8 u, int key=0, QPrio prio=QPRIOMEDIUM);
		void writeU16(U16 u, int key=0, QPrio prio=QPRIOMEDIUM);
		void writeU32(U32 u, int key=0, QPrio prio=QPRIOMEDIUM);
		void writeS8(S8 s) {writeU8((U8)s);}
		void writeS16(S16 s) {writeU16((U16)s);}
		void writeS32(S32 s) {writeU32((U32)s);}

		virtual void pad(size_t bytes, int key=0, QPrio prio=QPRIOMEDIUM);
		virtual void writeBytes(const void* data, size_t numBytes, int key=0, QPrio prio=QPRIOMEDIUM);
		void writeOpaque16(U16 u, int key=0, QPrio prio=QPRIOMEDIUM);
		void writeOpaque32(U32 u, int key=0, QPrio prio=QPRIOMEDIUM);

	private:
		OutStream* out;
		void copyHeader(struct queueBuffer * buffer, const U16 len, const U8 streamId=VNC_STREAM_ID);
		unsigned int videoBoostDelayInt;
		U32 lastPing;
		bool multiPartSupport;
		bool remoteSupportsPulseZstd;
		U64 pulseZstdSentRaw;
		U64 pulseZstdSentCompressed;
	};
};

#endif
