/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * 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/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#pragma once

#include <QItemSelection>
#include <QMainWindow>
#include <QTimer>
#include <QMenu>

#include "src/datovka_shared/io/draft_db.h" /* DraftEntryList, DraftCounts are used in slots. Q_MOC_INCLUDE */
#include "src/datovka_shared/json/basic.h" /* Json::Int64StringList is used in slots. Q_MOC_INCLUDE */
#include "src/io/account_db.h"
#include "src/io/message_db.h"
#include "src/gui/dlg_import_zfo.h"
#include "src/gui/dlg_timestamp_expir.h"
#include "src/gui/mw_status.h"
#include "src/identifiers/composite.h" /* AcntIdToMsgIdListHash is used in slots. Q_MOC_INCLUDE */
#include "src/identifiers/message_id.h"
#include "src/json/message_id.h" /* Json::MsgId2List is used in slots. Q_MOC_INCLUDE */
#include "src/json/tag_assignment.h" /* Json::TagAssignmentList is used in slots. Q_MOC_INCLUDE */
#include "src/json/tag_entry.h" /* Json::TagEntryList is used in slots. Q_MOC_INCLUDE */
#include "src/models/accounts_model.h"
#include "src/models/attachments_model.h"
#include "src/models/collapsible_account_proxy_model.h"
#include "src/models/draft_model.h"
#include "src/models/messages_model.h"
#include "src/models/sort_filter_proxy_model.h"
#include "src/settings/account.h"
#include "src/single/single_instance.h"

class AcntId; /* Forward declaration. */
class AcntIdDb; /* Forward declaration. */
class MessageDbSet; /* Forward declaration. */
class Prefs; /* Forward declaration. */
class QComboBox; /* Forward declaration. */
class QLineEdit; /* Forward declaration. */
class QProgressBar; /* Forward declaration. */
class QUrl; /* Forward declaration. */

namespace Ui {
	class MainWindow;
}

/*!
 * @brief Main window.
 */
class MainWindow : public QMainWindow {
	Q_OBJECT

public:
	/*!
	 * @brief Destructor.
	 */
	~MainWindow(void);

	/*!
	 * @brief Set geometry from settings.
	 *
	 * @note It appears that window geometry must be set outside of main
	 *     window constructor in order to properly set splitter positions.
	 *
	 * @param[in] prefs Preferences.
	 */
	void loadWindowGeometry(const Prefs &prefs);

protected:
	/*!
	 * @brief Check if a worker is working on the background and show
	 *     a dialogue whether the user wants to close the application.
	 *
	 * @param[in,out] event Close event.
	 */
	virtual
	void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;

	/*!
	 * @brief Store original window position on window maximisation.
	 *
	 * @param[in] event Move event.
	 */
	virtual
	void moveEvent(QMoveEvent *event) Q_DECL_OVERRIDE;

	/*!
	 * @brief Store original window size on window maximisation.
	 *
	 * @param[in] event Resize event.
	 */
	virtual
	void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;

	/*!
	 * @brief Check window geometry, adjust size if window is too large for
	 *     desktop.
	 *
	 * @param[in] event Widget show event.
	 */
	virtual
	void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;

private:
	/*!
	 * @brief Performs initial user interface initialisation.
	 */
	void setUpUi(void);

	/*!
	 * @brief Load and apply settings from configuration.
	 */
	void loadSettings(void);

	/*!
	 * @brief Store settings to preferecnes database.
	 */
	void savePrefsSettings(void) const;

	/*!
	 * @brief Store current settings to INI file and preferences database.
	 */
	void saveSettings(void) const;

	/*!
	 * @brief Load sent/received messages column widths from settings.
	 */
	void loadMsgListPrefs(const Prefs &prefs);

	/*!
	 * @brief Save sent/received messages column widths into settings.
	 */
	void saveMsgListPrefs(Prefs &prefs) const;

	/*!
	 * @brief Connects top menu bar actions to appropriate slots.
	 */
	void topMenuConnectActions(void) const;

	/*!
	 * @brief Connect message-action-bar buttons to appropriate actions.
	 */
	void messageBarAssignActions(void);

	/*!
	 * @brief Connect settings container signals to appropriate slots.
	 */
	void settingsConnectActions(void);

	/*!
	 * @brief Connect database container signals to appropriate slots.
	 */
	void databaseConnectActions(void);

private slots:
	/*!
	 * @brief Stops workers and closes the window.
	 */
	void haltRequested(void);

	/*!
	 * @brief Shows the quit app dialogue.
	 */
	void viewAskCloseDlg(void);

	/*!
	 * @brief Quit app dialogue closed.
	 *
	 * @param[in] result Dialogue window closing status.
	 */
	void closedAskCloseDlg(int result);

/* File menu. */
	/*!
	 * @brief Downloads new messages from server for all accounts.
	 */
	void synchroniseAllAccounts(void);

	/*!
	 * @brief Show add new account dialogue.
	 */
	void viewAddAccountDlg(void);

	/*!
	 * @brief Removal confirmation dialogue.
	 */
	void viewRemoveAccountDlg(void);

	/*!
	 * @brief Show the all account properties dialogue.
	 */
	void viewManageAccountsDlg(void);

	/*!
	 * @brief Show import database directory dialogue.
	 */
	void viewImportDatabaseDlg(void);

	/*
	 * @brief Back up stored data.
	 *
	 * @param[in] automaticNotification True if automatically invoked.
	 */
	void viewDataBackupDlg(bool automaticNotification = false);

