/*
 * Copyright (C) 2014-2019 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 <QDateTime>
#include <QList>
#include <QScopedPointer>
#include <QString>

class QJsonObject; /* Forward declaration. */

class BackupEntryPrivate;
/*!
 * @brief Back-up description.
 */
class BackupEntry {
	Q_DECLARE_PRIVATE(BackupEntry)

public:
	class FilePrivate;
	/*!
	 * @brief Describes an ordinary file backup.
	 */
	class File {
		Q_DECLARE_PRIVATE(File)

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

		explicit File(const QString &f);
#ifdef Q_COMPILER_RVALUE_REFS
		explicit File(QString &&f);
#endif /* Q_COMPILER_RVALUE_REFS */

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

		static
		void swap(File &first, File &second) Q_DECL_NOTHROW;

		bool isNull(void) const;
		bool isValid(void) const;

		const QString &fileName(void) const;
		void setFileName(const QString &f);
#ifdef Q_COMPILER_RVALUE_REFS
		void setFileName(QString &&f);
#endif /* Q_COMPILER_RVALUE_REFS */

		/*!
		 * @brief Creates a back-up file entry structure from supplied
		 *     JSON document.
		 *
		 * @param[in]  jsonObj JSON object.
		 * @param[out] ok Set to true on success.
		 * @return Invalid structure on error a valid structure else.
		 */
		static
		File fromJson(const QJsonObject &jsonObj, bool *ok = Q_NULLPTR);

		/*!
		 * @brief Writes content of JSON object.
		 *
		 * @note Unspecified values are omitted.
		 *
		 * @param[out] jsonObj JSON object to write to.
		 * @return True on success.
		 */
		bool toJson(QJsonObject *jsonObj) const;

	private:
		QScopedPointer<FilePrivate> d_ptr; // std::unique_ptr ?
	};

	class MessageDbPrivate;
	/*!
	 * @brief Describes a message database back-up entry.
	 */
	class MessageDb {
		Q_DECLARE_PRIVATE(MessageDb)

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

		MessageDb(bool t, const QString &a, const QString &b,
		    const QString &u, const QString &s, const QList<QString> &f);

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

		static
		void swap(MessageDb &first, MessageDb &second) Q_DECL_NOTHROW;

		bool isNull(void) const;
		bool isValid(void) const;

		bool testing(void) const;
		void setTesting(bool t);

		const QString &accountName(void) const;
		void setAccountName(const QString &a);
#ifdef Q_COMPILER_RVALUE_REFS
		void setAccountName(QString &&a);
#endif /* Q_COMPILER_RVALUE_REFS */

		const QString &boxId(void) const;
		void setBoxId(const QString &b);
#ifdef Q_COMPILER_RVALUE_REFS
		void setBoxId(QString &&b);
#endif /* Q_COMPILER_RVALUE_REFS */

		const QString &username(void) const;
		void setUsername(const QString &u);
#ifdef Q_COMPILER_RVALUE_REFS
		void setUsername(QString &&u);
#endif /* Q_COMPILER_RVALUE_REFS */

		const QString &subDir(void) const;
		void setSubDir(const QString &s);
#ifdef Q_COMPILER_RVALUE_REFS
		void setSubDir(QString &&s);
#endif /* Q_COMPILER_RVALUE_REFS */

		const QList<QString> &fileNames(void) const;
		void setFileNames(const QList<QString> &f);
#ifdef Q_COMPILER_RVALUE_REFS
		void setFileNames(QList<QString> &&f);
#endif /* Q_COMPILER_RVALUE_REFS */

		/*!
		 * @brief Creates a back-up message database entry structure
		 *     from supplied JSON document.
		 *
		 * @param[in]  jsonObj JSON object.
		 * @param[out] ok Set to true on success.
		 * @return Invalid structure on error a valid structure else.
		 */
		static
		MessageDb fromJson(const QJsonObject &jsonObj,
		    bool *ok = Q_NULLPTR);

		/*!
		 * @brief Writes content of JSON object.
		 *
		 * @note Unspecified values are omitted.
		 *
		 * @param[out] jsonObj JSON object to write to.
		 * @return True on success.
		 */
		bool toJson(QJsonObject *jsonObj) const;

	private:
		QScopedPointer<MessageDbPrivate> d_ptr; // std::unique_ptr ?
	};

	BackupEntry(void);
	BackupEntry(const BackupEntry &other);
#ifdef Q_COMPILER_RVALUE_REFS
	BackupEntry(BackupEntry &&other) Q_DECL_NOEXCEPT;
#endif /* Q_COMPILER_RVALUE_REFS */
	~BackupEntry(void);

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

	static
	void swap(BackupEntry &first, BackupEntry &second) Q_DECL_NOTHROW;

	bool isNull(void) const;
	bool isValid(void) const;

	const QDateTime &dateTime(void) const;
	void setDateTime(const QDateTime &t);
#ifdef Q_COMPILER_RVALUE_REFS
	void setDateTime(QDateTime &&t);
#endif /* Q_COMPILER_RVALUE_REFS */

	const QList<MessageDb> &messageDbs(void) const;
	void setMessageDbs(const QList<MessageDb> &m);
#ifdef Q_COMPILER_RVALUE_REFS
	void setMessageDbs(QList<MessageDb> &&m);
#endif /* Q_COMPILER_RVALUE_REFS */

	const File &accountDb(void) const;
	void setAccountDb(const File &a);
#ifdef Q_COMPILER_RVALUE_REFS
	void setAccountDb(File &&a);
#endif /* Q_COMPILER_RVALUE_REFS */

	const File &tagDb(void) const;
	void setTagDb(const File &t);
#ifdef Q_COMPILER_RVALUE_REFS
	void setTagDb(File &&t);
#endif /* Q_COMPILER_RVALUE_REFS */

	/*!
	 * @brief Return a message database for specified username.
	 *
	 * @param[in] username Non-empty username.
	 * @param[in] testing Whether this is a testing account.
	 * @return Null message database entry if no such username found.
	 */
	const MessageDb &messageDb(const QString &username, bool testing) const;

	/*!
	 * @brief Creates a back-up entry structure from supplied JSON document.
	 *
	 * @param[in]  json JSON document.
	 * @param[out] ok Set to true on success.
	 * @return Invalid structure on error a valid structure else.
	 */
	static
	BackupEntry fromJson(const QByteArray &json, bool *ok = Q_NULLPTR);

	/*!
	 * @brief Writes content of a JSON document.
	 *
	 * @note Unspecified values are omitted.
	 *
	 * @param[out] jsonObj JSON object to write to.
	 * @return True on success.
	 */
	QByteArray toJson(void) const;

private:
	QScopedPointer<BackupEntryPrivate> d_ptr; // std::unique_ptr ?
};
