
/* 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 "PlaylistBottomBar.h"
#include "PlaylistBottomBarButton.h"
#include "PlaylistActionMenu.h"

#include "Components/DynamicPlayback/DynamicPlaybackChecker.h"
#include "Gui/Plugins/PlayerPluginHandler.h"
#include "Gui/Shutdown/GUI_Shutdown.h"
#include "Gui/Utils/GuiUtils.h"
#include "Gui/Utils/Icons.h"
#include "Utils/Language/Language.h"
#include "Utils/Macros.h"
#include "Utils/Message/Message.h"
#include "Utils/Playlist/PlaylistMode.h"
#include "Utils/Settings/Settings.h"

#include <QFile>
#include <QHBoxLayout>
#include <QPushButton>
#include <QSpacerItem>

using Playlist::BottomBar;

namespace
{
	Playlist::BottomBarButton* createButton(QWidget* parent, const Gui::IconName iconName,
	                                        const Gui::IconMode iconMode = Gui::ForceSayonaraIcon)
	{
		return new Playlist::BottomBarButton{Gui::icon(iconName, iconMode), parent};
	}
}

struct BottomBar::Private
{
	Mode plm;
	DynamicPlaybackChecker* dynamicPlaybackChecker;
	PlayerPlugin::Handler* playerPluginHandler;
	Shutdown* shutdown;

	BottomBarButton* btnRep1;
	BottomBarButton* btnRepall;
	BottomBarButton* btnAppend;
	BottomBarButton* btnDynamic;
	BottomBarButton* btnShuffle;
	BottomBarButton* btnGapless;
	BottomBarButton* btnShutdown;

	Private(DynamicPlaybackChecker* dynamicPlaybackChecker, PlayerPlugin::Handler* playerPluginHandler,
	        Shutdown* shutdown, BottomBar* parent) :
		plm{GetSetting(Set::PL_Mode)},
		dynamicPlaybackChecker{dynamicPlaybackChecker},
		playerPluginHandler{playerPluginHandler},
		shutdown{shutdown},
		btnRep1{createButton(parent, Gui::Repeat1)},
		btnRepall{createButton(parent, Gui::RepeatAll)},
		btnAppend{createButton(parent, Gui::Append)},
		btnDynamic{createButton(parent, Gui::Dynamic)},
		btnShuffle{createButton(parent, Gui::Shuffle)},
		btnGapless{createButton(parent, Gui::Gapless)},
		btnShutdown{createButton(parent, Gui::Shutdown, Gui::Automatic)} {}

	[[nodiscard]] QList<BottomBarButton*> buttons() const
	{
		return {
			btnRep1,
			btnAppend,
			btnRepall,
			btnDynamic,
			btnShuffle,
			btnGapless,
			btnShutdown
		};
	}
};

BottomBar::BottomBar(QWidget* parent) :
	Widget(parent) {}

BottomBar::~BottomBar() = default;

void BottomBar::init(DynamicPlaybackChecker* dynamicPlaybackChecker, PlayerPlugin::Handler* playerPluginHandler,
                     Shutdown* shutdown)
{
	m = Pimpl::make<Private>(dynamicPlaybackChecker, playerPluginHandler, shutdown, this);

	using namespace Gui;

	QLayout* layout = new QHBoxLayout(this);
	this->setLayout(layout);

	layout->addWidget(m->btnRep1);
	layout->addWidget(m->btnRepall);
	layout->addWidget(m->btnShuffle);
	layout->addWidget(m->btnDynamic);
	layout->addWidget(m->btnAppend);
	layout->addWidget(m->btnGapless);
	layout->addItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding));
	layout->addWidget(m->btnShutdown);

	layout->setContentsMargins(3, 2, 3, 5);
	layout->setSpacing(5);

	const auto buttons = m->buttons();
	for(auto* button: buttons)
	{
		button->setCheckable(true);
		button->setFlat(false);
		button->setFocusPolicy(Qt::NoFocus);
	}

	m->btnGapless->setCheckable(false);

	m->btnRep1->setChecked(Mode::isActive(m->plm.rep1()));
	m->btnRepall->setChecked(Mode::isActive(m->plm.repAll()));
	m->btnAppend->setChecked(Mode::isActive(m->plm.append()));
	m->btnDynamic->setChecked(Mode::isActive(m->plm.dynamic()));
	m->btnShuffle->setChecked(Mode::isActive(m->plm.shuffle()));
	m->btnShutdown->setVisible(false);

	connect(m->btnRep1, &QPushButton::clicked, this, &BottomBar::rep1Checked);
	connect(m->btnRepall, &QPushButton::clicked, this, &BottomBar::repAllChecked);
	connect(m->btnAppend, &QPushButton::released, this, &BottomBar::changePlaylistMode);
	connect(m->btnShuffle, &QPushButton::clicked, this, &BottomBar::shuffleChecked);
	connect(m->btnDynamic, &QPushButton::released, this, &BottomBar::changePlaylistMode);
	connect(m->btnGapless, &QPushButton::clicked, this, &BottomBar::gaplessClicked);

	connect(m->btnShutdown, &QPushButton::clicked, this, &BottomBar::shutdownClicked);
	connect(m->shutdown, &Shutdown::sigStarted, this, &BottomBar::shutdownStarted);
	connect(m->shutdown, &Shutdown::sigStopped, this, &BottomBar::shutdownClosed);

	ListenSetting(Set::PL_Mode, BottomBar::playlistModeSettingChanged);
}

void BottomBar::rep1Checked(bool checked)
{
	if(checked)
	{
		m->btnRepall->setChecked(false);
		m->btnShuffle->setChecked(false);
	}

	changePlaylistMode();
}

void BottomBar::repAllChecked(bool checked)
{
	if(checked)
	{
		m->btnRep1->setChecked(false);
	}

	changePlaylistMode();
}

void BottomBar::shuffleChecked(bool checked)
{
	if(checked)
	{
		m->btnRep1->setChecked(false);
	}

	changePlaylistMode();
}

void BottomBar::changePlaylistMode()
{
	parentWidget()->setFocus();

	auto plm = GetSetting(Set::PL_Mode);

	plm.setAppend(m->btnAppend->isChecked(), m->btnAppend->isEnabled());
	plm.setRep1(m->btnRep1->isChecked(), m->btnRep1->isEnabled());
	plm.setRepAll(m->btnRepall->isChecked(), m->btnRepall->isEnabled());
	plm.setShuffle(m->btnShuffle->isChecked(), m->btnShuffle->isEnabled());
	plm.setDynamic(m->btnDynamic->isChecked(), m->btnDynamic->isEnabled());

	if(const auto isEqual = (plm == m->plm); !isEqual)
	{
		m->plm = plm;
		SetSetting(Set::PL_Mode, m->plm);
	}
}

void BottomBar::gaplessClicked()
{
	m->playerPluginHandler->showPlugin("Crossfader");
}

void BottomBar::playlistModeSettingChanged()
{
	const auto plm = GetSetting(Set::PL_Mode);
	if(plm == m->plm)
	{
		return;
	}

	m->plm = plm;

	m->btnAppend->setChecked(Mode::isActive(m->plm.append()));
	m->btnRep1->setChecked(Mode::isActive(m->plm.rep1()));
	m->btnRepall->setChecked(Mode::isActive(m->plm.repAll()));
	m->btnShuffle->setChecked(Mode::isActive(m->plm.shuffle()));
	m->btnDynamic->setChecked(Mode::isActive(m->plm.dynamic()));

	m->btnRep1->setEnabled(Mode::isEnabled(m->plm.rep1()));
	m->btnAppend->setEnabled(Mode::isEnabled(m->plm.append()));
	m->btnRepall->setEnabled(Mode::isEnabled(m->plm.repAll()));
	m->btnDynamic->setEnabled(Mode::isEnabled(m->plm.dynamic()));
	m->btnShuffle->setEnabled(Mode::isEnabled(m->plm.shuffle()));
	m->btnGapless->setEnabled(Mode::isEnabled(m->plm.gapless()));

	checkDynamicPlayButton();
}

void BottomBar::checkDynamicPlayButton()
{
	const auto tooltip = !m->dynamicPlaybackChecker->isDynamicPlaybackPossible()
	                     ? QStringLiteral("%1\n%2")
	                       .arg(Lang::get(Lang::DynamicPlayback))
	                       .arg(tr("Please set library path first"))
	                     : Lang::get(Lang::DynamicPlayback);

	m->btnDynamic->setToolTip(tooltip);
}

void BottomBar::languageChanged()
{
	m->btnAppend->setToolTip(Lang::get(Lang::Append));
	m->btnDynamic->setToolTip(Lang::get(Lang::DynamicPlayback));
	m->btnGapless->setToolTip(Lang::get(Lang::GaplessPlayback));
	m->btnRep1->setToolTip(Lang::get(Lang::Repeat1));
	m->btnRepall->setToolTip(Lang::get(Lang::RepeatAll));
	m->btnShuffle->setToolTip(Lang::get(Lang::Shuffle));
	m->btnShutdown->setToolTip(
		Lang::get(Lang::Shutdown) + QStringLiteral(": ") + Lang::get(Lang::Cancel));

	checkDynamicPlayButton();
}

void BottomBar::skinChanged()
{
	const auto fm = this->fontMetrics();
	auto width = (Gui::Util::textWidth(fm, QStringLiteral("m")) * 250) / 100;
	width = std::max(29, width);

	const auto buttons = m->buttons();
	for(auto* button: buttons)
	{
		button->setFixedSize(QSize{width, width});
	}
}

void BottomBar::showEvent(QShowEvent* e)
{
	Gui::Widget::showEvent(e);
	skinChanged();
}

void BottomBar::resizeEvent(QResizeEvent* e)
{
	Gui::Widget::resizeEvent(e);
	skinChanged();
}

void BottomBar::shutdownClicked()
{
	const auto answer = Message::question_yn(tr("Cancel shutdown?"));
	if(answer == Message::Answer::Yes)
	{
		m->shutdown->stop();
	}
}

void BottomBar::shutdownStarted([[maybe_unused]] MilliSeconds time2go)
{
	const auto b = m->shutdown->isRunning();
	m->btnShutdown->setVisible(b);
	m->btnShutdown->setChecked(b);
}

void BottomBar::shutdownClosed()
{
	const auto b = m->shutdown->isRunning();
	m->btnShutdown->setVisible(b);
	m->btnShutdown->setChecked(b);
}