	/*!
	 * @brief Restore data from backup.
	 */
	void viewDataRestoreDlg(void);

	/*!
	 * @brief Proxy settings dialogue.
	 */
	void viewProxySettingsDlg(void);

	/*!
	 * @brief Records management dialogue.
	 */
	void viewRecordsManagementDlg(void);

	/*!
	 * @brief Obtain information about stored messages from records
	 *     management.
	 */
	void getStoredMsgInfoFromRecordsManagement(void);

	/*!
	 * @brief Obtain information about stored messages from records
	 *     management and upload missing messages.
	 */
	void checkUploadMessagesIntoRecordsManagement(void);

	/*
	 * @brief Edit the tag container settings.
	 */
	void editTagContSettings(void);

	/*!
	 * @brief Shows the application preferences dialogue.
	 */
	void viewPreferencesDlg(void);

/* Data box menu. */
	/*!
	 * @brief Downloads all messages from server for selected account.
	 */
	void synchroniseSelectedAccount(void);

	/*!
	 * @brief Downloads received messages from server for selected account.
	 */
	void synchroniseSelectedAccountReceived(void);

	/*!
	 * @brief Downloads sent messages from server for selected account.
	 */
	void synchroniseSelectedAccountSent(void);

	/*!
	 * @brief Create and send a new message from selected account.
	 */
	void viewCreateMessageDlg(void);

	/*!
	 * @brief Create and send an e-gov request.
	 */
	void viewCreateGovRequestDlg(void);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedRead(void);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedUnread(void);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedUnsettled(void);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedInProgress(void);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedSettled(void);

	/*!
	 * @brief Shows change password dialogue.
	 */
	void viewChangePasswordDlg(void);

	/*!
	 * @brief Shows account properties dialogue.
	 */
	void viewManageSelectedAccountDlg(void);

	/*!
	 * @brief Move selected account one position up.
	 */
	void moveSelectedAccountUp(void);

	/*!
	 * @brief Move selected account one position down.
	 */
	void moveSelectedAccountDown(void);

	/*!
	 * @brief Show change data directory dialogue.
	 */
	void viewChangeDataDirectoryDlg(void);

	/*!
	 * @brief Show message import from database dialogue.
	 */
	void viewImportMessagesFromDatabaseDlg(void);

	/*!
	 * @brief Show message import from ZFO files dialogue.
	 */
	void viewImportMessagesFromZfosDlg(void);

	/*!
	 * @brief Show vacuum message database dialogue.
	 */
	void viewVacuumMessageDatabaseDlg(void);

	/*!
	 * @brief Split message database slot.
	 */
	void viewSplitMessageDatabaseByYearsDlg(void);

/* Message menu. */
	/*!
	 * @brief Downloads attachments of selected messages.
	 */
	void downloadSelectedMessageAttachments(void);

	/*!
	 * @brief Create and send a message reply from selected account and
	 *     message.
	 */
	void viewReplyMessageDlg(void);

	/*!
	 * @brief Create and send a message containing as attachments
	 *     the selected messages in ZFO format.
	 */
	void viewForwardMessageDlg(void);

	/*!
	 * @brief Create and send a message. Use selected message as a template.
	 */
	void viewCreateMessageFromMessageDlg(void);

	/*!
	 * @brief View signature details dialogue.
	 */
	void viewSignatureDetailsDlg(void);

	/*!
	 * @brief Authenticate message dialogue.
	 */
	void viewAuthenticateMessageDlg(void);

	/*!
	 * @brief Open selected message in external application.
	 */
	void openSelectedMessageExternally(void);

	/*!
	 * @brief Open acceptance information of selected message in external
	 *     application.
	 */
	void openAcceptanceInfoExternally(void);

	/*!
	 * @brief Send message to records management.
	 */
	void viewSendSelectedMessageToRecordsManagementDlg(void);

	/*!
	 * @brief Export selected messages into ZFO files.
	 */
	void exportSelectedMessageZfos(void);

	/*!
	 * @brief Export selected acceptance information as ZFO files.
	 */
	void exportSelectedAcceptanceInfoZfos(void);

	/*!
	 * @brief Export selected acceptance information as PDF files.
	 */
	void exportSelectedAcceptanceInfoPdfs(void);

	/*!
	 * @brief Export selected message envelopes as PDF files.
	 */
	void exportSelectedEnvelopePdfs(void);

	/*!
	 * @brief Export selected message envelopes as PDF and attachment files.
	 */
	void exportSelectedEnvelopeAttachments(void);

	/*!
	 * @brief Sends selected messages as ZFO into default e-mail client.
	 */
	void createEmailWithZfos(void);

	/*!
	 * @brief Sends all attachments of selected messages into default
	 *     e-mail client.
	 */
	void createEmailWithAllAttachments(void);

	/*!
	 * @brief Sends selected message content into default e-mail client.
	 */
	void createEmailContentSelection(void);

	/*!
	 * @brief Save all attachments to selected directory dialogue.
	 */
	void viewSaveAllAttachmentsDlg(void);

	/*!
	 * @brief Saves selected attachments to files, each file separately.
	 */
	void viewSaveSelectedAttachmentsDlgs(void);

	/*!
	 * @brief Open attachment in default application.
	 *
	 * @param[in] index Attachment model index.
	 */
	void openSelectedAttachment(const QModelIndex &index = QModelIndex());

