/* DirectoryContextMenu.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 "DirectoryContextMenu.h"

#include "Components/LibraryManagement/LibraryManager.h"
#include "Gui/Utils/Icons.h"
#include "Gui/Utils/PreferenceAction.h"
#include "Utils/Language/Language.h"
#include "Utils/Library/LibraryInfo.h"

#include <QAction>

namespace Directory
{
	struct ContextMenu::Private
	{
		QAction* actionCreateDirectory = nullptr;
		QAction* actionRename = nullptr;
		QAction* actionRenameByTag = nullptr;
		QAction* actionCollapseAll = nullptr;
		QAction* actionViewInFileManager = nullptr;

		QMap<ContextMenu::Entry, QAction*> entryActionMap;

		QMenu* menuMoveToLibrary = nullptr;
		QAction* actionMoveToLibrary = nullptr;

		QMenu* menuCopyToLibrary = nullptr;
		QAction* actionCopyToLibrary = nullptr;

		QList<QAction*> libraryMoveActions, libraryCopyActions;

		ContextMenu::Mode mode;

		Private(ContextMenu::Mode mode, Library::InfoAccessor* libraryInfoAccessor, ContextMenu* parent) :
			actionCreateDirectory {new QAction(parent)},
			actionRename {new QAction(parent)},
			actionRenameByTag {new QAction(parent)},
			actionCollapseAll {new QAction(parent)},
			actionViewInFileManager {new QAction(parent)},
			menuMoveToLibrary {new QMenu(parent)},
			menuCopyToLibrary {new QMenu(parent)},
			mode {mode}
		{
			const auto libraries = libraryInfoAccessor->allLibraries();
			for(const auto& info: libraries)
			{
				auto* actionCopy = menuCopyToLibrary->addAction(info.name());
				auto* actionMove = menuMoveToLibrary->addAction(info.name());

				actionCopy->setData(info.id());
				actionMove->setData(info.id());

				libraryCopyActions << actionCopy;
				libraryMoveActions << actionMove;
			}

			actionCopyToLibrary = parent->addMenu(menuCopyToLibrary); // NOLINT(*-prefer-member-initializer)
			actionMoveToLibrary = parent->addMenu(menuMoveToLibrary); // NOLINT(*-prefer-member-initializer)

			entryActionMap =
				{
					{EntryCreateDir,   actionCreateDirectory},
					{EntryRename,      actionRename},
					{EntryRenameByTag, actionRenameByTag},
					{EntryCollapseAll, actionCollapseAll},
					{EntryMoveToLib,   actionMoveToLibrary},
					{EntryCopyToLib,   actionCopyToLibrary},
					{EntryViewInFM,    actionViewInFileManager}
				};
		}
	};

	ContextMenu::ContextMenu(ContextMenu::Mode mode, Library::InfoAccessor* libraryInfoAccessor, QWidget* parent) :
		Library::ContextMenu(parent),
		m {Pimpl::make<Private>(mode, libraryInfoAccessor, this)}
	{
		showActions(
			Library::ContextMenu::EntryPlay |
			Library::ContextMenu::EntryPlayNewTab |
			Library::ContextMenu::EntryDelete |
			Library::ContextMenu::EntryInfo |
			Library::ContextMenu::EntryEdit |
			Library::ContextMenu::EntryLyrics |
			Library::ContextMenu::EntryAppend |
			Library::ContextMenu::EntryPlayNext);

		auto* deleteAction = action(Library::ContextMenu::EntryDelete);
		if(deleteAction)
		{
			insertActions(
				deleteAction,
				{
					addSeparator(),
					m->actionCreateDirectory, m->actionRename, m->actionRenameByTag,
				});
		}

		connect(m->actionCreateDirectory, &QAction::triggered, this, &ContextMenu::sigCreateDirectoryClicked);
		connect(m->actionRename, &QAction::triggered, this, &ContextMenu::sigRenameClicked);
		connect(m->actionRenameByTag, &QAction::triggered, this, &ContextMenu::sigRenameByTagClicked);
		connect(m->actionCollapseAll, &QAction::triggered, this, &ContextMenu::sigCollapseAllClicked);
		connect(m->actionViewInFileManager, &QAction::triggered, this, &ContextMenu::sigViewInFileManagerClicked);

		for(auto* moveAction: qAsConst(m->libraryMoveActions))
		{
			connect(moveAction, &QAction::triggered, this, &ContextMenu::libraryMoveActionTriggered);
		}

		for(auto* copyAction: qAsConst(m->libraryCopyActions))
		{
			connect(copyAction, &QAction::triggered, this, &ContextMenu::libraryCopyActionTriggered);
		}

		auto* libraryPreferenceAction = addPreferenceAction(new Gui::LibraryPreferenceAction(this));

		insertActions(
			libraryPreferenceAction,
			{
				m->actionViewInFileManager,
				m->actionCollapseAll,
				addSeparator(),
				m->actionMoveToLibrary,
				m->actionCopyToLibrary,
				addSeparator()
			});

		switch(mode)
		{
			case ContextMenu::Mode::Dir:
				showAction(Library::ContextMenu::EntryLyrics, false);
				break;
			case ContextMenu::Mode::File:
				m->actionCreateDirectory->setVisible(false);
				m->actionCollapseAll->setVisible(false);
				break;
			default:
				break;
		}

		skinChanged();
		languageChanged();
	}

	ContextMenu::~ContextMenu() = default;

	void ContextMenu::refresh(const int count)
	{
		if((count == 0) && (m->mode == ContextMenu::Mode::File))
		{
			showActions(Library::ContextMenu::EntryDelete);

			m->actionCreateDirectory->setVisible(false);
			m->actionCollapseAll->setVisible(false);
			m->actionViewInFileManager->setVisible(false);
			m->actionMoveToLibrary->setVisible(false);
			m->actionCopyToLibrary->setVisible(false);
			m->actionRenameByTag->setVisible(false);
			m->actionRename->setVisible(false);
		}

		else
		{
			showActions(
				Library::ContextMenu::EntryPlay |
				Library::ContextMenu::EntryPlayNewTab |
				Library::ContextMenu::EntryDelete |
				Library::ContextMenu::EntryInfo |
				Library::ContextMenu::EntryEdit |
				Library::ContextMenu::EntryLyrics |
				Library::ContextMenu::EntryAppend |
				Library::ContextMenu::EntryPlayNext |
				Library::ContextMenu::EntryViewType);

			switch(m->mode)
			{
				case ContextMenu::Mode::Dir:
					showAction(Library::ContextMenu::EntryLyrics, false);
					m->actionCreateDirectory->setVisible(count == 1);
					m->actionViewInFileManager->setVisible(count > 0);
					m->actionCollapseAll->setVisible(true);
					m->actionRenameByTag->setVisible(false);
					showAction(Library::ContextMenu::EntryLyrics, false);
					break;
				case ContextMenu::Mode::File:
					m->actionCreateDirectory->setVisible(false);
					m->actionCollapseAll->setVisible(false);
					m->actionViewInFileManager->setVisible(false);
					m->actionRenameByTag->setVisible(true);
					showAction(Library::ContextMenu::EntryLyrics, (count == 1));
					break;
				default:
					break;
			}

			m->actionRename->setVisible(count == 1);
			m->actionMoveToLibrary->setVisible(true);
			m->actionCopyToLibrary->setVisible(true);
		}
	}

	Library::ContextMenu::Entries ContextMenu::entries() const
	{
		auto entries = Library::ContextMenu::entries();
		for(auto it = m->entryActionMap.begin(); it != m->entryActionMap.end(); it++)
		{
			if(it.value()->isVisible())
			{
				entries |= it.key();
			}
		}

		return entries;
	}

	void ContextMenu::showActions(Library::ContextMenu::Entries entries)
	{
		Library::ContextMenu::showActions(entries);

		for(auto it = m->entryActionMap.begin(); it != m->entryActionMap.end(); it++)
		{
			const auto entry = it.key();
			auto* action = it.value();
			action->setVisible(entries & entry);
		}
	}

	void ContextMenu::showDirectoryAction(ContextMenu::Entry entry, bool b)
	{
		auto entries = this->entries();
		if(b)
		{
			entries |= entry;
		}

		else
		{
			entries &= ~entry;
		}

		showActions(entries);
	}

	void ContextMenu::libraryMoveActionTriggered()
	{
		auto* action = dynamic_cast<QAction*>(sender());

		const auto libraryId = action->data().value<LibraryId>();
		emit sigMoveToLibrary(libraryId);
	}

	void ContextMenu::libraryCopyActionTriggered()
	{
		auto* action = dynamic_cast<QAction*>(sender());

		const auto libraryId = action->data().value<LibraryId>();
		emit sigCopyToLibrary(libraryId);
	}

	void ContextMenu::languageChanged()
	{
		Library::ContextMenu::languageChanged();

		if(m && m->actionRename)
		{
			m->actionRename->setText(Lang::get(Lang::Rename));
			m->actionRenameByTag->setText(tr("Rename by metadata"));
			m->actionCreateDirectory->setText(Lang::get(Lang::CreateDirectory));
			m->actionCollapseAll->setText(tr("Collapse all"));
			m->actionMoveToLibrary->setText(tr("Move to another library"));
			m->actionCopyToLibrary->setText(tr("Copy to another library"));
			m->actionViewInFileManager->setText(tr("View in file manager"));
		}
	}

	void ContextMenu::skinChanged()
	{
		Library::ContextMenu::skinChanged();

		if(m && m->actionRename)
		{
			m->actionViewInFileManager->setIcon(Gui::icon(Gui::FolderOpen));
			m->actionRename->setIcon(Gui::icon(Gui::Rename));
			m->actionRenameByTag->setIcon(Gui::icon(Gui::Rename));
			m->actionCreateDirectory->setIcon(Gui::icon(Gui::New));
		}
	}
}
