/***

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

#include <QDialogButtonBox>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QSplitter>
#include <QVBoxLayout>

#include "config/config.h"
#include "core.h"
#include "common/qtutils.h"
#include "undo/undostack.h"

namespace olive
{

SequenceDialog::SequenceDialog(Sequence *s, Type t, QWidget *parent)
	: QDialog(parent)
	, sequence_(s)
	, make_undoable_(true)
{
	QVBoxLayout *layout = new QVBoxLayout(this);

	QSplitter *splitter = new QSplitter();
	layout->addWidget(splitter);

	preset_tab_ = new SequenceDialogPresetTab();
	splitter->addWidget(preset_tab_);

	parameter_tab_ = new SequenceDialogParameterTab(sequence_);
	splitter->addWidget(parameter_tab_);

	connect(preset_tab_, &SequenceDialogPresetTab::PresetChanged,
			parameter_tab_, &SequenceDialogParameterTab::PresetChanged);
	connect(preset_tab_, &SequenceDialogPresetTab::PresetAccepted, this,
			&SequenceDialog::accept);
	connect(parameter_tab_, &SequenceDialogParameterTab::SaveParametersAsPreset,
			preset_tab_, &SequenceDialogPresetTab::SaveParametersAsPreset);

	// Set up name section
	QHBoxLayout *name_layout = new QHBoxLayout();
	name_layout->addWidget(new QLabel(tr("Name:")));
	name_field_ = new QLineEdit();
	name_layout->addWidget(name_field_);
	layout->addLayout(name_layout);

	// Set up dialog buttons
	QDialogButtonBox *buttons =
		new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	QPushButton *default_btn =
		buttons->addButton(tr("Set As Default"), QDialogButtonBox::ActionRole);
	connect(buttons, &QDialogButtonBox::accepted, this,
			&SequenceDialog::accept);
	connect(buttons, &QDialogButtonBox::rejected, this,
			&SequenceDialog::reject);
	connect(default_btn, &QPushButton::clicked, this,
			&SequenceDialog::SetAsDefaultClicked);
	layout->addWidget(buttons);

	// Set window title based on type
	switch (t) {
	case kNew:
		setWindowTitle(tr("New Sequence"));
		break;
	case kExisting:
		setWindowTitle(tr("Editing \"%1\"").arg(sequence_->GetLabel()));
		break;
	}

	name_field_->setText(sequence_->GetLabel());
}

void SequenceDialog::SetUndoable(bool u)
{
	make_undoable_ = u;
}

void SequenceDialog::SetNameIsEditable(bool e)
{
	name_field_->setEnabled(e);
}

void SequenceDialog::accept()
{
	if (name_field_->isEnabled() && name_field_->text().isEmpty()) {
		QtUtils::MsgBox(this, QMessageBox::Critical,
						tr("Error editing Sequence"),
						tr("Please enter a name for this Sequence."));
		return;
	}

	if (!VideoParams::FormatIsFloat(
			parameter_tab_->GetSelectedPreviewFormat()) &&
		!OLIVE_CONFIG("PreviewNonFloatDontAskAgain").toBool()) {
		QMessageBox b(this);
		QCheckBox *dont_show_again_ = new QCheckBox(tr("Don't ask me again"));

		b.setIcon(QMessageBox::Warning);
		b.setWindowTitle(tr("Low Quality Preview"));
		b.setText(tr(
			"The preview resolution has been set to a non-float format. This may cause banding and clipping artifacts in the preview.\n\n"
			"Do you wish to continue?"));
		b.setCheckBox(dont_show_again_);

		b.addButton(QMessageBox::Yes);
		b.addButton(QMessageBox::No);

		if (b.exec() == QMessageBox::No) {
			return;
		}

		if (dont_show_again_->isChecked()) {
			OLIVE_CONFIG("PreviewNonFloatDontAskAgain") = true;
		}
	}

	// Generate video and audio parameter structs from data
	VideoParams video_params =
		VideoParams(parameter_tab_->GetSelectedVideoWidth(),
					parameter_tab_->GetSelectedVideoHeight(),
					parameter_tab_->GetSelectedVideoFrameRate().flipped(),
					parameter_tab_->GetSelectedPreviewFormat(),
					VideoParams::kInternalChannelCount,
					parameter_tab_->GetSelectedVideoPixelAspect(),
					parameter_tab_->GetSelectedVideoInterlacingMode(),
					parameter_tab_->GetSelectedPreviewResolution());

	AudioParams audio_params =
		AudioParams(parameter_tab_->GetSelectedAudioSampleRate(),
					parameter_tab_->GetSelectedAudioChannelLayout(),
					Sequence::kDefaultSampleFormat);

	if (make_undoable_) {
		// Make undoable command to change the parameters
		SequenceParamCommand *param_command = new SequenceParamCommand(
			sequence_, video_params, audio_params, name_field_->text(),
			parameter_tab_->GetSelectedPreviewAutoCache());

		Core::instance()->undo_stack()->push(
			param_command,
			tr("Set Sequence Parameters For \"%1\"").arg(sequence_->GetLabel()));

	} else {
		// Set sequence values directly with no undo command
		sequence_->SetVideoParams(video_params);
		sequence_->SetAudioParams(audio_params);
		sequence_->SetLabel(name_field_->text());
		sequence_->SetVideoAutoCacheEnabled(
			parameter_tab_->GetSelectedPreviewAutoCache());
	}

	QDialog::accept();
}

void SequenceDialog::SetAsDefaultClicked()
{
	if (QtUtils::MsgBox(
			this, QMessageBox::Question, tr("Confirm Set As Default"),
			tr("Are you sure you want to set the current parameters as defaults?"),
			QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
		// Maybe replace with Preset system
		OLIVE_CONFIG("DefaultSequenceWidth") =
			parameter_tab_->GetSelectedVideoWidth();
		OLIVE_CONFIG("DefaultSequenceHeight") =
			parameter_tab_->GetSelectedVideoHeight();
		OLIVE_CONFIG("DefaultSequencePixelAspect") =
			QVariant::fromValue(parameter_tab_->GetSelectedVideoPixelAspect());
		OLIVE_CONFIG("DefaultSequenceFrameRate") = QVariant::fromValue(
			parameter_tab_->GetSelectedVideoFrameRate().flipped());
		OLIVE_CONFIG("DefaultSequenceInterlacing") =
			parameter_tab_->GetSelectedVideoInterlacingMode();
		OLIVE_CONFIG("DefaultSequenceAudioFrequency") =
			parameter_tab_->GetSelectedAudioSampleRate();
		OLIVE_CONFIG("DefaultSequenceAudioLayout") = QVariant::fromValue(
			parameter_tab_->GetSelectedAudioChannelLayout());
	}
}

SequenceDialog::SequenceParamCommand::SequenceParamCommand(
	Sequence *s, const VideoParams &video_params,
	const AudioParams &audio_params, const QString &name, bool autocache)
	: sequence_(s)
	, new_video_params_(video_params)
	, new_audio_params_(audio_params)
	, new_name_(name)
	, new_autocache_(autocache)
	, old_video_params_(s->GetVideoParams())
	, old_audio_params_(s->GetAudioParams())
	, old_name_(s->GetLabel())
	, old_autocache_(s->IsVideoAutoCacheEnabled())
{
}

Project *SequenceDialog::SequenceParamCommand::GetRelevantProject() const
{
	return sequence_->project();
}

void SequenceDialog::SequenceParamCommand::redo()
{
	if (sequence_->GetVideoParams() != new_video_params_) {
		sequence_->SetVideoParams(new_video_params_);
	}
	if (sequence_->GetAudioParams() != new_audio_params_) {
		sequence_->SetAudioParams(new_audio_params_);
	}
	sequence_->SetLabel(new_name_);
	sequence_->SetVideoAutoCacheEnabled(new_autocache_);
}

void SequenceDialog::SequenceParamCommand::undo()
{
	if (sequence_->GetVideoParams() != old_video_params_) {
		sequence_->SetVideoParams(old_video_params_);
	}
	if (sequence_->GetAudioParams() != old_audio_params_) {
		sequence_->SetAudioParams(old_audio_params_);
	}
	sequence_->SetLabel(old_name_);
	sequence_->SetVideoAutoCacheEnabled(old_autocache_);
}

}