	/*!
	 * @brief Delete selected messages from local database and ISDS.
	 */
	void deleteSelectedMessages(void);

/* Tools menu. */
	/*!
	 * @brief Search data box dialogue.
	 */
	void viewFindDataBoxDlg(void);

	/*!
	 * @brief Authenticate message file dialogue.
	 */
	void viewAuthenticateMessageFileDlg(void);

	/*!
	 * @brief View message from file dialogue.
	 */
	void viewMessageFromZfoDlg(void);

	/*!
	 * @brief Show export correspondence overview dialogue.
	 */
	void viewExportCorrespondenceOverviewDlg(void);

	/*!
	 * @brief Show message timestamp expiration dialogue.
	 */
	void viewTimestampExpirationDlg(void);

	/*!
	 * @brief Show non-modal timestamp renewal dialogue window.
	 */
	void viewTimestampRenewalDlg(void);

	/*!
	 * @brief Timestamp renewal dialogue closed.
	 *
	 * @param[in] result Dialogue window closing status.
	 */
	void closeTimestampRenewalDlg(int result);

	/*!
	 * @brief Show non-modal search message dialogue window.
	 */
	void viewMessageSearchDlg(void);

	/*!
	 * @brief Message search dialogue closed.
	 *
	 * @param[in] result Dialogue window closing status.
	 */
	void closeMessageSearchDlg(int result);

	/*!
	 * @brief Show available tag manager dialogue window.
	 */
	void viewAvailableTagsDlg(void);

	/*!
	 * @brief Show convert and import from mobile app dialogue window.
	 */
	void viewConvertImportFromMobileAppDlg(void);

	/*!
	 * @brief Show convert and create zip archive for mobile app.
	 */
	void viewConvertDataForMobileAppDlg(void);

	/*!
	 * @brief Quit application and continue with database repair.
	 */
	void repairDatabaseFiles(void);

	/*!
	 * @brief Quit application and continue with database repair.
	 *
	 * @param[in] link File URL.
	 */
	void repairDatabaseFile(const QUrl &link);

	/*!
	 * @brief Store top tool bar visibility into preferences.
	 */
	void toolBarSettingsToggled(bool checked);

	/*!
	 * @brief Store attachment and message list tool bar visibility into preferences.
	 */
	void topPanelBarsToggled(bool checked);

	/*!
	 * @brief Show top tool bar configuration dialogue.
	 */
	void viewCustomiseToolBar(void);

	/*!
	 * @brief Show account list tool bar configuration dialogue.
	 */
	void viewCustomiseAccountBar(void);

	/*!
	 * @brief Show message list tool bar configuration dialogue.
	 */
	void viewCustomiseMessageBar(void);

	/*!
	 * @brief Show message detail tool bar configuration dialogue.
	 */
	void viewCustomiseDetailBar(void);

	/*!
	 * @brief Show attachment list tool bar configuration dialogue.
	 */
	void viewCustomiseAttachmentBar(void);

	/*!
	 * @brief Show non-modal log dialogue.
	 */
	void viewLogDlg(void);

	/*!
	 * @brief Log dialogue closed.
	 *
	 * @param[in] result Dialogue window closing status.
	 */
	void closedLogDlg(int result);

	/*!
	 * @brief Show application internal preferences dialogue.
	 */
	void viewAllSettingsDlg(void);

/* Help menu. */
	/*!
	 * @brief Show a dialogue window about the application.
	 */
	void viewAboutAppDlg(void);

	/*!
	 * @brief Open the homepage in the default internet browser.
	 */
	void openHomepageUrl(void) const;

	/*!
	 * @brief Open manual page in the default internet browser.
	 */
	void openHelpUrl(void) const;

/* Account context menu. */
	/*!
	 * @brief Mark all recently received messages in the current working
	 *     account.
	 */
	void accountMarkRecentReceivedRead(void);

	/*!
	 * @brief Mark all recently received messages in the current working
	 *     account.
	 */
	void accountMarkRecentReceivedUnread(void);

	/*!
	 * @brief Mark all recently received messages in the current working
	 *     account.
	 */
	void accountMarkRecentReceivedUnsettled(void);

	/*!
	 * @brief Mark all recently received messages in the current working
	 *     account.
	 */
	void accountMarkRecentReceivedInProgress(void);

	/*!
	 * @brief Mark all recently received messages in the current working
	 *     account.
	 */
	void accountMarkRecentReceivedSettled(void);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearRead(void);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearUnread(void);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearUnsettled(void);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearInProgress(void);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearSettled(void);

/* Message context menu. */
	/*!
	 * @brief Mark selected messages.
	 */
	void messageItemsSelectedMarkRead(void);

	/*!
	 * @brief Mark selected messages.
	 */
	void messageItemsSelectedMarkUnread(void);

	/*!
	 * @brief Mark selected messages.
	 */
	void messageItemsSelectedMarkUnsettled(void);

	/*!
	 * @brief Mark selected messages.
	 */
	void messageItemsSelectedMarkInProgress(void);

	/*!
	 * @brief Mark selected messages.
	 */
	void messageItemsSelectedMarkSettled(void);

/* Draft context menu. */

	/*!
	 * @brief Delete selected drafts.
	 */
	void deleteSelectedDrafts(void);

/* Filter-field-related actions. */
	/*!
	 * @brief Show message list or draft list filter.
	 */
	void showFilter(void);

