#pragma once

#include "volumeshop.h"

#undef emit
#include <ufo/ufo.hpp>
#include <ufo/ux/ux.hpp>
#define emit

#include "Plugin.h"
#include "Event.h"
#include <list>

class Environment;

class Viewer : public ufo::UObject
{
	class PluginObject : public ufo::UObject
	{
	public:
		
		PluginObject(Plugin *pPlugin)
		{
			m_pPlugin = pPlugin;
		};

		Plugin * GetPlugin()
		{
			return m_pPlugin;
		};

	private:
		
		Plugin *m_pPlugin;
	};

public:

	Viewer();
	virtual ~Viewer();

	virtual void initialize();
	virtual void uninitialize();

	virtual void idle();
	virtual void display();
	virtual void reshape(const unsigned int uWidth, const unsigned int uHeight);
	virtual void mousePress(const MouseEvent & mouEvent);
	virtual void mouseRelease(const MouseEvent & mouEvent);
	virtual void mouseMove(const MouseEvent & mouEvent);
	virtual void keyboardPress(const KeyboardEvent & keyEvent);
	virtual void keyboardRelease(const KeyboardEvent & keyEvent);

	virtual const unsigned int GetWidth() const
	{
		return m_uWidth;
	};

	virtual const unsigned int GetHeight() const
	{
		return m_uHeight;
	};

	virtual void add(Plugin *pPlugin);
	virtual void add(const std::list<Plugin *> & lisPlugins);
	virtual void remove(Plugin *pPlugin);
	virtual void remove(const std::list<Plugin *> & lisPlugins);
	virtual void remove(Environment *pEnvironment);

	virtual void SetEnabled(Plugin *pPlugin, const bool bEnabled);
	virtual const bool IsEnabled(Plugin *pPlugin) const;

	virtual void update() = 0;
	virtual void bindContext() { };
	virtual void releaseContext() { };

	const std::list<Plugin*> GetPlugins()
	{
		std::list<Plugin*> lisPlugins;

		for (std::map< std::string, std::list<Plugin*> >::iterator i = m_mapPlugins.begin(); i != m_mapPlugins.end(); i++)
			lisPlugins.insert(lisPlugins.end(),i->second.begin(),i->second.end());

		return lisPlugins;
	};

	const std::list<Plugin*> GetPlugins(const std::string & strType) const
	{
		std::map< std::string, std::list<Plugin*> >::const_iterator i = m_mapPlugins.find(strType);

		if (i != m_mapPlugins.end())
			return i->second;

		return std::list<Plugin*>();
	};

	void OnPluginButtonPressed(ufo::UActionEvent *e);

protected:

	void initialize(Plugin *pPlugin);

protected:

	unsigned int m_uWidth;
	unsigned int m_uHeight;

	std::map< std::string, std::list<Plugin*> > m_mapPlugins;
	std::map< Plugin * , ufo::UButton * > m_mapButtons;

	ufo::UXToolkit *m_pToolkit;
	ufo::UXDisplay *m_pDisplay;
	ufo::UXContext *m_pContext;
	ufo::UWidget *m_pMainWidget;
	ufo::UWidget *m_pRendererPluginWidget;
};