/**********************************************************************
 * 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 <QModelIndex>
#include "modelsconfig.h"
#include "modelitembase.h"

namespace LeechCraft
{
namespace Util
{
	class ModelItem;

	typedef std::shared_ptr<ModelItem> ModelItem_ptr;
	typedef std::weak_ptr<ModelItem> ModelItem_wtr;
	typedef QVector<ModelItem_ptr> ModelItemsList_t;
	typedef std::shared_ptr<const ModelItem> ModelItem_cptr;

	/** @brief Provides a proxying API on top of an QAbstractItemModel.
	 *
	 * This class simplifies writing wrappers around QAbstractItemModel
	 * classes representing the data in different means than Qt's MVC.
	 *
	 * @ingroup ModelUtil
	 */
	class UTIL_MODELS_API ModelItem final : public ModelItemBase<ModelItem>
	{
		QAbstractItemModel * const Model_ = nullptr;
		QModelIndex SrcIdx_;
	public:
		typedef ModelItemsList_t::iterator iterator;
		typedef ModelItemsList_t::const_iterator const_iterator;

		/** @brief Constructs a default (invalid) ModelItem having no
		 * model set.
		 */
		ModelItem () = default;

		/** @brief Constructs a ModelItem associated with a given
		 * \em index in the \em model.
		 *
		 * @param[in] model The model which this model item wraps.
		 * @param[in] index The source index in this model.
		 * @param[in] parent The parent ModelItem, or an empty pointer if
		 * this is the root item.
		 */
		ModelItem (QAbstractItemModel *model, const QModelIndex& index, const ModelItem_wtr& parent);

		/** @brief Ensures there is a child item at the given \em row.
		 *
		 * If necessary, this function expands the list of children until
		 * there is a given \em row.
		 *
		 * If no model item has been set for the given row, this function
		 * creates a proper ModelItem.
		 *
		 * @param[in] row The row for which to obtain a child item.
		 * @return A child item already existing at the given \em row or
		 * a new child item if there was no item at the \em row.
		 */
		ModelItem* EnsureChild (int row);

		/** @brief Returns the index this ModelItem instance wraps.
		 *
		 * @return The model index this item wraps, either the one passed
		 * to the constructor or the one obtained during the
		 * RefreshIndex() call.
		 */
		const QModelIndex& GetIndex () const;

		/** @brief Returns the wrapped model.
		 *
		 * @return The wrapped model.
		 */
		QAbstractItemModel* GetModel () const;

		/** @brief Updates the wrapped index so that it points at the
		 * given row.
		 *
		 * Calling this function on a ModelItem wrapping the root of the
		 * underlying model (that is, constructed by the parameterless
		 * constructor) leads to undefined behavior.
		 *
		 * @param[in] modelStartingRow The new row (among the children of
		 * this item's wrapped index) in the model this item should
		 * represent.
		 */
		void RefreshIndex (int modelStartingRow);

		/** @brief Finds a child item for the given \em index.
		 *
		 * The \em index is assumed to be the child of the one wrapped by
		 * this ModelItem.
		 *
		 * @param[in] index The index (a child of the one returned by
		 * GetIndex()) for which a child model item should be found.
		 * @return The model item wrapping the given \em index or a null
		 * pointer if there is no such item.
		 */
		ModelItem_ptr FindChild (QModelIndex index) const;
	};
}
}