	/*!
	 * @brief Show message list filter.
	 */
	void showMessageFilter(void);

	/*!
	 * @brief Hide message list filter.
	 */
	void hideMessageFilter(void);

	/*!
	 * @brief Show draft list filter.
	 */
	void showDraftFilter(void);

	/*!
	 * @brief Hide draft list filter.
	 */
	void hideDraftFilter(void);

/* Window state change. */
	/*!
	 * @brief Enable actions and other controls according to status.
	 */
	void updateActionActivation(void);

	/*!
	 * @brief Updates account and message selection.
	 *
	 * @param[in] current Currently selected account list index.
	 * @param[in] previous Previously selected account list index.
	 */
	void updateAccountSelection(const QModelIndex &current,
	    const QModelIndex &previous = QModelIndex());

	/*!
	 * @brief Updates message selection.
	 *
	 * @param[in] selected Newly selected indexes.
	 * @param[in] deselect Deselected indexes.
	 */
	void updateMessageSelection(const QItemSelection &selected,
	    const QItemSelection &deselected = QItemSelection());

	/*!
	 * @brief Updates daft selection.
	 *
	 * @param[in] selected Newly selected indexes.
	 * @param[in] deselect Deselected indexes.
	 */
	void updateDraftSelection(const QItemSelection &selected,
	    const QItemSelection &deselected = QItemSelection());

	/*!
	 * @brief Reload model and widget content according to account
	 *     selection.
	 */
	void adaptToAccountSelection(void);

	/*!
	 * @brief Reload model and widget content according to message
	 *     selection.
	 */
	void adaptToMessageSelection(void);

	/*!
	 * @brief Reload widget content according to attachment selection.
	 *
	 * @param[in] selected Newly selected indexes.
	 * @param[in] deselect Deselected indexes.
	 */
	void adaptToAttachmentSelection(const QItemSelection &selected,
	    const QItemSelection &deselected = QItemSelection());

/* Mouse on widget clicks. */
	/*!
	 * @brief Generates a context menu for the menu bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewMenuBarContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu for the top tool bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewToolBarContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu for the account list tool bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewAccountToolBarContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu for the message list tool bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewMessageToolBarContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu for the message detail tool bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewDetailToolBarContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu for the attachment list tool bar.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewAttachmentToolBarContextMenu(const QPoint &point);

	/*!
	 * @brief Show classic tag assignment dialogue or pop-up.
	 */
	void viewTagAssignmentInterface(void);

	/*!
	 * @brief Show classic tag assignment dialogue.
	 */
	void viewTagAssignmentDialogue(void);

	/*!
	 * @brief Show tag assignment pop-up.
	 */
	void viewTagAssignmentPopup(void);

	/*!
	 * @brief Enable timestamp tracking for selected messages.
	 *
	 * @param[in] enable Whether to enable/disable tracking.
	 */
	void toggleTimestampTracking(bool enable);

/* Mouse on view clicks. */
	/*!
	 * @brief Generates a context menu depending on the item and selection
	 *     it was invoked on.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewAccountListContextMenu(const QPoint &point);

	/*!
	 * @brief Create custom context menu when clicking on anchors in the
	 *     account text info.
	 */
	void viewAccountTextInfoContextMenu(const QPoint &point);

	/*!
	 * @brief Open an URL when clicked on a link in the account text info.
	 *
	 * @param[in] link File URL.
	 */
	void viewAccountTextInfoAnchorClicked(const QUrl &link);

	/*!
	 * @brief Generates a context menu depending on the item and selection
	 *     it was invoked on.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewMessageListContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu depending on the item and selection
	 *     it was invoked on.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewAttachmentListContextMenu(const QPoint &point);

	/*!
	 * @brief Generates a context menu depending on the item and selection
	 *     it was invoked on.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewDraftListContextMenu(const QPoint &point);

	/*!
	 * @brief Used for toggling the message read state.
	 *
	 * @param[in] index Message model index.
	 */
	void messageItemClicked(const QModelIndex &index);

	/*!
	 * @brief Handle message double click.
	 */
	void viewSelectedMessage(void);

	/*!
	 * @brief Handle draft double click.
	 */
	void openSelectedDraft(void);

/* Handle settings changes. */
	/*!
	 * @brief Store INI settings.
	 */
	void watchSettingsChange(void);

/* Handle model signals. */
	/*!
	 * @brief Offer attachment download for supplied messages.
	 *
	 * @param[in] acntMsgIds List of message identifiers for respective
	 *                       accounts.
	 */
	void offerDownloadForMessages(const AcntIdToMsgIdListHash &acntMsgIds);

/* Handle database signals. */
	/*!
	 * @brief Update window data when message locally read status changes.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgIds Message identifiers.
	 * @param[in] read New locally read status.
	 */
	void watchChangedLocallyRead(const AcntId &acntId,
	    const QList<MsgId> &msgIds, bool read);

	/*!
	 * @brief Update window data when message process state changes.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgIds Message identifiers.
	 * @param[in] state New message state.
	 */
	void watchChangedProcessState(const AcntId &acntId,
	    const QList<MsgId> &msgIds, enum MessageDb::MessageProcessState state);

	/*!
	 * @brief Update window data when complete message has been written
	 *     to database.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgId Message identifier.
	 * @param[in] direction Sent or received messages
	 *                      (enum MessageDirection).
	 */
	void watchMessageInserted(const AcntId &acntId, const MsgId &msgId,
	    int direction);

