//=============================================================================
//
//   File : DccVoiceCodec.cpp
//   Creation date : Sun Aug 26 04:19:36 2001 GMT by Szymon Stefanek
//
//   This file is part of the KVIrc IRC client distribution
//   Copyright (C) 2001-2010 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program 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 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 General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#include "DccVoiceCodec.h"

#include <QImage>
#include <QByteArray>
#include <QBuffer>

DccVoiceCodec::DccVoiceCodec()
    = default;

DccVoiceCodec::~DccVoiceCodec()
    = default;

void DccVoiceCodec::encode(KviDataBuffer *, KviDataBuffer *)
{
}

void DccVoiceCodec::decode(KviDataBuffer *, KviDataBuffer *)
{
}

int DccVoiceCodec::encodedFrameSize()
{
	return 0;
}

int DccVoiceCodec::decodedFrameSize()
{
	return 0;
}

const char * DccVoiceCodec::name()
{
	return m_szName.ptr();
}

DccVoiceNullCodec::DccVoiceNullCodec()
    : DccVoiceCodec()
{
	m_szName = "null (no compression)";
}

DccVoiceNullCodec::~DccVoiceNullCodec()
    = default;

void DccVoiceNullCodec::encode(KviDataBuffer * signal, KviDataBuffer * stream)
{
	if(signal->size() < 1)
		return;
	stream->append(signal->data(), signal->size());
	signal->resize(0);
}

void DccVoiceNullCodec::decode(KviDataBuffer * stream, KviDataBuffer * signal)
{
	if(stream->size() < 1)
		return;
	signal->append(stream->data(), stream->size());

	stream->resize(0);
}

int DccVoiceNullCodec::encodedFrameSize()
{
	return 1024;
}

int DccVoiceNullCodec::decodedFrameSize()
{
	return 1024;
}

DccVideoCodec::DccVideoCodec()
    = default;

DccVideoCodec::~DccVideoCodec()
    = default;

void DccVideoCodec::encodeVideo(KviDataBuffer *, KviDataBuffer *)
{
}

void DccVideoCodec::encodeText(KviDataBuffer *, KviDataBuffer *)
{
}

void DccVideoCodec::decode(KviDataBuffer *, KviDataBuffer *, KviDataBuffer *)
{
}

int DccVideoCodec::encodedFrameSize()
{
	return 0;
}

int DccVideoCodec::decodedFrameSize()
{
	return 0;
}

const char * DccVideoCodec::name()
{
	return m_szName.ptr();
}

DccVideoSJpegCodec::DccVideoSJpegCodec()
    : DccVideoCodec()
{
	m_szName = "sjpeg";
}

DccVideoSJpegCodec::~DccVideoSJpegCodec()
    = default;

void DccVideoSJpegCodec::encodeVideo(KviDataBuffer * videoSignal, KviDataBuffer * stream)
{

	if(videoSignal->size() < 1)
		return;

	QImage img(videoSignal->data(), 320, 240, 1280, QImage::Format_ARGB32);
	QByteArray ba;
	QBuffer buffer(&ba);
	buffer.open(QIODevice::WriteOnly);
	//0 to obtain small compressed files,
	//100 for large uncompressed files,
	//and -1 (the default) to use the default settings.
	img.save(&buffer, "JPEG", 20);
	if(ba.size() > 0)
	{
		stream->append((const unsigned char *)ba.data(), ba.size());
	}
	videoSignal->clear();
}

void DccVideoSJpegCodec::encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream)
{
	static unsigned const char * irct_magic_init = (unsigned const char *)"\0<text>\0";
	static unsigned const char * irct_magic_end = (unsigned const char *)"\0</text>\0";

	qDebug("encodeText %s %d", textSignal->data(), textSignal->size());
	if(textSignal->size() < 1)
		return;
	stream->append(irct_magic_init, 8);
	stream->append((const unsigned char *)textSignal->data(), textSignal->size());
	stream->append(irct_magic_end, 9);
	textSignal->clear();
	return;
}

