/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
 *
 */
/* This class is a C++/Qt version of input_ffmpeg.c from libebur128
 */

/* See LICENSE file for copyright and license details. */
#ifdef __cplusplus
extern "C" {
#endif
#include <mpg123.h>
#ifdef __cplusplus
}
#endif
#include "ebur128.h"
#include "mpg123input.h"
#include <QByteArray>
#include <QFile>
#include <QString>

struct Mpg123Input::Handle {
	Handle()
		: mpg123(0), rate(0), channels(0), encoding(0), buffer(0)
	{
	}
	~Handle()
	{
		if (buffer) {
			free(buffer);
		}
	}
	mpg123_handle* mpg123;
	long rate;
	int channels, encoding;
	float* buffer;
};

void Mpg123Input::init()
{
	static int i = false;
	if (!i) {
		mpg123_init();
	}
}

Mpg123Input::Mpg123Input(const QString& fileName)
{
	handle = new Handle;

	QByteArray fName = QFile::encodeName(fileName);
	bool ok = false;
	int result;
	handle->mpg123 = mpg123_new(NULL, &result);
	if (handle->mpg123 && MPG123_OK == mpg123_open(handle->mpg123, fName.constData()) && MPG123_OK == mpg123_getformat(handle->mpg123, &handle->rate, &handle->channels, &handle->encoding) && MPG123_OK == mpg123_format_none(handle->mpg123) && MPG123_OK == mpg123_format(handle->mpg123, handle->rate, handle->channels, MPG123_ENC_FLOAT_32)) {

		mpg123_close(handle->mpg123);
		if (MPG123_OK == mpg123_open(handle->mpg123, fName.constData()) && MPG123_OK == mpg123_getformat(handle->mpg123, &handle->rate, &handle->channels, &handle->encoding)) {
			ok = true;
		}
	}

	if (!ok) {
		if (handle->mpg123) {
			mpg123_close(handle->mpg123);
			mpg123_delete(handle->mpg123);
			handle->mpg123 = NULL;
		}
		delete handle;
		handle = 0;
	}
}

Mpg123Input::~Mpg123Input()
{
	if (handle) {
		if (handle->mpg123) {
			mpg123_close(handle->mpg123);
			mpg123_delete(handle->mpg123);
			handle->mpg123 = NULL;
		}
		delete handle;
		handle = 0;
	}
}

size_t Mpg123Input::totalFrames() const
{
	if (!handle) {
		return 0;
	}

	off_t length = mpg123_length(handle->mpg123);
	return MPG123_ERR == length ? 0 : (size_t)length;
}

unsigned int Mpg123Input::channels() const
{
	return handle ? (unsigned int)handle->channels : 0;
}

unsigned long Mpg123Input::sampleRate() const
{
	return handle ? (unsigned long)handle->rate : 0;
}

bool Mpg123Input::allocateBuffer()
{
	if (!handle) {
		return false;
	}

	handle->buffer = (float*)malloc((size_t)handle->rate * (size_t)handle->channels * sizeof(float));
	return handle->buffer;
}

float* Mpg123Input::buffer() const
{
	return handle ? handle->buffer : 0;
}

bool Mpg123Input::setChannelMap(int* st) const
{
	Q_UNUSED(st)
	return false;
}

size_t Mpg123Input::readFrames()
{
	if (!handle) {
		return 0;
	}

	size_t numberRead;
	int result = mpg123_read(handle->mpg123, (unsigned char*)handle->buffer,
	                         (size_t)handle->rate * (size_t)handle->channels * sizeof(float),
	                         &numberRead);
	if (MPG123_OK != result && MPG123_DONE != result) {
		return 0;
	}
	numberRead /= (size_t)handle->channels * sizeof(float);
	return numberRead;
}
