/* DatabaseVisStyles.cpp */

/* Copyright (C) 2011-2024 Michael Lugmair (Lucio Carreras)
 *
 * 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 "Database/Query.h"
#include "Database/VisualStyles.h"

#include "Components/Visualization/VisualStyleTypes.h"
#include "Utils/Utils.h"

#include <QColor>

using DB::VisualStyles;
using DB::Module;

VisualStyles::VisualStyles(const QString& connection_name, DbId databaseId) :
	Module(connection_name, databaseId) {}

VisualStyles::~VisualStyles() = default;

QString col2String(const QColor& col)
{
	QString str;
	str = QString::number(col.red()) + "," +
	      QString::number(col.green()) + "," +
	      QString::number(col.blue()) + "," +
	      QString::number(col.alpha());
	return str;
}

bool colFromString(const QString& str, QColor& c)
{
	QStringList colors = str.split(",");

	if(colors.size() < 3)
	{
		return false;
	}

	c.setRed(colors[0].toInt());
	c.setGreen(colors[1].toInt());
	c.setBlue(colors[2].toInt());

	if(colors.size() == 4)
	{
		c.setAlpha(colors[3].toInt());
	}

	else
	{
		c.setAlpha(255);
	}

	return true;
}

QList<RawColorStyle> VisualStyles::getRawColorStyles()
{
	QList<RawColorStyle> ret_val;

	auto q = QSqlQuery(db());
	q.prepare("SELECT * FROM VisualStyles;");

	if(!q.exec())
	{
		showError(q, "Could not fetch color styles");
		return ret_val;
	}

	while(q.next())
	{
		RawColorStyle rcs;

		rcs.colorList.name = q.value(0).toString();
		QColor col1, col2, col3, col4;
		bool col3v, col4v;
		colFromString(q.value(1).toString(), col1);
		colFromString(q.value(2).toString(), col2);
		col3v = colFromString(q.value(3).toString(), col3);
		col4v = colFromString(q.value(4).toString(), col4);

		rcs.colorList.colors << col1;
		rcs.colorList.colors << col2;
		if(col3v) { rcs.colorList.colors << col3; }
		if(col4v) { rcs.colorList.colors << col4; }
		rcs.spectrumBins = q.value(5).toInt();
		rcs.rectHeightSpectrum = q.value(6).toInt();
		rcs.fadingStepsSpectrum = q.value(7).toInt();
		rcs.horSpacingSpectrum = q.value(8).toInt();
		rcs.verSpacingSpectrum = q.value(9).toInt();
		rcs.rectWidthLevel = q.value(10).toInt();
		rcs.rectHeightLevel = q.value(11).toInt();
		rcs.horSpacingLevel = q.value(12).toInt();
		rcs.verSpacingLevel = q.value(13).toInt();
		rcs.fadingStepsLevel = q.value(14).toInt();

		ret_val << rcs;
	}

	return ret_val;
}

bool VisualStyles::insertRawColorStyle(const RawColorStyle& rcs)
{
	if(rawColorStyleExists(rcs.colorList.name))
	{
		return updateRawColorStyle(rcs);
	}

	QString col_str;
	for(int i = 0; i < 4; i++)
	{
		col_str += ":col" + QString::number(i + 1) + ", ";
	}

	auto q = QSqlQuery(db());
	QString sql_str;
	sql_str = "INSERT INTO VisualStyles VALUES ("
	          ":name, "
	          + col_str +
	          ":n_bins_sp, "
	          ":rect_height_sp, "
	          ":fading_steps_sp, "
	          ":h_spacing_sp, "
	          ":v_spacing_sp, "
	          ":rect_width_lv, "
	          ":rect_height_lv, "
	          ":h_spacing_lv, "
	          ":v_spacing_lv, "
	          ":fading_steps_lv"
	          ")";

	q.prepare(sql_str);
	q.bindValue(":name", Util::convertNotNull(rcs.colorList.name));
	q.bindValue(":col1", col2String(rcs.colorList.colors[0]));
	q.bindValue(":col2", col2String(rcs.colorList.colors[1]));

	if(rcs.colorList.colors.size() > 2)
	{
		q.bindValue(":col3", col2String(rcs.colorList.colors[2]));
	}

	else
	{
		q.bindValue(":col3", QString(""));
	}

	if(rcs.colorList.colors.size() > 3)
	{
		q.bindValue(":col4", col2String(rcs.colorList.colors[3]));
	}

	else { q.bindValue(":col4", QString("")); }

	q.bindValue(":n_bins_sp", rcs.spectrumBins);
	q.bindValue(":rect_height_sp", rcs.rectHeightSpectrum);
	q.bindValue(":fading_steps_sp", rcs.fadingStepsSpectrum);
	q.bindValue(":h_spacing_sp", rcs.horSpacingSpectrum);
	q.bindValue(":v_spacing_sp", rcs.verSpacingSpectrum);
	q.bindValue(":rect_width_lv", rcs.rectWidthLevel);
	q.bindValue(":rect_height_lv", rcs.rectHeightLevel);
	q.bindValue(":h_spacing_lv", rcs.horSpacingLevel);
	q.bindValue(":v_spacing_lv", rcs.verSpacingLevel);
	q.bindValue(":fading_steps_lv", rcs.fadingStepsLevel);

	if(!q.exec())
	{
		showError(q, "Could not insert style");
		return false;
	}

	return true;
}

bool VisualStyles::updateRawColorStyle(const RawColorStyle& rcs)
{
	if(!rawColorStyleExists(rcs.colorList.name))
	{
		return insertRawColorStyle(rcs);
	}

	QString col_str;
	for(int i = 0; i < 4; i++)
	{
		col_str += "col" + QString::number(i + 1) + "=:col" + QString::number(i + 1) + ", ";
	}

	auto q = QSqlQuery(db());
	QString sql_str;
	sql_str = "UPDATE VisualStyles SET "

	          + col_str +
	          "nBinsSpectrum=:n_bins_sp, "
	          "rectHeightSpectrum=:rect_height_sp, "
	          "fadingStepsSpectrum=:fading_steps_sp, "
	          "horSpacingSpectrum=:h_spacing_sp, "
	          "vertSpacingSpectrum=:v_spacing_sp, "
	          "rectWidthLevel=:rect_width_lv, "
	          "rectHeightLevel=:rect_height_lv, "
	          "horSpacingLevel=:h_spacing_lv, "
	          "verSpacingLevel=:v_spacing_lv, "
	          "fadingStepsLevel=:fading_steps_lv"
	          " WHERE name=:name";

	q.prepare(sql_str);
	q.bindValue(":name", Util::convertNotNull(rcs.colorList.name));
	q.bindValue(":col1", Util::convertNotNull(col2String(rcs.colorList.colors[0])));
	q.bindValue(":col2", Util::convertNotNull(col2String(rcs.colorList.colors[1])));

	if(rcs.colorList.colors.size() > 2)
	{
		q.bindValue(":col3", col2String(rcs.colorList.colors[2]));
	}
	else
	{
		q.bindValue(":col3", QString(""));
	}

	if(rcs.colorList.colors.size() > 3)
	{
		q.bindValue(":col4", col2String(rcs.colorList.colors[3]));
	}
	else
	{
		q.bindValue(":col4", QString(""));
	}

	q.bindValue(":n_bins_sp", rcs.spectrumBins);
	q.bindValue(":rect_height_sp", rcs.rectHeightSpectrum);
	q.bindValue(":fading_steps_sp", rcs.fadingStepsSpectrum);
	q.bindValue(":h_spacing_sp", rcs.horSpacingSpectrum);
	q.bindValue(":v_spacing_sp", rcs.verSpacingSpectrum);
	q.bindValue(":rect_width_lv", rcs.rectWidthLevel);
	q.bindValue(":rect_height_lv", rcs.rectHeightLevel);
	q.bindValue(":h_spacing_lv", rcs.horSpacingLevel);
	q.bindValue(":v_spacing_lv", rcs.verSpacingLevel);
	q.bindValue(":fading_steps_lv", rcs.fadingStepsLevel);

	if(!q.exec())
	{
		showError(q, QString("Could not update style ") + rcs.colorList.name);
		return false;
	}

	return true;
}

bool VisualStyles::deleteRawColorStyle(QString name)
{
	auto q = QSqlQuery(db());
	q.prepare("DELETE FROM visualstyles WHERE name=:name;");
	q.bindValue(":name", Util::convertNotNull(name));

	if(!q.exec())
	{
		showError(q, QString("Could not delete Raw color style ") + name);
		return false;
	}

	return true;
}

bool VisualStyles::rawColorStyleExists(QString name)
{
	auto q = QSqlQuery(db());
	q.prepare("SELECT * FROM visualstyles WHERE name=:name;");
	q.bindValue(":name", Util::convertNotNull(name));

	if(!q.exec())
	{
		showError(q, "Cannot check if raw color style exists");
		return false;
	}

	if(!q.next())
	{
		return false;
	}

	return true;
}

