/*
 * 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 <QDialog>
#include <QItemSelection>
#include <QList>
#include <QMap>
#include <QPair>
#include <QThread>
#include <QTimer>

#include "src/datovka_shared/identifiers/account_id.h" /* AcntId is used in slots. Q_MOC_INCLUDE */
#include "src/datovka_shared/utility/network_speed.h"
#include "src/delegates/progress_delegate.h"
#include "src/identifiers/account_id_db.h"
#include "src/io/timestamp_db.h" /* QList<TstEntry> is used in slots. Q_MOC_INCLUDE */
#include "src/json/message_id.h" /* Json::MsgId2List is used in slots. Q_MOC_INCLUDE */
#include "src/models/backup_selection_model.h"
#include "src/models/datetime_filter_proxy_model.h"
#include "src/models/message_timestamp_listing_model.h"
#include "src/models/progress_proxy_model.h"
#include "src/models/sort_filter_proxy_model.h"

/*!
 * @brief Scan all accounts for timestamp expiration dates of all stored messages.
 */
class ScanAccountsThread : public QThread {
	Q_OBJECT

public:
	/*!
	 * @brief Constructor.
	 *
	 * @param[in, out] Variable to interrupt the process.
	 */
	explicit ScanAccountsThread(volatile bool &stop);

	/*!
	 * @brief Set list of accounts to be scanned.
	 *
	 * @note May fail when thread is running.
	 *
	 * @param[in] acntIdDbList List of accounts.
	 *
	 * @return True if list set, false if thread is running.
	 */
	bool setScannedAcntIdDbList(const QList<AcntIdDb> &acntIdDbList);

Q_SIGNALS:
	/*!
	 * @brief Emitted on thread start.
	 */
	void started(void);

	/*!
	 * @brief Emitted on thread stop.
	 *
	 * @param[in] interrupted True if the scan process has been interrupted by user.
	 */
	void stopped(bool interrupted);

	/*!
	 * @brief Emitted after time stamp expiration has been determined.
	 *
	 * @param[in] acntIdDb Account identifier.
	 * @param[in] tstEntries Timestamp entries.
	 */
	void processed(const AcntIdDb &acntIdDb, const QList<TstEntry> &tstEntries);

	/*!
	 * @brief Emitted periodically while scannign account \a acntIdDb.
	 *
	 * @note It is guaranteed to be emitted when first message is scanned
	 *     and after scanning the last message.
	 *     When \a num and \a total are equal then the last message has
	 *     been scanned or the scan process has been interrupted.
	 *
	 * @param[in] acntIdDb Account identifier.
	 * @param[in] num Number of scanned messages.
	 * @param[in] total Total number of messages.
	 */
	void progress(const AcntIdDb &acntIdDb, int num, int total);

protected:
	/*!
	 * @brief Thread function.
	 */
	virtual
	void run(void) Q_DECL_OVERRIDE;

private:
	QList<AcntIdDb> m_scannedAcntIdDbList; /* List of accounts to be scanned. */
	volatile bool &m_stop; /*!< Signals break of download loop. */
};

class DbContainer; /* Forward declaration. */
class IsdsSessions; /* Forward declaration. */
class MainWindow; /* Forward declaration. */
class TaskArchiveIsdsDocument; /* Forward declaration. */
class TaskArchiveIsdsDocumentFile; /* Forward declaration. */
class TimestampDb; /* Forward declaration. */

namespace Ui {
	class DlgTimestampRenewal;
}

/*!
 * @brief Timestamp renewal dialogue.
 */
class DlgTimestampRenewal : public QDialog {
	Q_OBJECT
public:
	/*!
	 * @brief Tabs which this dialogue has.
	 */
	enum TabIndexes {
		TAB_TRACKED = 0,
		TAB_EXTERNAL,

		MAX_TABNUM /* Maximal number of columns (convenience value). */
	};

