/**********************************************************************
 * LeechCraft - modular cross-platform feature rich internet client.
 * Copyright (C) 2006-2014  Georg Rudoy
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **********************************************************************/

#pragma once

#include <memory>
#include <QFuture>
#include <util/sll/newtype.h>

namespace LC
{
namespace Util
{
	using QtException_t = QException;

	using QtException_ptr = std::shared_ptr<QtException_t>;

	/** @brief A concurrent exception that plays nicely with Qt.
	 *
	 * This class can be used to make some third-party exception type
	 * compatible with the QtConcurrent framework, which requires all
	 * exceptions to be derived from a Qt's base exception class.
	 *
	 * This class wraps differences between Qt4's QtConcurrent::Exception
	 * and Qt5's QException and provides an uniform interface.
	 *
	 * @tparam T The base type of the exception.
	 */
	template<typename T>
	class ConcurrentException : public QtException_t
							  , public T
	{
	public:
		/** @brief Default-constructs the exception object.
		 */
		ConcurrentException () = default;

		/** @brief Constructs the exception object with the given
		 * \em args.
		 *
		 * @param[in] args The argments to pass to the constructor of the
		 * base exception \em T.
		 * @tparam Args The types of the arguments of the constructor of
		 * \em T.
		 */
		template<typename... Args>
		ConcurrentException (Args&&... args)
		: T { std::forward<Args> (args)... }
		{
		}

		/** @brief Rethrows an exception of exactly this type and state.
		 *
		 * @throws ConcurrentException<T>
		 */
		void raise () const override
		{
			throw ConcurrentException<T> { *this };
		}

		/** @brief Constructs a copy of this object.
		 *
		 * @return The copy of this object.
		 */
		ConcurrentException<T>* clone () const override
		{
			return new ConcurrentException<T> { *this };
		}

		/** @brief Overrides base pure virtual.
		 *
		 * Calls <code>T::what()</code>.
		 */
		const char* what () const noexcept override
		{
			return T::what ();
		}
	};

	using ConcurrentStdException = Util::ConcurrentException<Util::NewType<std::exception, 0, __LINE__>>;
}
}

Q_DECLARE_METATYPE (LC::Util::QtException_ptr)
