//
// C++ Interface: EntityIcon
//
// Description: 
//
//
// Author: Erik Ogenvik <erik@ogenvik.org>, (C) 2007
//
// 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 2 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, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//
//
#ifndef EMBEROGRE_GUIENTITYICON_H
#define EMBEROGRE_GUIENTITYICON_H


#include "icons/Icon.h"
#include "EntityIconManager.h"
#include "EntityIconDragDropTarget.h"
#include "GenericIconUserData.h"
#include "CEGUIUtils.h"
#include <sigc++/trackable.h>
#include <any>
#include <memory>
#include <functional>
#include <framework/AttributeObserver.h>

namespace CEGUI {
class DragContainer;

class Window;

class EventArgs;
}

namespace Ember {
class EmberEntity;

namespace OgreView::Gui {

class EntityIconSlot;

class EntityIcon;

/**
	@brief An entity icon, representing a specific entity.
	An entity icon is a draggable element, which can be dragged and dropped onto different slots.
	The most common slot on which it can be dragged and dropped would be an instance of EntityIconSlot. An entity icon doesn't necessarily have to be connected to a slot, but in most cases they are.
	
	Additionally, another entity icon can be dragged and dropped onto an instance of this class. When this happens the EvenIcon* events are emitted. This allows you to implement functionality for combining different entities.
	@author Erik Ogenvik <erik@ogenvik.org>
*/
class EntityIcon : public EntityIconDragDropTarget, public virtual sigc::trackable {
	friend class EntityIconManager;

public:

	/**
	 * @brief Ctor. This is normally only called from the EntityIconManager.
	 * @param manager The icon manager to which this entity belongs.
	 * @param dragContainer The CEGUI drag container instance which provides drag and drop behavior for this entity icon. Ownership will not be transferred.
	 * @param image The image which represents the entity. In many cases this will be the same image as provided by the icon parameter. Ownership is not transferred.
	 * @param icon The Icon instance responsible for providing the image. Ownership is not transferred.
	 * @param entity The entity to which this icon belongs. Ownership is not transferred.
	 */
	EntityIcon(EntityIconManager& manager,
			   UniqueWindowPtr<CEGUI::DragContainer> dragContainer,
			   CEGUI::Window& image,
			   CEGUI::Window& amountWindow,
			   Gui::Icons::Icon* icon,
			   EmberEntity* entity);

	/**
	 * @brief Dtor.
	 *
	 * If the ícon is attached to a slot it will be detached at destruction.
	 */
	~EntityIcon() override;

	/**
	 * @brief Gets the CEGUI image which shows the entity. This can in some cases be a 3d render of the icon, or a prerendered texture. The actual handling of this is often taken care of by the mIcon instance.
	 * @return The image displaying the entity in the CEGUI system.
	 */
	CEGUI::Window& getImage();

	/**
	 * @brief Gets the CEGUI drag container which allows this entity to be dragged and dropped.
	 * @return The CEGUI drag container instance for this entity icon.
	 */
	CEGUI::DragContainer* getDragContainer();

	/**
	 * @brief Gets the icon instance which is responsible for providing the graphical representation (for example a live render, or a prerendered texture).
	 * @return The icon instance responsible for providing the graphical representation of the entity.
	 */
	Gui::Icons::Icon* getIcon();

	/**
	 * @brief Sets the slot to which this entity icon is attached. This will make the entity icon appear within the slot.
	 * Calling this on an entity which is already connected to a slot will make the icon first disconnect from that slot.
	 * @param slot The slot to which the entity icon should be connected.
	 */
	void setSlot(EntityIconSlot* slot);

	/**
	 * @brief Gets the icon entity slot to which this entity currently is attached to.
	 * @return The entity slot to which this entity icon is attached, or null if it's not connected to any slot.
	 */
	EntityIconSlot* getSlot();

	/**
	 * @brief Sets the tool tip for this entity icon.
	 * The tooltip will be displayed when the user hovers the mouse over the icon.
	 * @param text A text to show when the user hovers the mouse over the icon.
	 */
	void setTooltipText(const std::string& text);

	/**
	 * @brief Gets the entity which this icon represents.
	 * @return The entity which this icon represents.
	 */
	EmberEntity* getEntity();

	/**
	 * Set an arbitrary tag on the icon.
	 *
	 * @param tag
	 */
	void setTag(std::string tag);

	/**
	 * Gets an arbitrary tag set on the icon.
	 * @return
	 */
	const std::string& getTag() const;

	/**
	 * @brief Emitted when another EntityIcon instance is dragged and enters this icon.
	 */
	sigc::signal<void(EntityIcon*)> EventIconEntered;

	/**
	 * @brief Emitted when another EntityIcon instance is dragged and leaves this icon.
	 */
	sigc::signal<void(EntityIcon*)> EventIconLeaves;

	/**
	 * @brief Emitted when another EntityIcon instance is dragged and dropped on this icon.
	 */
	sigc::signal<void(EntityIcon*)> EventIconDropped;

	/**
	 * @brief The main reason for having this is an issue in the lua bindings where comparisons of two EntityIcon instances always generated a lua error.
	 * @param value Another object to compare to.
	 * @return True if the objects are identical.
	 */
	bool operator==(const EntityIcon& value) const noexcept { return this == &value; }

	bool operator!=(const EntityIcon& value) const noexcept { return this != &value; }

protected:


	/**
	 * @brief The main entity icon manager.
	 */
	EntityIconManager& mManager;

	/**
	 * @brief The CEGUI drag container instance which provides drag and drop behavior for this entity icon.
	 */
	UniqueWindowPtr<CEGUI::DragContainer> mDragContainer;

	/**
	 * @brief The image which represents the entity. In many cases this will be the same image as provided by the icon parameter.
	 */
	CEGUI::Window& mImage;

	/**
	 * If there's an amount, this window will show it.
	 */
	CEGUI::Window& mAmount;

	/**
	 * @brief The Icon instance responsible for providing the image.
	 */
	Gui::Icons::Icon* mIcon;

	/**
	 * @brief The user data attached to the window which binds it to this instance.
	 */
	GenericIconUserData<EntityIcon> mUserData;

	/**
	 * @brief Holds the mUserData and is attached to the CEGUI::DragContainer.
	 *
	 * This allows us to better query for type, as the std::any class stores the type id of the wrapped object.
	 */
	std::any mUserDataWrapper;

	/**
	 * @brief If the icon is attached to any slot it's stored here.
	 */
	EntityIconSlot* mCurrentSlot;

	/**
	 * @brief The entity which the icon represents.
	 */
	EmberEntity* mEntity;

	AttributeObserver mAmountObserver;

	/**
	 * An arbitrary tag set on the icon.
	 */
	std::string mTag;

	/**
	 * @brief Handler for CEGUI drag start event.
	 * @param args Event args.
	 */
	bool dragContainer_DragStarted(const CEGUI::EventArgs& args);

	/**
	 * @brief Handler for CEGUI drag stop event.
	 * @param args Event args.
	 */
	bool dragContainer_DragStopped(const CEGUI::EventArgs& args);

	bool handleDragEnter(const CEGUI::EventArgs& args, EntityIcon* icon) override;

	bool handleDragLeave(const CEGUI::EventArgs& args, EntityIcon* icon) override;

	bool handleDragDropped(const CEGUI::EventArgs& args, EntityIcon* icon) override;

	void icon_Updated();

	void updateAmount();

};

}


}

#endif