	/*!
	 * @brief Update window data when message deleted.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgId Message identifier.
	 */
	void watchMessageDataDeleted(const AcntId &acntId, const MsgId &msgId);

	/*!
	 * @brief Update model data when tags updated.
	 *
	 * @param[in] entries Updated tag entries.
	 */
	void watchTagsUpdated(const Json::TagEntryList &entries);

	/*!
	 * @brief Update model data when tags deleted.
	 *
	 * @param[in] ids Deleted tag identifiers.
	 */
	void watchTagsDeleted(const Json::Int64StringList &ids);

	/*!
	 *  @brief Update model data when tag assignment changes.
	 *
	 *  @param[in] assignments Updated tag assignments.
	 */
	void watchTagAssignmentChanged(const Json::TagAssignmentList &assignments);

	/*!
	 * @brief Action when tag client is connected.
	 */
	void watchTagContConnected(void);

	/*!
	 * @brief Action when tag client is disconnected.
	 */
	void watchTagContDisconnected(void);

	/*!
	 * @brief Action when tag container is reset.
	 */
	void watchTagContReset(void);

	/*!
	 * @brief Update model data when timestamp tracking enabled.
	 *
	 * @param[in] msgIds Message identifiers.
	 * @param[in] acntId Account identifier.
	 */
	void watchIdentificationsInserted(const Json::MsgId2List &msgIds,
	    const AcntId &acntId);

	/*!
	 * @brief Update model data when timestamp tracking disabled.
	 *
	 * @param[in] msgIds Message identifiers.
	 */
	void watchIdentificationsDeleted(const Json::MsgId2List &msgIds);

	/*!
	 * @brief Update model when draft entries inserted.
	 *
	 * @param[in] entries Inserted entries.
	 */
	void watchDraftsInserted(const DraftEntryList &entries);

	/*!
	 * @brief Update model when draft entries modified.
	 *
	 * @param[in] entries Modified draft entries.
	 */
	void watchDraftsUpdated(const DraftEntryList &entries);

	/*!
	 * @brief Update model when draft entries deleted.
	 *
	 * @param[in] ids Deleted draft identifiers.
	 */
	void watchDraftsDeleted(const Json::Int64StringList &ids);

	/*!
	 * @brief Update model when draft entries deleted.
	 *
	 * @param[in] draftCounts Draft counts for accounts where it has changed.
	 */
	void watchDraftCountChanged(const DraftCounts &draftCounts);

	/*!
	 * @brief Update model data when records management entry is deleted.
	 *
	 * @param[in] dmIds List of message identifiers.
	 */
	void watchRmMsgEntriesDeleted(const QList<qint64> &dmIds);

	/*!
	 * @brief Update model data when records management entry has been changed.
	 *
	 * @param[in] dmId Message identifier.
	 * @param[in] locations List of locations.
	 */
	void watchRmMsgEntryUpdated(qint64 dmId, const QStringList &locations);

	/*!
	 * @brief Watch changes in preferences. Handle configuration signals.
	 *
	 * @param[in] valueType Utilises enum PrefsDb::ValueType values.
	 * @param[in] name Entry name.
	 * @param[in] value Entry value holding the respective type.
	 */
	void watchPrefsModification(int valueType, const QString &name,
	    const QVariant &value);

private:
	Ui::MainWindow *ui; /*!< User interface as generated from ui files. */

	MWLockedStatus m_selectionStatus; /*!< Holds element selection information. */

// Below this line lies code that has to be refactored.

public:
	/*!
	 * @brief Constructor.
	 *
	 * @param[in] parent Parent widget.
	 */
	explicit MainWindow(QWidget *parent = Q_NULLPTR);

	/*!
	 * @brief Connects to ISDS and downloads basic information about the
	 *     user.
	 *
	 * @param acntId Account identifier.
	 * @param[in] shadow True to indicate shadow account.
	 * @return True on success.
	 */
	bool connectToIsds(const AcntId &acntId, bool shadow = false);

public slots:
	/*!
	 * @brief Changes the application theme.
	 *
	 * @param[in] index Theme index.
	 */
	void changeTheme(int index);

private slots:
	/*!
	 * @brief Refresh account list.
	 */
	void refreshAccountList(const AcntId &acntId);

	/*!
	 * @brief Display a status bar notification that database file cannot
	 *     be opened.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] fileName Database file name.
	 */
	void watchOpeningFailed(const AcntId &acntId, const QString &fileName);

	/*!
	 * @brief Processes messages from single instance emitter.
	 */
	void processSingleInstanceMessages(int msgType, const QString &msgVal);

	/*!
	 * @brief Fired when workers performing tasks on background have
	 *     finished.
	 */
	void backgroundWorkersFinished(void);

	/*!
	 * @brief Performs action depending on message download outcome.
	 */
	void collectDownloadMessageStatus(const AcntId &acntId, qint64 msgId,
	    const QDateTime &deliveryTime, int result, const QString &errDesc,
	    int processFlags, const QString &recMgmtHierarchyId);

	/*!
	 * @brief Performs action depending on message list download outcome.
	 */
	void collectDownloadMessageListStatus(const AcntIdDb &rAcntIdDb,
	    const AcntId &sAcntId, int direction, int result,
	    const QString &errDesc, bool add, int rt, int rn, int st, int sn);

