/*
 * Copyright (C) 2014-2022 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 <QObject>
#include <QReadWriteLock>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#  include <memory> /* ::std::unique_ptr */
#else /* < Qt-5.12 */
#  include <QScopedPointer>
#endif /* >= Qt-5.12 */
#include <QSet>

#include "src/identifiers/message_id.h"
#include "src/models/accounts_model.h" /* enum AccountModel::NodeType */

class AcntId; /* Forward declaration. */
class QString; /* Forward declaration. */

class MWStatusPrivate;
/*!
 * @brief Describes the main window selection status.
 */
class MWStatus {
	Q_DECLARE_PRIVATE(MWStatus)

public:
	MWStatus(void);
	MWStatus(const MWStatus &other);
#ifdef Q_COMPILER_RVALUE_REFS
	MWStatus(MWStatus &&other) Q_DECL_NOEXCEPT;
#endif /* Q_COMPILER_RVALUE_REFS */
	~MWStatus(void);

	MWStatus &operator=(const MWStatus &other) Q_DECL_NOTHROW;
#ifdef Q_COMPILER_RVALUE_REFS
	MWStatus &operator=(MWStatus &&other) Q_DECL_NOTHROW;
#endif /* Q_COMPILER_RVALUE_REFS */

	bool operator==(const MWStatus &other) const;
	bool operator!=(const MWStatus &other) const;

	friend void swap(MWStatus &first, MWStatus &second) Q_DECL_NOTHROW;

	bool isNull(void) const;

	const AcntId &acntId(void) const;
	void setAcntId(const AcntId &ai);
#ifdef Q_COMPILER_RVALUE_REFS
	void setAcntId(AcntId &&ai);
#endif /* Q_COMPILER_RVALUE_REFS */

	enum AccountModel::NodeType acntNodeType(void) const;
	void setAcntNodeType(enum AccountModel::NodeType nt);

	const QString &year(void) const;
	void setYear(const QString &y);
#ifdef Q_COMPILER_RVALUE_REFS
	void setYear(QString &&y);
#endif /* Q_COMPILER_RVALUE_REFS */

	const QSet<MsgId> &msgIds(void) const;
	void setMsgIds(const QSet<MsgId> &ml);
#ifdef Q_COMPILER_RVALUE_REFS
	void setMsgIds(QSet<MsgId> &&ml);
#endif /* Q_COMPILER_RVALUE_REFS */

	bool flagBlockIsds(void) const;
	void setFlagBlockIsds(bool fbi);

	bool flagBlockImports(void) const;
	void setFlagBlockImports(bool fbi);

private:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
	::std::unique_ptr<MWStatusPrivate> d_ptr;
#else /* < Qt-5.12 */
	QScopedPointer<MWStatusPrivate> d_ptr;
#endif /* >= Qt-5.12 */
};

void swap(MWStatus &first, MWStatus &second) Q_DECL_NOTHROW;

/*!
 * @brief Locked main window status.
 */
class MWLockedStatus : public QObject {
	Q_OBJECT

public:
	/*!
	 * @brief Constructor.
	 *
	 * @param[in] parent Parent object.
	 */
	MWLockedStatus(QObject *parent = Q_NULLPTR);

	/*!
	 * @brief Obtain a window item selection status.
	 *
	 * @note A read lock is used to ensure atomicity of the operation.
	 *
	 * @return Window selection status copy.
	 */
	MWStatus mwStatus(void) const;

	/*!
	 * @brief Set new account state.
	 *
	 * @note Message state is reset when account state is modified.
	 * @note Emits changed signal if state is changed.
	 * @note Emits accountChanged signal if account state is changed.
	 * @note Emits messageChanged signal if message selection is changed.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] acntNodeType Account node type.
	 * @param[in] year Year string if node type points to a year entry.
	 */
	void setAccount(const AcntId &acntId,
	    enum AccountModel::NodeType acntNodeType, const QString &year);

	/*!
	 * @brief Set message selection.
	 *
	 * @note Emits changed signal if state is changed.
	 * @note Emits messageChanged signal if message selection is changed.
	 *
	 * @param[in] msgIds Message selection.
	 */
	void setMsgIds(const QSet<MsgId> &msgIds);

	/*!
	 * @brief Sets the block ISDS actions flag.
	 *
	 * @note Emits changed signal if state is changed.
	 *
	 * @param[in] fbi Block ISDS action flag.
	 */
	void setFlagBlockIsds(bool fbi);

	/*!
	 * @brief Sets the block import actions flag.
	 *
	 * @note Emits changed signal if state is changed.
	 *
	 * @param[in] fbi Block import action flag.
	 */
	void setFlagBlockImports(bool fbi);

signals:
	/*!
	 * @brief Emitted when status changes.
	 */
	void changed(void);

	/*!
	 * @brief Emitted when account status changes.
	 */
	void accountChanged(void);

	/*!
	 * @brief Emitted when message selection changes.
	 */
	void messageChanged(void);

private:
	mutable QReadWriteLock m_lock; /*!< Read/write mutual exclusion. */

	MWStatus m_mwStatus; /*!< Main window status. */
};