void DccVideoSJpegCodec::decode(KviDataBuffer * stream, KviDataBuffer * videoSignal, KviDataBuffer * textSignal)
{
	static unsigned const char jpg_magic_init[4] = { 0xFF, 0xD8, 0xFF, 0xE0 }; //SOI + APP0
	static unsigned const char jpg_magic_end[2] = { 0xFF, 0xD9 };              //EOI

	static unsigned const char * irct_magic_init = (unsigned const char *)"\0<text>\0";
	static unsigned const char * irct_magic_end = (unsigned const char *)"\0</text>\0";

	if(stream->size() < 1)
		return;

	int txtStart = stream->find(irct_magic_init, 8);
	int txtEnd = stream->find(irct_magic_end, 9);

	int jpgStart = stream->find(jpg_magic_init, 4);

	if(txtStart != -1 && txtEnd != -1 && txtStart < jpgStart)
	{
		qDebug("a txtStart %d txtEnd %d", txtStart, txtEnd);
		stream->remove(txtStart + 8);
		int len = txtEnd - txtStart - 8; //-8 irct_magic_init
		if(len > 0)
		{
			textSignal->append(stream->data(), len);
			char * txt = (char *)malloc(len + 1);
			memcpy(txt, stream->data(), len);
			txt[len] = '\0';
			qDebug("a recv |%s| %d", txt, len);
		}
		stream->remove(len + 9);
	}

	if(stream->size() < 1)
		return;

	jpgStart = stream->find(jpg_magic_init, 4);
	int jpgEnd = stream->find(jpg_magic_end, 2);

	if(jpgStart != -1 && jpgEnd != -1)
	{
		// 		qDebug("jpgStart %d jpgEnd %d",jpgStart,jpgEnd);
		QImage img;
		//remove junk before jpeg start
		if(jpgStart > 0)
			stream->remove(jpgStart);

		int len = jpgEnd - jpgStart + 1;

		img.loadFromData(stream->data(), stream->size());
		if(!img.isNull())
		{
			videoSignal->clear();
			videoSignal->append(img.bits(), img.sizeInBytes());
		}
		stream->remove(len);
	}

	txtStart = stream->find(irct_magic_init, 8);
	txtEnd = stream->find(irct_magic_end, 9);

	if(txtStart != -1 && txtEnd != -1)
	{
		qDebug("b txtStart %d txtEnd %d", txtStart, txtEnd);
		stream->remove(txtStart + 8);
		int len = txtEnd - txtStart - 8; //-8 irct_magic_init
		if(len > 0)
		{
			textSignal->append(stream->data(), len);
			char * txt = (char *)malloc(len + 1);
			memcpy(txt, stream->data(), len);
			txt[len] = '\0';
			qDebug("b recv |%s| %d", txt, len);
		}
		stream->remove(len + 9);
	}
}

int DccVideoSJpegCodec::encodedFrameSize()
{
	return 0;
}

int DccVideoSJpegCodec::decodedFrameSize()
{
	return 0;
}

#ifndef COMPILE_DISABLE_OGG_THEORA
DccVideoTheoraCodec::DccVideoTheoraCodec()
    : DccVideoCodec()
{
	m_szName = "theora";
	m_pEncoder = nullptr;
	m_pDecoder = nullptr;
}

DccVideoTheoraCodec::~DccVideoTheoraCodec()
{
	if(m_pEncoder)
		delete m_pEncoder;
	m_pEncoder = nullptr;

	if(m_pDecoder)
		delete m_pDecoder;
	m_pDecoder = nullptr;
}

void DccVideoTheoraCodec::encodeVideo(KviDataBuffer * videoSignal, KviDataBuffer * stream)
{
	if(videoSignal->size() < 1)
		return;

	if(!m_pEncoder)
		m_pEncoder = new KviOggTheoraEncoder(stream);

	m_pEncoder->addVideoFrame((QRgb *)videoSignal->data(), videoSignal->size());
	videoSignal->clear();
}

void DccVideoTheoraCodec::encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream)
{
	if(textSignal->size() < 1)
		return;

	if(!m_pEncoder)
		m_pEncoder = new KviOggTheoraEncoder(stream);

	m_pEncoder->addTextFrame(textSignal->data(), textSignal->size());
	textSignal->clear();
}

void DccVideoTheoraCodec::decode(KviDataBuffer * stream, KviDataBuffer * videoSignal, KviDataBuffer * textSignal)
{
	if(stream->size() < 1)
		return;

	if(!m_pDecoder)
		m_pDecoder = new KviOggTheoraDecoder(videoSignal, textSignal);

	m_pDecoder->addData(stream);
}

int DccVideoTheoraCodec::encodedFrameSize()
{
	return 0;
}

int DccVideoTheoraCodec::decodedFrameSize()
{
	return 0;
}
#endif // COMPILE_DISABLE_OGG_THEORA