	/*!
	 * @brief Shows a warning about not displayed messages.
	 */
	void collectDownloadedUnlistedMessages(const AcntIdDb &rAcntIdDb,
	    int direction, const QList<MsgId> &unlistedMsgIds);

	/*!
	 * @brief Collects information about import status.
	 */
	void collectImportZfoStatus(const QString &fileName, int result,
	    const QString &resultDesc);

	/*!
	 * @brief Performs action depending on message send outcome.
	 */
	void collectSendMessageStatus(const AcntId &acntId,
	    const QString &transactId, int result, const QString &resultDesc,
	    const QString &dbIDRecipient, const QString &recipientName,
	    bool isPDZ, bool isVodz, qint64 dmId, int processFlags,
	    const QString &recMgmtHierarchyId);

	/*!
	 * @brief Saves message selection.
	 */
	void messageItemStoreSelection(qint64 msgId);

	/*!
	 * @brief Saves message selection when model changes.
	 */
	void messageItemStoreSelectionOnModelChange(void);

	/*!
	 * @brief Restores message selection.
	 */
	void messageItemRestoreSelectionOnModelChange(void);

	/*!
	 * @brief Restores message selection.
	 */
	void messageItemRestoreSelectionAfterLayoutChange(void);

	/*!
	 * @brief Select account via username and focus on
	 *        message ID from search selection
	 */
	void messageItemFromSearchSelection(const AcntId &acntId, qint64 msgId,
	    const QString &deliveryYear, int msgType);

	/*!
	 * @brief Downloads new messages from server for all accounts
	 *     using available shadow accounts.
	 */
	void synchroniseAllShadowAccounts(void);

	/*!
	 * @brief Sends selected attachments into default e-mail client.
	 */
	void sendAttachmentsEmail(void);

	/*!
	 * @brief Filter listed messages.
	 */
	void filterMessages(const QString &text);

	/*!
	 * @brief Filter listed drafts.
	 */
	void filterDrafts(const QString &text);

	/*!
	 * @brief Set new sent/received message column widths.
	 */
	void onTableColumnResized(int index, int oldSize, int newSize);

	/*!
	 * @brief Set actual sort order for current column.
	 */
	void onTableColumnHeaderSectionClicked(int column);

	/*!
	 * @brief Set ProgressBar value and Status bar text.
	 */
	void updateProgressBar(const QString &label, int value);

	/*!
	 * @brief Set Status bar text.
	 */
	void updateStatusBarText(const QString &text);

	/*!
	 * @brief Clear progress bar text.
	 */
	void clearProgressBar(void);

	/*!
	 * @brief Clear status bar text.
	 */
	void clearStatusBar(void);

	/*!
	 * @brief Set and run any actions after main window has been created.
	 */
	void setWindowsAfterInit(void);

	/*!
	 * @brief set message process state into db
	 */
	void msgSetSelectedMessageProcessState(int stateIndex);

	/*!
	 * @brief Show information about import message results.
	 */
	void showImportMessageResults(const QString &userName,
	    const QStringList &errImportList, int totalMsgs, int importedMsgs);

	/*!
	 * @brief Populates the dock menu with active windows.
	 */
	void dockMenuPopulate(void);

	/*!
	 * @brief Handles the raise window actions.
	 */
	void dockMenuActionTriggerred(QAction *action);

	/*!
	 * @brief Show status bar text with timeout.
	 */
	void showStatusTextWithTimeout(const QString &qStr);

private:
	QTimer m_timerCheckReqHalt;
	QTimer m_timerSyncAccounts;
	QTimer m_timerShadowSyncAccounts;

	void aggregateDownloadMessageStatus(const AcntId &acntId, qint64 msgId,
	    bool forceProcess);

	/*!
	 * @brief Obtain working shadow account identifier.
	 *
	 * @param[in] rAcntId regular account identifier.
	 * @return Shadow account identifier, invalid value if nothing found.
	 */
	AcntId shadowAcntId(const AcntId &rAcntId);

	/*!
	 * @brief Downloads new message lists from ISDS server.
	 *
	 * @param[in] shadow True to use shadow accounts.
	 */
	void synchroniseAccounts(bool shadow);

	/*!
	 * @brief Downloads new messages from server for selected account.
	 *
	 * @param[in] rAcntId Regular account identifier.
	 * @param[in] sAcntId Shadow account identifier if shadow account
	 *                    should be used.
	 * @param[in] msgDirect Whether to download all, or only received or
	 *                      sent messages.
	 * @return True if some actions have been planned.
	 */
	bool synchroniseAccount(const AcntId &rAcntId,
	    const AcntId &sAcntId = AcntId(),
	    enum MessageDirection msgDirect = MSG_ALL);

	/*!
	 * @brief Remove account.
	 *
	 * @note This method intentionally doesn't take a reference argument
	 *     because it potentially deletes the source of the argument.
	 */
	void removeAccount(const AcntId acntId);

	/*!
	 * @brief Prepare message timestamp expiration based on action.
	 */
	void prepareMsgTmstmpExpir(enum DlgTimestampExpir::Action action);

	/*!
	 * @brief Shows tag editing dialogue.
	 *
	 * @no If no message identifiers are supplied then just the tags are
	 *     edited.
	 *
	 * @param[in] acntId Account identifier. Must be supplied when
	 *                   message identifiers are passed.
	 * @param[in] msgIdList Messages whose tags should be edited.
	 */
	void modifyTags(const AcntId &acntId, QList<qint64> msgIdList);