	/*!
	 * @brief Constructor.
	 *
	 * @param[in] acntIdDbList List of available accounts.
	 * @param[in.out] timestampDb Timestamp database.
	 * @param[in,out] msgDbs Message database container.
	 * @param[in,out] sessions Session container.
	 * @param[in] mw Main application window.
	 * @param[in] parent Parent widget.
	 * @param[in] flags Window flags.
	 */
	explicit DlgTimestampRenewal(const QList<AcntIdDb> &acntIdDbList,
	    TimestampDb *timestampDb,
	    DbContainer *msgDbs, IsdsSessions *sessions, MainWindow *mw,
	    QWidget *parent = Q_NULLPTR,
	    Qt::WindowFlags flags = Qt::WindowFlags());

	/*!
	 * @brief Destructor.
	 */
	~DlgTimestampRenewal(void);

protected:
	/*!
	 * @brief Check window geometry and set table columns width.
	 *
	 * @param[in] event Widget show event.
	 */
	virtual
	void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;

Q_SIGNALS:
	/*!
	 * @brief Signals that a message was selected should be focused
	 *     elsewhere.
	 *
	 * @param[in] username Username identifying an account.
	 * @param[in] testing True if this is an testing account.
	 * @param[in] dmId Message identifier.
	 * @param[in] year Message delivery year.
	 * @param[in] msgType Message type.
	 */
	void focusSelectedMsg(AcntId acntId, qint64 dmId, QString year,
	    int msgType);

public Q_SLOTS:
	/*!
	 * @brief Check if a worker is working on the background and show
	 *     a dialogue whether the user wants to close this dialogue.
	 *
	 * @note Used instead of closeEvent().
	 *     https://stackoverflow.com/questions/13129380/show-a-dialog-before-closing-the-program-in-qt
	 *
	 * @param[in] resultCode Dialog result code.
	 */
	virtual
	void done(int resultCode) Q_DECL_OVERRIDE;

private Q_SLOTS:
	/*!
	 * @brief Renews timestamps for selected tracked messages.
	 */
	void renewSelectedTrackedTimestamps(void);

	/*!
	 * @brief Renews timestamps for selected all stored messages.
	 */
	void renewSelectedAllStoredTimestamps(void);

	/*!
	 * @brief Renews timestamps for all stored messages which are at the
	 *     moment displayed in the list.
	 */
	void renewListedAllStoredTimestamps(void);

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

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

	/*!
	 * @brief Enables/disables actions depending on the content of the all
	 *     stored list.
	 */
	void watchAllStoredMessageList(void);

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

