/***

  Olive - Non-Linear Video Editor
  Copyright (C) 2020 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 "footageproperties.h"

#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <QTreeWidgetItem>
#include <QGroupBox>
#include <QListWidget>
#include <QCheckBox>
#include <QSpinBox>

#include "core.h"
#include "node/nodeundo.h"
#include "streamproperties/audiostreamproperties.h"
#include "streamproperties/videostreamproperties.h"

namespace olive
{

FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent,
												 Footage *footage)
	: QDialog(parent)
	, footage_(footage)
{
	QGridLayout *layout = new QGridLayout(this);

	setWindowTitle(tr("\"%1\" Properties").arg(footage_->GetLabelOrName()));
	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

	int row = 0;

	layout->addWidget(new QLabel(tr("Name:")), row, 0);

	footage_name_field_ = new QLineEdit(footage_->GetLabel());
	layout->addWidget(footage_name_field_, row, 1);
	row++;

	layout->addWidget(new QLabel(tr("Tracks:")), row, 0, 1, 2);
	row++;

	track_list = new QListWidget();
	layout->addWidget(track_list, row, 0, 1, 2);

	row++;

	stacked_widget_ = new QStackedWidget();
	layout->addWidget(stacked_widget_, row, 0, 1, 2);

	int first_usable_stream = -1;

	for (int i = 0; i < footage_->GetTotalStreamCount(); i++) {
		Track::Reference reference = footage_->GetReferenceFromRealIndex(i);

		QString description;
		bool is_enabled = false;

		switch (reference.type()) {
		case Track::kVideo: {
			stacked_widget_->addWidget(
				new VideoStreamProperties(footage_, reference.index()));

			VideoParams vp = footage_->GetVideoParams(reference.index());
			is_enabled = vp.enabled();
			description = Footage::DescribeVideoStream(vp);
			break;
		}
		case Track::kAudio: {
			stacked_widget_->addWidget(
				new AudioStreamProperties(footage_, reference.index()));

			AudioParams ap = footage_->GetAudioParams(reference.index());
			is_enabled = ap.enabled();
			description = Footage::DescribeAudioStream(ap);
			break;
		}
		case Track::kSubtitle: {
			SubtitleParams sp = footage_->GetSubtitleParams(reference.index());
			is_enabled = sp.enabled();

			// FIXME: Language?
			description = tr("Subtitles");
			break;
		}
		default:
			stacked_widget_->addWidget(new StreamProperties());
			description = tr("Unknown");
			break;
		}

		QListWidgetItem *item = new QListWidgetItem(description, track_list);
		item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
		item->setCheckState(is_enabled ? Qt::Checked : Qt::Unchecked);
		track_list->addItem(item);

		if (first_usable_stream == -1 &&
			(reference.type() == Track::kVideo ||
			 reference.type() == Track::kAudio ||
			 reference.type() == Track::kSubtitle)) {
			first_usable_stream = i;
		}
	}

	row++;

	QDialogButtonBox *buttons =
		new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	buttons->setCenterButtons(true);
	layout->addWidget(buttons, row, 0, 1, 2);

	connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
	connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);

	connect(track_list, &QListWidget::currentRowChanged, stacked_widget_,
			&QStackedWidget::setCurrentIndex);

	// Auto-select first item that actually has properties
	if (first_usable_stream >= 0) {
		track_list->setCurrentRow(first_usable_stream);
	}
	track_list->setFocus();
}

void FootagePropertiesDialog::accept()
{
	// Perform sanity check on all pages
	for (int i = 0; i < stacked_widget_->count(); i++) {
		if (!static_cast<StreamProperties *>(stacked_widget_->widget(i))
				 ->SanityCheck()) {
			// Switch to the failed panel in question
			stacked_widget_->setCurrentIndex(i);

			// Do nothing (it's up to the property panel itself to throw the error message)
			return;
		}
	}

	MultiUndoCommand *command = new MultiUndoCommand();

	if (footage_->GetLabel() != footage_name_field_->text()) {
		NodeRenameCommand *nrc = new NodeRenameCommand();
		nrc->AddNode(footage_, footage_name_field_->text());
		command->add_child(nrc);
	}

	for (int i = 0; i < footage_->GetTotalStreamCount(); i++) {
		Track::Reference reference = footage_->GetReferenceFromRealIndex(i);
		bool new_stream_enabled =
			(track_list->item(i)->checkState() == Qt::Checked);
		bool old_stream_enabled = new_stream_enabled;

		switch (reference.type()) {
		case Track::kVideo:
			old_stream_enabled =
				footage_->GetVideoParams(reference.index()).enabled();
			break;
		case Track::kAudio:
			old_stream_enabled =
				footage_->GetAudioParams(reference.index()).enabled();
			break;
		case Track::kSubtitle:
			old_stream_enabled =
				footage_->GetSubtitleParams(reference.index()).enabled();
			break;
		case Track::kNone:
		case Track::kCount:
			break;
		}

		if (old_stream_enabled != new_stream_enabled) {
			command->add_child(new StreamEnableChangeCommand(
				footage_, reference.type(), reference.index(),
				new_stream_enabled));
		}
	}

	for (int i = 0; i < stacked_widget_->count(); i++) {
		static_cast<StreamProperties *>(stacked_widget_->widget(i))
			->Accept(command);
	}

	Core::instance()->undo_stack()->push(
		command, tr("Set Footage \"%1\" Properties").arg(footage_->GetLabel()));

	QDialog::accept();
}

FootagePropertiesDialog::StreamEnableChangeCommand::StreamEnableChangeCommand(
	Footage *footage, Track::Type type, int index_in_type, bool enabled)
	: footage_(footage)
	, type_(type)
	, index_(index_in_type)
	, new_enabled_(enabled)
{
}

Project *
FootagePropertiesDialog::StreamEnableChangeCommand::GetRelevantProject() const
{
	return footage_->project();
}

void FootagePropertiesDialog::StreamEnableChangeCommand::redo()
{
	switch (type_) {
	case Track::kVideo: {
		VideoParams vp = footage_->GetVideoParams(index_);
		old_enabled_ = vp.enabled();
		vp.set_enabled(new_enabled_);
		footage_->SetVideoParams(vp, index_);
		break;
	}
	case Track::kAudio: {
		AudioParams ap = footage_->GetAudioParams(index_);
		old_enabled_ = ap.enabled();
		ap.set_enabled(new_enabled_);
		footage_->SetAudioParams(ap, index_);
		break;
	}
	case Track::kSubtitle: {
		SubtitleParams sp = footage_->GetSubtitleParams(index_);
		old_enabled_ = sp.enabled();
		sp.set_enabled(new_enabled_);
		footage_->SetSubtitleParams(sp, index_);
		break;
	}
	case Track::kNone:
	case Track::kCount:
		break;
	}
}

void FootagePropertiesDialog::StreamEnableChangeCommand::undo()
{
	switch (type_) {
	case Track::kVideo: {
		VideoParams vp = footage_->GetVideoParams(index_);
		vp.set_enabled(old_enabled_);
		footage_->SetVideoParams(vp, index_);
		break;
	}
	case Track::kAudio: {
		AudioParams ap = footage_->GetAudioParams(index_);
		ap.set_enabled(old_enabled_);
		footage_->SetAudioParams(ap, index_);
		break;
	}
	case Track::kSubtitle: {
		SubtitleParams sp = footage_->GetSubtitleParams(index_);
		sp.set_enabled(old_enabled_);
		footage_->SetSubtitleParams(sp, index_);
		break;
	}
	case Track::kNone:
	case Track::kCount:
		break;
	}
}

}