	/*!
	 * @brief Show status bar text permanently.
	 */
	void showStatusTextPermanently(const QString &qStr);

	/*!
	 * @brief Verify whether a connection to ISDS can be establisehd
	 *     and databox exists for the account.
	 */
	void getAccountUserDataboxInfo(AcntData accountInfo);

	/*!
	 * @brief Used to copy attachment(s) via event filter.
	 *
	 * @param[in] alPtr Pointer to attachment list view.
	 */
	static
	void copyAttachmentViaFilter(QObject *alPtr);

	/*!
	 * @brief Used to view selected message via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void viewSelectedMessageViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to delete selected message via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void deleteSelectedMessageViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to copy selected message(s) via event filter.
	 *
	 * @param[in] mlPtr Pointer to message list view.
	 */
	static
	void copySelectedMessageViaFilter(QObject *mlPtr);

	/*!
	 * @brief Used to clear message list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void clearMessageFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to view message list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void showMessageFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to hide message list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void hideMessageFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to open selected draft via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void openSelectedDraftViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to delete selected draft via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void deleteSelectedDraftViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to clear draft list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void clearDraftFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to view draft list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void showDraftFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Used to hide draft list filter line via event filter.
	 *
	 * @param[in] mwPtr Pointer to main window.
	 */
	static
	void hideDraftFilterLineViaFilter(QObject *mwPtr);

	/*!
	 * @brief Set info status bar from worker.
	 */
	void dataFromWorkerToStatusBarInfo(bool add,
	    int rt, int rn, int st, int sn);

	/*!
	 * @brief Save attachment identified by indexes to file.
	 */
	void saveAttachmentToFile(const AcntId &acntId, const MsgId &msgId,
	    const QModelIndex &attIdx);

	/*!
	 * @brief Return index for yearly entry with given properties.
	 */
	QModelIndex accountYearlyIndex(const AcntId &acntId,
	    const QString &year, int msgType) const;

	/*!
	 * @brief Check message time stamp expiration for account.
	 */
	void checkMsgsTmstmpExpiration(const AcntId &acntId,
	    const QStringList &filePathList);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedLocallyRead(bool read);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearLocallyRead(bool read);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkRecentReceivedLocallyRead(bool read);

	/*!
	 * @brief Mark all received messages in the current working account.
	 */
	void accountMarkReceivedProcessState(
	    enum MessageDb::MessageProcessState state);

	/*!
	 * @brief Mark all received messages in given year in the current
	 *     working account.
	 */
	void accountMarkReceivedYearProcessState(
	    enum MessageDb::MessageProcessState state);

	/*!
	 * @brief Mark recently received messages in the current
	 *     working account.
	 */
	void accountMarkRecentReceivedProcessState(
	    enum MessageDb::MessageProcessState state);

	/*!
	 * @brief Show send message dialog and send message(s).
	 *
	 * @param[in] action Defines send action (new,reply,forward,template).
	 * @param[in] composeSerialised Serialised content data.
	 * @param[in] draftEntry Draft entry.
	 */
	void showSendMessageDialog(int action,
	    const QString &composeSerialised = QString(),
	    const DraftEntry &draftEntry = DraftEntry());

	/*!
	 * @brief Set default account from settings.
	 */
	void setDefaultAccount(const Prefs &prefs);

	/*!
	 * @brief Set received message column widths.
	 */
	void setReceivedColumnWidths(void);

	/*!
	 * @brief Set sent message column widths.
	 */
	void setSentColumnWidths(void);

	/*!
	 * @brief Store geometry to settings.
	 */
	void saveWindowGeometry(Prefs &prefs) const;

	/*!
	 * @brief Store current account user name to settings.
	 */
	void saveAccountIndex(Prefs &prefs) const;

	/*!
	 * @brief Partially regenerates account model according to the database
	 *     content.
	 *
	 * @note The prohibitYearRemoval is a hack to prevent a nasty cascade
	 *     of actions resulting in undefined behaviour when removing
	 *     a freshly selected year node.
	 * @todo Remove the prohibitYearRemoval parameter. An extensive rewrite
	 *     of the main window logic may be required.
	 *
	 * @param[in] index Index identifying account.
	 * @param[in] prohibitYearRemoval Set to true if year nodes should not be removed.
	 * @return True on success.
	 *
	 * @note This function adds/removes nodes and does not set the
	 *     currentIndex back to its original position.
	 */
	bool regenerateAccountModelYears(const QModelIndex &index,
	    bool prohibitYearRemoval = false);

	/*!
	 * @brief Regenerates account model according to the database content.
	 *
	 * @return True on success.
	 *
	 * @note This function add/removes nodes and does not set the
	 *     currentIndex back to its original position.
	 */
	bool regenerateAllAccountModelYears(void);

	/*!
	 * @brief Delete message from long term storage in ISDS and
	 * local database - based on delFromIsds parameter.
	 *
	 * @return True if message has been removed from local database.
	 */
	bool eraseMessage(const AcntId &acntId, enum MessageDirection msgDirect,
	    const MsgId &msgId, bool delFromIsds);

	/*!
	 * @brief Send message to records management.
	 */
	void sendMessageToRecordsManagement(const AcntId &acntId, MsgId msgId,
	    const QString &recMgmtHierarchyId = QString());