	/*!
	 * @brief Enable timestamp tracking for selected messages.
	 *
	 * @param[in] enable Whether to enable/disable tracking.
	 */
	void toggleAllStoredTimestampTracking(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 viewTrackedMessagesListContextMenu(const QPoint &point);

	/*!
	 * @brief Emit ID of message entry.
	 *
	 * @param[in] index Model index.
	 */
	void trackedMessageItemDoubleClicked(const QModelIndex &index);

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

	/*!
	 * @brief Emit ID of message entry.
	 *
	 * @param[in] index Model index.
	 */
	void allStoredMessageItemDoubleClicked(const QModelIndex &index);

/* Filter-field-related actions. */
	/*!
	 * @brief Filter listed tracked messages.
	 *
	 * @param[in] text Sought text.
	 */
	void filterTrackedMessages(const QString &text);

	/*!
	 * @brief Filter listed all messages.
	 *
	 * @param[in] text Sought text.
	 */
	void filterAllMessages(const QString &text);

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

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

/* Handle database signals. */
	/*!
	 * @brief Update 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 data when timestamp tracking disabled.
	 *
	 * @param[in] msgIds Message identifiers.
	 */
	void watchIdentificationsDeleted(const Json::MsgId2List &msgIds);

	/*!
	 * @brief Update data when timestamp data updated.
	 *
	 * @param[in] values Updated values.
	 */
	void watchMsgTimestampDataUpdated(const TstValidityHash &values);

	/*!
	 * @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);

/* All stored tab functions. */
	/*!
	 * @brief Change selection according to all checkbox state.
	 *
	 * @param[in] state Selection state of the 'select all' checkbox.
	 */
	void applyAllSelection(int state);

	/*!
	 * @brief Filter messages according to restampable checkbox state.
	 *
	 * @param[in] state Selection state of the 'restampable only' checkbox.
	 */
	void applyRestampableFiltering(int state);

	/*!
	 * @brief Update all selection button.
	 */
	void modifiedAccountSelection(void);

	/*!
	 * @brief Start scanning accounts for expiring timestamps.
	 */
	void startAccountScan(void);

	/*!
	 * @brief Stops running scan.
	 */
	void interruptAccountScan(void);

	/*!
	 * @brief Re-enables various widgets.
	 *
	 * @param[in] interrupted True if the scan process has been interrupted by user.
	 */
	void watchScanStopped(bool interrupted);

	/*!
	 * @brief Fills data into all stored table.
	 *
	 * @param[in] acntIdDb Account identifier.
	 * @param[in] tstEntries Timestamp entries.
	 */
	void watchScanProcessed(const AcntIdDb &acntIdDb,
	    const QList<TstEntry> &tstEntries);

	/*!
	 * @brief Draws progress bars when scanning accounts.
	 *
	 * @param[in] acntIdDb Account identifier.
	 * @param[in] num Number of scanned messages.
	 * @param[in] total Total number of messages.
	 */
	void watchScanProgress(const AcntIdDb &acntIdDb, int num, int total);

/* External tab functions. */
	/*!
	 * @brief Choose source file.
	 */
	void selectExternalSrcZfo(void);

	/*!
	 * @brief View source file content.
	 */
	void viewExternalSrcZfo(void);

	/*!
	 * @brief Choose target file.
	 */
	void selectExternalTgtZfo(void);

	/*!
	 * @brief Renews timestamps for source file.
	 */
	void renewExternalTimestamps(void);

/* Handle worker signals. */
	/*!
	 * @brief Set upload progress.
	 */
	void watchUploadProgress(const AcntId &acntId,
	    const QString &transactId, qint64 uploadTotal,
	    qint64 uploadCurrent);

	/*!
	 * @brief Hide upload progress.
	 */
	void watchUploadProgressFinished(const AcntId &acntId,
	    const QString &transactId, int result, const QString &resultDesc,
	    const QVariant &resultVal);

	/*!
	 * @brief Set download progress.
	 */
	void watchDownloadProgress(const AcntId &acntId,
	    const QString &transactId, const MsgId &msgId,
	    qint64 downloadTotal, qint64 downloadCurrent);

	/*!
	 * @brief Set result into timestamp model.
	 */
	void watchDownloadProgressFinished(const AcntId &acntId,
	    const QString &transactId, const MsgId &msgId,
	    int result, const QString &resultDesc);

private:
	/*!
	 * @brief Initialise message search dialogue.
	 */
	void initTimestampWindow(void);

	/*!
	 * @brief Connects menu actions to appropriate slots.
	 */
	void menuConnectActions(void);

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

	/*!
	 * @brief Connect worker signals to appropriate slots.
	 */
	void workerConnectActions(void);

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

	/*!
	 * @brief Renews timestamps for selected messages.
	 *
	 * @param[in] modelRowSelection Selected rows of \a timestampTableModel.
	 * @param[in] timestampTableModel Model of list of messages.
	 */
	void renewSelectedTimestamps(const QList<int> &modelRowSelection,
	    MsgTstListingModel &timestampTableModel);

	/*!
	 * @brief Emit ID of message entry.
	 *
	 * @param[in] index Model index.
	 * @param[in] proxyModelCascade List of proxy models, first is the most outer one.
	 * @param[in] timestampTableModel TImestamp table model.
	 */
	void messageItemDoubleClicked(const QModelIndex &index,
	    const QList<const QAbstractProxyModel *> &proxyModelCascade,
	    const MsgTstListingModel &timestampTableModel);

	/*!
	 * @brief Used to clear message list filter line via event filter.
	 *
	 * @param[in] lineEditPtr Pointer to line edit widget.
	 */
	static
	void clearFilterLineViaFilter(QObject *lineEditPtr);

	/*!
	 * @brief Used to view tracked message list filter line via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void showTrackedFilterLineViaFilter(QObject *dlgPtr);

	/*!
	 * @brief Used to view all message list filter line via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void showAllFilterLineViaFilter(QObject *dlgPtr);

	/*!
	 * @brief Used to hide tracked message list filter line via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void hideTrackedFilterLineViaFilter(QObject *dlgPtr);

	/*!
	 * @brief Used to hide all message list filter line via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void hideAllFilterLineViaFilter(QObject *dlgPtr);

	/*!
	 * @brief Used to focus on a tracked message via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void focusOnTrackedMessageViaFilter(QObject *dlgPtr);

	/*!
	 * @brief Used to focus on a all stored message via event filter.
	 *
	 * @param[in] dlgPtr Pointer to dialogue window.
	 */
	static
	void focusOnAllMessageViaFilter(QObject *dlgPtr);

	Ui::DlgTimestampRenewal *m_ui; /*!< UI generated from UI file. */

	QList<int> m_trackedModelRowSelection; /*!< Holds the tracked message selection. */
	QList<int> m_allStoredModelRowSelection; /*!< Holds the all stored message selection. */

	TimestampDb *m_timestampDb; /*!< Timestamp database. */
	DbContainer *m_msgDbs; /*!< Message databases. */
	IsdsSessions *m_sessions; /*!< ISDS session container. */
	MainWindow *m_mw; /*!< Pointer to main window. */

	QTimer m_updateTimer; /*!< Update current time in m_trackedTimestampTableModel and m_allStoredTimestampTableModel. */

	SortFilterProxyModel m_trackedSortProxyModel; /*!<
	                                               * Used for timestamp
	                                               * sorting and filtering.
	                                               */

	ProgressBarProxyModel m_trackedProgressProxyModel; /*!< Generates progress-bars on top of the tracked model. */
	ProgressDelegate m_progressDelegate; /*!< Draws progress bars into the download table view. */

	MsgTstListingModel m_trackedTimestampTableModel; /*!< Timestamp expiration table model for tracked messages. */

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

	ProgressBarProxyModel m_accountProgressProxyModel; /*!< Generates progress-bars on top of the account model. */

	BackupSelectionModel m_accountSelectionModel; /*!< Choose account to work with. */

	SortFilterProxyModel m_allStoredSortProxyModel; /*!<
	                                                 * Used for timestamp
	                                                 * sorting and filtering.
	                                                 */
	DateTimeFilterProxyModel m_allStoredTimeProxyModel; /*!<
	                                                     * Used for expiration
	                                                     * filtering.
	                                                     */

	ProgressBarProxyModel m_allStoredProgressProxyModel; /*!< Generates progress-bars on top of the all stored model. */

	MsgTstListingModel m_allStoredTimestampTableModel; /*!< Timestamp expiration table model for all stored messages. */

	QMap<QString, QPair<AcntId, MsgId> > m_trackedTransactionMap; /*!< Created transactions for tracked messages. */

	QString m_externalTransaction; /*!< Single external file transaction. */
	QMap<QString, TaskArchiveIsdsDocument *> m_tasks; /*!< Created tasks. */
	TaskArchiveIsdsDocumentFile *m_externalTask; /*!< Created task. */

	volatile bool m_breakScanLoop; /*!< Signals break of download loop. */
	ScanAccountsThread m_scanAccountsThread; /*!< Scan thread. Doesn't block the GUI when downloading. */

	QMap<QString, NetworkSpeed> m_speeds; /* Network speeds. */

	const QList<AcntIdDb> m_acntIdDbList; /*!< Available accounts.*/

	QSize m_dfltSize; /*!< Remembered dialogue default size. */
};
