/***

  Olive - Non-Linear Video Editor
  Copyright (C) 2022 Olive Team
  Modifications Copyright (C) 2025 mikesolar

  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 "subtitleparams.h"

#include <QCoreApplication>

#include "common/xmlutils.h"

namespace olive
{

QString SubtitleParams::GenerateASSHeader()
{
	// NOTE: We'll probably implement more customization as we support ASS better. Right now, we only
	//       natively support SRT and only make this header because FFmpeg requires it.
	static const int kAssDefaultPlayResX = 384;
	static const int kAssDefaultPlayResY = 288;
	static const QString kAssDefaultFont = QStringLiteral("Arial");
	static const int kAssDefaultFontSize = 16;
	static const int kAssDefaultPrimaryColor = 0xFFFFFF; // White
	static const int kAssDefaultSecondaryColor = 0xFFFFFF; // White
	static const int kAssDefaultOutlineColor = 0x000000; // Black
	static const int kAssDefaultBackColor = 0x000000; // Black
	static const int kAssBold = 0;
	static const int kAssItalic = 0;
	static const int kAssUnderline = 0;
	static const int kAssStrike = 0;
	static const int kAssBorderStyle = 1;
	static const int kAssAlignment = 2;

	QString ass_code;

	// Header info
	ass_code.append(QStringLiteral("[Script Info]\r\n"));
	ass_code.append(QStringLiteral("; Script generated by %1 %2\r\n")
						.arg(QCoreApplication::applicationName(),
							 QCoreApplication::applicationVersion()));
	ass_code.append(QStringLiteral("ScriptType: v4.00+\r\n"));
	ass_code.append(QStringLiteral("PlayResX: %1\r\n")
						.arg(QString::number(kAssDefaultPlayResX)));
	ass_code.append(QStringLiteral("PlayResY: %1\r\n")
						.arg(QString::number(kAssDefaultPlayResY)));
	ass_code.append(QStringLiteral("ScaledBorderAndShadow: yes\r\n"));
	ass_code.append(QStringLiteral("\r\n"));

	// ASSv4 header
	ass_code.append(QStringLiteral("[V4+ Styles]\r\n"));
	ass_code.append(QStringLiteral("Format: Name, "));
	ass_code.append(QStringLiteral("Fontname, Fontsize, "));
	ass_code.append(QStringLiteral(
		"PrimaryColour, SecondaryColour, OutlineColour, BackColour, "));
	ass_code.append(QStringLiteral("Bold, Italic, Underline, StrikeOut, "));
	ass_code.append(QStringLiteral("ScaleX, ScaleY, "));
	ass_code.append(QStringLiteral("Spacing, Angle, "));
	ass_code.append(QStringLiteral("BorderStyle, Outline, Shadow, "));
	ass_code.append(QStringLiteral("Alignment, MarginL, MarginR, MarginV, "));
	ass_code.append(QStringLiteral("Encoding\r\n"));
	ass_code.append(QStringLiteral("Style: "));

	// Name
	ass_code.append(QStringLiteral("Default,"));

	// Font{name,size}
	ass_code.append(QStringLiteral("%1,%2,").arg(
		kAssDefaultFont, QString::number(kAssDefaultFontSize)));

	// {Primary,Secondary,Outline,Back}Colour
	ass_code.append(QStringLiteral("&H%1,&H%2,&H%3,&H%4,")
						.arg(QString::number(kAssDefaultPrimaryColor, 16),
							 QString::number(kAssDefaultSecondaryColor, 16),
							 QString::number(kAssDefaultOutlineColor, 16),
							 QString::number(kAssDefaultBackColor, 16)));

	// Bold, Italic, Underline, StrikeOut
	ass_code.append(
		QStringLiteral("%1,%2,%3,%4,")
			.arg(QString::number(kAssBold), QString::number(kAssItalic),
				 QString::number(kAssUnderline), QString::number(kAssStrike)));

	// Scale{X,Y}
	ass_code.append(QStringLiteral("100,100,"));

	// Spacing, Angle
	ass_code.append(QStringLiteral("0,0,"));

	// BorderStyle, Outline, Shadow
	ass_code.append(
		QStringLiteral("%1,1,0,").arg(QString::number(kAssBorderStyle)));

	// Alignment, Margin[LRV]
	ass_code.append(
		QStringLiteral("%1,10,10,10,").arg(QString::number(kAssAlignment)));

	// Encoding
	ass_code.append(QStringLiteral("0\r\n"));
	ass_code.append(QStringLiteral("\r\n"));
	ass_code.append(QStringLiteral("[Events]\r\n"));
	ass_code.append(QStringLiteral(
		"Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n"));

	return ass_code;
}

void SubtitleParams::Load(QXmlStreamReader *reader)
{
	this->clear();

	while (XMLReadNextStartElement(reader)) {
		if (reader->name() == QStringLiteral("streamindex")) {
			set_stream_index(reader->readElementText().toInt());
		} else if (reader->name() == QStringLiteral("enabled")) {
			set_enabled(reader->readElementText().toInt());
		} else if (reader->name() == QStringLiteral("subtitles")) {
			while (XMLReadNextStartElement(reader)) {
				if (reader->name() == QStringLiteral("subtitle")) {
					rational in, out;
					QString text;

					XMLAttributeLoop(reader, attr)
					{
						if (attr.name() == QStringLiteral("in")) {
							in = rational::fromString(
								attr.value().toString().toStdString());
						} else if (attr.name() == QStringLiteral("out")) {
							out = rational::fromString(
								attr.value().toString().toStdString());
						}
					}

					text = reader->readElementText();

					this->push_back(Subtitle(TimeRange(in, out), text));
				} else {
					reader->skipCurrentElement();
				}
			}
		} else {
			reader->skipCurrentElement();
		}
	}
}

void SubtitleParams::Save(QXmlStreamWriter *writer) const
{
	writer->writeTextElement(QStringLiteral("streamindex"),
							 QString::number(stream_index_));
	writer->writeTextElement(QStringLiteral("enabled"),
							 QString::number(enabled_));

	writer->writeStartElement(QStringLiteral("subtitles"));
	for (auto it = this->cbegin(); it != this->cend(); it++) {
		writer->writeStartElement(QStringLiteral("subtitle"));
		writer->writeAttribute(
			QStringLiteral("in"),
			QString::fromStdString(it->time().in().toString()));
		writer->writeAttribute(
			QStringLiteral("out"),
			QString::fromStdString(it->time().out().toString()));
		writer->writeCharacters(it->text());
		writer->writeEndElement(); // subtitle
	}
	writer->writeEndElement(); // subtitles
}

}