	/*!
	 * @brief Performs a ISDS log-in operation.
	 *
	 * @param[in,out] acntSettings Account settings reference.
	 * @return True on successful login.
	 */
	bool logInGUI(AcntData &acntSettings);

	/*!
	 * @brief connect to ISDS databox from new account
	 */
	bool firstConnectToIsds(AcntData &accountInfo);

	/*!
	 * @brief Download complete message synchronously
	 * without worker and thread.
	 *
	 * @note Delivery time may change if invalid given.
	 *
	 * @param[in,out] msgId Message identifier.
	 * @return True on success.
	 */
	bool downloadCompleteMessage(MsgId &msgId);

	/*!
	 * @brief Shows notification dialogue and offers downloading of
	 *     missing message.
	 *
	 * @note Delivery time may change if invalid given.
	 *
	 * @param[in,out] msgId Message identifier.
	 * @param[in]     title Question dialogue title.
	 * @return True on success.
	 */
	bool messageMissingOfferDownload(MsgId &msgId, const QString &title);

	/*!
	 * @brief Set read status of selected messages.
	 */
	void messageItemsSetReadStatus(bool read);

	/*!
	 * @brief Set process status of selected messages.
	 */
	void messageItemsSetProcessStatus(
	    enum MessageDb::MessageProcessState state);

	/*!
	 * @brief Export message with expired time stamp to ZFO.
	 */
	void exportExpirMessagesToZFO(const AcntId &acntId,
	    const QList<MsgId> &expirMsgIds);

	/*!
	 * @brief Fill attachment binary content into attachment model.
	 */
	void ensureSelectedAttachmentsPresence(void);

	QString m_confDirName; /*!< Configuration directory location. */
	QString m_confFileName; /*!< Configuration file location. */

	AccountModel m_accountModel; /*!<
	                              * Account tree view model. Generated from
	                              * configuration file.
	                              */
	CollapsibleAccountProxyModel m_accountProxyModel;
	DbMsgsTblModel m_messageTableModel; /*!< Message table model. */
	SortFilterProxyModel m_messageListProxyModel; /*!<
	                                               * Used for message
	                                               * sorting and filtering.
	                                               */
	AttachmentTblModel m_attachmentModel; /*!< Attachment table model. */
	DraftTableModel m_draftModel; /*!< Draft table model. */
	SortFilterProxyModel m_draftListProxyModel; /*!<
	                                             * Used for message
	                                             * sorting and filtering.
	                                             */

	QString m_dfltFilerLineStyleSheet; /*!< Used to remember default line edit style. */

	QTimer m_messageMarker; /*!< Used for marking messages as read. */
	qint64 m_lastSelectedMessageId; /*!< Id of the last selected message. */
	qint64 m_lastStoredMessageId; /*!< Last stored message selection. */
	enum AccountModel::NodeType
	    m_lastSelectedAccountNodeType; /*!< Last selected position. */
	enum AccountModel::NodeType
	    m_lastStoredAccountNodeType; /*!< Last stored account position. */

	QDialog *m_timestampRenewalDlg; /*!< Non-null if timestamp renewal dialogue is active. */
	QDialog *m_messageSearchDlg; /*!< Non-null if message search dialogue is active. */
	QDialog *m_logDlg; /*!< Non-null if log dialogue is active. */
	QDialog *m_askCloseDlg; /*!< Non-null if ask cancel task dialogue is active. */

	QVector<int> m_colWidth; /*!< Message list column widths. */
	int m_sortCol; /*!< Column with enabled sorting. */
	QString m_sort_order;
	QRect m_geometry; /* Non-maximised window geometry. */

	QList<DbMsgsTblModel::AppendedCol> m_msgTblAppendedCols; /*< Appended columns. */

	/* User interface elements. */
	QAction *mui_firstUnconfigurableToolbarElement; /*!< First top tool bar element that cannot be configured. */
	QAction *mui_lastUnconfigurableAccountToolBarElement; /*!< Last account list tool bar element that cannot be configured. */
	QToolBar *mui_accountToolBar; /*!< Account list tool bar. */
	QAction *mui_lastUnconfigurableMessageToolBarElement; /*!< Last message list tool bar element that cannot be configured. */
	QAction *mui_firstUnconfigurableMessageToolBarElement; /*!< First message list tool bar element that cannot be configured. */
	QToolBar *mui_messageToolBar; /*!< Message list tool bar. */
	QAction *mui_lastUnconfigurableDetailToolBarElement; /*!< Last message detail tool bar element that cannot be configured. */
	QComboBox *mui_messageStateCombo; /*!< Message state combo box placed on the message detail tool bar. */
	QToolBar *mui_detailToolBar; /*!< Message detail tool bar. */
	QAction *mui_lastUnconfigurableAttachmentToolBarElement; /*!< Last attachment list tool bar element that cannot be configured. */
	QToolBar *mui_attachmentToolBar; /*!< Attachment list tool bar. */
	QStatusBar *mui_statusBar; /*!< Status bar. */
	QWidget *mui_dbStatusMode; /*!< Database status label/widget. */
	QWidget *mui_statusLabelTimestamps; /*!< Timestamp status lalbel/widget. */
	QWidget *mui_statusLabelTags; /*!< Tag status label/widget. */
	QWidget *mui_statusAccounts; /*!< Account status label/widget. */
	QProgressBar *mui_statusProgressBar; /*!< Progress bar. */
	QMenu mui_dockMenu; /*!< Dock menu for macOS. */
};
