/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
 *
 */
/*
 * Copyright (c) 2008 Sander Knopper (sander AT knopper DOT tk) and
 *                    Roeland Douma (roeland AT rullzer DOT com)
 *
 * This file is part of QtMPC.
 *
 * QtMPC 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 2 of the License, or
 * (at your option) any later version.
 *
 * QtMPC 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 QtMPC.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H

#include "config.h"
#include "models/playqueuemodel.h"
#include "models/playqueueproxymodel.h"
#include "mpd-interface/mpdconnection.h"
#include "mpd-interface/mpdstatus.h"
#include "mpd-interface/song.h"
#include "ui_mainwindow.h"
#include <QMainWindow>
#include <QStringList>
#include <QToolButton>
#include <qglobal.h>

class Action;
class ActionCollection;
class MainWindow;
class Page;
class LibraryPage;
class FolderPage;
class PlaylistsPage;
class OnlineServicesPage;
#ifdef ENABLE_DEVICES_SUPPORT
class DevicesPage;
#endif
class SearchPage;
class QAbstractItemView;
#ifdef QT_QTDBUS_FOUND
class Mpris;
#endif
class QTimer;
class QPropertyAnimation;
class QActionGroup;
class QDateTime;
class QMenu;
class QSessionManager;
class TrayItem;
class HttpStream;
class MPDStatus;
struct MPDConnectionDetails;
struct Output;
#if defined Q_OS_WIN
class ThumbnailToolBar;
#endif
#ifdef Q_OS_MAC
class DockMenu;
#endif
#ifdef MAC_MEDIAPLAYER_FOUND
class MacNowPlaying;
#endif

// Dummy classes so that when class name is saved to the config file, we get a more meaningful name than QWidget!!!
class PlayQueuePage : public QWidget {
	Q_OBJECT
public:
	PlayQueuePage(QWidget* p) : QWidget(p) {}
};
class ContextPage : public QWidget {
	Q_OBJECT
public:
	ContextPage(QWidget* p) : QWidget(p) {}
};

class MainWindow : public QMainWindow, private Ui::MainWindow {
	Q_OBJECT

	Q_PROPERTY(QStringList listActions READ listActions)

public:
	enum Pages {
		PAGE_PLAYQUEUE,
		PAGE_LIBRARY,
		PAGE_FOLDERS,
		PAGE_PLAYLISTS,
		PAGE_ONLINE,
#ifdef ENABLE_DEVICES_SUPPORT
		PAGE_DEVICES,
#endif
		PAGE_SEARCH,
		PAGE_CONTEXT
	};

	MainWindow(QWidget* parent = nullptr);
	~MainWindow() override;

	QList<Song> selectedSongs() const;
	QStringList listActions() const;

protected:
	void keyPressEvent(QKeyEvent* event) override;
	void showEvent(QShowEvent* event) override;
	void closeEvent(QCloseEvent* event) override;
	void resizeEvent(QResizeEvent* event) override;

private:
#if !defined Q_OS_WIN
	void addMenuAction(QMenu* menu, QAction* action);
#endif
	void setupTrayIcon();

Q_SIGNALS:
	// These are for communicating with MPD object (which is in its own thread, so need to talk via signal/slots)
	void setDetails(const MPDConnectionDetails& det);
	void pause(bool p);
	void play();
	void stop(bool afterCurrent = false);
	void terminating();
	void getStatus();
	void playListInfo();
	void currentSong();
	void setSeekId(qint32, quint32);
	void startPlayingSongId(qint32);
	void setVolume(int);
	void changePartition(QString partition);
	void newPartition(QString name);
	void delPartition(QString name);
	void outputs();
	void enableOutput(quint32 id, bool);
	void moveOutput(QString name);
	void setPriority(const QList<qint32>& ids, quint8 priority, bool decreasePriority);
	void addSongsToPlaylist(const QString& name, const QStringList& files);
	void showPreferencesPage(const QString& page);
	void playNext(const QList<quint32>& items, quint32 pos, quint32 size);

public Q_SLOTS:
	void showError(const QString& message, bool showActions = false);
	void showInformation(const QString& message);
	void dynamicStatus(const QString& message);
	void setCollection(const QString& collection);
	void mpdConnectionName(const QString& name);
	void hideWindow();
	void restoreWindow();
	void load(const QStringList& urls) { PlayQueueModel::self()->load(urls, -1); }
	void showAboutDialog();
	void mpdConnectionStateChanged(bool connected);
	void playQueueItemsSelected(bool s);
	void showPreferencesDialog(const QString& page = QString());
	void quit();
	void commitDataRequest(QSessionManager& mgr);
	void updateSettings();
	void toggleOutput();
	void moveOutputToThisPartition();
	void selectPartition();
	void createNewPartition();
	void deleteAPartition();
	void changeConnection();
	void connectToMpd();
	void connectToMpd(const MPDConnectionDetails& details);
	void streamUrl(const QString& u);
	void refreshDbPromp();
	void showServerInfo();
	void stopPlayback();
	void stopAfterCurrentTrack();
	void stopAfterTrack();
	void playPauseTrack();
	void setPosition();
	void searchPlayQueue();
	void realSearchPlayQueue();
	void playQueueSearchActivated(bool a);
	void updatePlayQueue(const QList<Song>& songs, bool isComplete);
	void updateCurrentSong(Song song, bool wasEmpty = false);
	void scrollPlayQueue(bool wasEmpty = false);
	void updateStatus();
	void playQueueItemActivated(const QModelIndex&);
	void clearPlayQueue();
	void centerPlayQueue();
	void removeFromPlayQueue() { PlayQueueModel::self()->remove(playQueueProxyModel.mapToSourceRows(playQueue->selectedIndexes())); }
	void replacePlayQueue() { appendToPlayQueue(MPDConnection::ReplaceAndplay); }
	void appendToPlayQueue() { appendToPlayQueue(MPDConnection::Append); }
	void appendToPlayQueueAndPlay() { appendToPlayQueue(MPDConnection::AppendAndPlay); }
	void addToPlayQueueAndPlay() { appendToPlayQueue(MPDConnection::AddAndPlay); }
	void insertIntoPlayQueue() { appendToPlayQueue(MPDConnection::AddAfterCurrent); }
	void addWithPriority();
	void addToNewStoredPlaylist();
	void addToExistingStoredPlaylist(const QString& name) { addToExistingStoredPlaylist(name, playQueue->hasFocus()); }
	void addToExistingStoredPlaylist(const QString& name, bool pq);
	void addStreamToPlayQueue();
	void addLocalFilesToPlayQueue();
	void removeItems();
	void checkMpdAccessibility();
	void cropPlayQueue() { PlayQueueModel::self()->crop(playQueueProxyModel.mapToSourceRows(playQueue->selectedIndexes())); }
	void updatePlayQueueStats(int songs, quint32 time);
	void expandOrCollapse(bool saveCurrentSize = true);
	void showSongInfo();
	void fullScreen();
	void sidebarModeChanged();
	void currentTabChanged(int index);
	void tabToggled(int index);
	void showPlayQueue() { showTab(PAGE_PLAYQUEUE); }
	void showLibraryTab() { showTab(PAGE_LIBRARY); }
	void showFoldersTab() { showTab(PAGE_FOLDERS); }
	void showPlaylistsTab() { showTab(PAGE_PLAYLISTS); }
	void showOnlineTab() { showTab(PAGE_ONLINE); }
	void showContextTab() { showTab(PAGE_CONTEXT); }
	void showDevicesTab()
	{
#ifdef ENABLE_DEVICES_SUPPORT
		showTab(PAGE_DEVICES);
#endif
	}
	void showSearchTab() { showTab(PAGE_SEARCH); }
	void toggleSplitterAutoHide();
	void locateTracks(const QList<Song>& songs);
	void locateTrack();
	void moveSelectionAfterCurrentSong();
	void moveSelectionAtQueueStart();
	void moveSelectionAtQueueEnd();
	void locateArtist(const QString& artist);
	void locateAlbum(const QString& artist, const QString& album);
	void editTags();
	void organiseFiles();
	void addToDevice(const QString& udi);
	void deleteSongs();
	void copyToDevice(const QString& from, const QString& to, const QList<Song>& songs);
	void deleteSongs(const QString& from, const QList<Song>& songs);
	void replayGain();
	void setCover();
	void showPlayQueueSearch();
	void showSearch();
	void expandAll();
	void collapseAll();
	void checkMpdDir();
	void partitionsUpdated(const QList<Partition>& outputs);
	void outputsUpdated(const QList<Output>& outputs);
	void updateConnectionsMenu();
	void controlConnectionsMenu(bool enable = true);
	void controlDynamicButton();
	void setRating();
	void triggerAction(const QString& name);

private:
	bool canClose();
	void expand();
	bool canShowDialog();
	void enableStopActions(bool enable);
	void updateStatus(MPDStatus* const status);
	void readSettings();
	void appendToPlayQueue(int action, quint8 priority = 0, bool decreasePriority = false);
	bool currentIsStream() const { return PlayQueueModel::self()->rowCount() && -1 != current.id && current.isStream(); }
	void updateWindowTitle();
	void showTab(int page) { tabWidget->setCurrentIndex(page); }
	void updateNextTrack(int nextTrackId);
	void updateActionToolTips();
	void startContextTimer();
	int calcMinHeight();
	int calcCollapsedSize();
	void setCollapsedSize();
	void controlView(bool forceUpdate = false);
	void moveSelection(int position);

private Q_SLOTS:
	void controlPlayQueueButtons();
	void toggleContext();
	void initMpris();
	void toggleMenubar();
	void paletteChanged();

private:
	int prevPage;
	MPDState lastState;
	qint32 lastSongId;
	QString lastPartition;
	PlayQueueProxyModel playQueueProxyModel;
	bool autoScrollPlayQueue;
	bool singlePane;
	bool shown;
	Action* prefAction;
	Action* refreshDbAction;
	Action* doDbRefreshAction;
	Action* connectAction;
	Action* connectionsAction;
	Action* partitionsAction;
	Action* outputsAction;
	QActionGroup* connectionsGroup;
	QActionGroup* partitionsGroup;
	Action* stopAfterTrackAction;
	Action* addPlayQueueToStoredPlaylistAction;
	Action* clearPlayQueueAction;
	Action* centerPlayQueueAction;
	Action* expandInterfaceAction;
	Action* cropPlayQueueAction;
	Action* addStreamToPlayQueueAction;
	Action* addLocalFilesToPlayQueueAction;
	Action* randomPlayQueueAction;
	Action* repeatPlayQueueAction;
	Action* singlePlayQueueAction;
	Action* consumePlayQueueAction;
	Action* searchPlayQueueAction;
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
	HttpStream* httpStream;
	Action* streamPlayAction;
#endif
	Action* songInfoAction;
	Action* fullScreenAction;
	Action* quitAction;
	Action* restoreAction;
	Action* locateAction;
	Action* locateTrackAction;
	Action* locateAlbumAction;
	Action* locateArtistAction;
	Action* playNextAction;
	Action* moveToBeginning;
	Action* moveToEnd;
#ifdef TagLib_FOUND
	Action* editPlayQueueTagsAction;
#endif
	Action* searchTabAction;
	Action* expandAllAction;
	Action* collapseAllAction;
	Action* serverInfoAction;
	Action* cancelAction;
	Action* ratingAction;
	TrayItem* trayItem;
	QPoint lastPos;
	QSize expandedSize;
	QSize collapsedSize;
	QSize previousSize;
	Song current;
	Page* currentPage;
	Action* showPlayQueueAction;
	QWidget* playQueuePage;
	Action* libraryTabAction;
	LibraryPage* libraryPage;
	Action* foldersTabAction;
	FolderPage* folderPage;
	Action* playlistsTabAction;
	PlaylistsPage* playlistsPage;
	Action* onlineTabAction;
	OnlineServicesPage* onlinePage;
	QWidget* contextPage;
#ifdef ENABLE_DEVICES_SUPPORT
	Action* devicesTabAction;
	Action* copyToDeviceAction;
	DevicesPage* devicesPage;
#endif
	SearchPage* searchPage;
#ifdef QT_QTDBUS_FOUND
	Mpris* mpris;
#endif
	QTimer* statusTimer;
	QTimer* playQueueSearchTimer;
#if !defined Q_OS_WIN && !defined Q_OS_MAC
	QTimer* mpdAccessibilityTimer;
	Action* showMenubarAction;
#endif
	QTimer* contextTimer;
	int contextSwitchTime;
	enum { CS_Init,
		   CS_Connected,
		   CS_Disconnected } connectedState;
	bool stopAfterCurrent;
	bool responsiveSidebar;
#if defined Q_OS_WIN
	ThumbnailToolBar* thumbnailTooolbar;
#endif
#ifdef Q_OS_MAC
	DockMenu* dockMenu;
#endif
#ifdef MAC_MEDIAPLAYER_FOUND
	MacNowPlaying* macNowPlaying;
#endif
	friend class TrayItem;
};

#endif
