/* SpectrumLabel.cpp
 *
 * Copyright (C) 2011-2024 Michael Lugmair
 *
 * This file is part of sayonara player
 *
 * 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 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "SpectrumLabel.h"
#include "Interfaces/AudioDataProvider.h"
#include <cmath>

#include <QPixmap>
#include <QPainter>
#include <QEvent>

namespace
{
	using SpectrumData = std::vector<float>;

	double scale(const double value)
	{
		constexpr const auto Offset = 75.0;
		return (value + Offset) / Offset;
	}

	double extractBass(const SpectrumData& data)
	{
		return scale(data[1]);
	}

	double extractMid(const SpectrumData& data)
	{
		const auto middleIndex = data.size() / 2;
		const auto value = scale(data[middleIndex]);
		return std::pow(value, 0.5); // NOLINT(*-magic-numbers)
	}

	double extractHigh(const SpectrumData& data)
	{
		const auto highIndex = data.size() - 2U;
		const auto value = scale(data[highIndex]);
		return std::pow(value, 0.3) * 2.0;  // NOLINT(*-magic-numbers)
	}
}

struct SpectrumLabel::Private
{
	SpectrumDataProvider* dataProvider;

	explicit Private(SpectrumDataProvider* dataProvider) :
		dataProvider(dataProvider) {}
};

SpectrumLabel::SpectrumLabel(SpectrumDataProvider* dataProvider, QWidget* parent) :
	QLabel(parent)
{
	m = Pimpl::make<Private>(dataProvider);

	m->dataProvider->registerSpectrumReceiver(this);
	m->dataProvider->spectrumActiveChanged(true);
}

SpectrumLabel::~SpectrumLabel() = default;

void SpectrumLabel::setSpectrum(const std::vector<float>& spectrum)
{
	auto pm = QPixmap(width(), height());
	pm.fill(QColor(0, 0, 0, 0));

	auto painter = QPainter(&pm);

	const auto bass = extractBass(spectrum);
	const auto mid = extractMid(spectrum);
	const auto high = extractHigh(spectrum);

	const auto w = width() / 3 - 3;
	const auto h = height();

	// left, top, width, height
	const auto bassRect = QRect(2, h - int(h * bass), w, h);
	const auto midRect = QRect(2 + w, h - int(h * mid), w, h);
	const auto highRect = QRect(2 + w + w, h - int(h * high), w, h);

	constexpr const auto MaxByte = 255;
	painter.setBrush(QColor(MaxByte, MaxByte, MaxByte));

	painter.drawRect(bassRect);
	painter.drawRect(midRect);
	painter.drawRect(highRect);

	setPixmap(pm);

	emit sigPixmapChanged();
}

bool SpectrumLabel::isActive() const { return isVisible(); }
