#ifndef SDPGTKOBJECTCONTAINER_H
#define SDPGTKOBJECTCONTAINER_H

// SDPGTK Library
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// 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
// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
		\brief Declares the sdpGtkObjectContainer class, which can load GTKML (XML) documents
		\author Timothy M. Shead (tshead@k-3d.com)
*/

#include "sdpgtkiobjectcontainer.h"
#include "sdpgtkwidgets.h"

#include <map>
#include <list>
#include <stack>

// We have a small collision with Xlib.h ...
#ifdef SDPUNIX
#ifdef RootWindow
#undef RootWindow
#endif // RootWindow

#endif // SPDUNIX


// Forward declarations ...
class sdpGtkEvent;
class sdpxml::Document;

///////////////////////////////////////////////////////////////////
// sdpGtkObjectContainer

/// Loads GTKML (XML) documents
class sdpGtkObjectContainer :
	public sdpGtkIObjectContainer,
	public sdpGtkObject
{
public:
	sdpGtkObjectContainer();
	virtual ~sdpGtkObjectContainer();

	/// Loads a GTKML file from an XML document
	bool Load(sdpxml::Document& Document, const boost::filesystem::path& ReferencePath = boost::filesystem::path());

	/// The main event handler function
	virtual void OnEvent(sdpGtkEvent* Event);

	/// Returns the container's root object (the top-level object within a GTKML document)
	GtkObject* Root() { return m_Object; }

	/// Maps an event by name
	sdpGtkEvent* MapEvent(const std::string& EventSignal, const std::string& EventName, const bool After, GtkObject* const Object, const bool Connect);
	/// Maps an event by name
	sdpGtkEvent* MapEvent(const std::string& EventSignal, const std::string& EventName, const bool After, sdpGtkObject* const Object, const bool Connect);
	/// Maps an event by name
	sdpGtkEvent* MapEvent(const std::string& EventSignal, const std::string& EventName, const bool After, sdpGtkObject& Object, const bool Connect);

	/// Connects all events to GTK+
	void ConnectAllEvents();
	/// Blocks all object events
	void BlockAllEvents();
	/// Unblocks all object events
	void UnblockAllEvents();
	/// Disconnects all events from GTK+
	void DisconnectAllEvents();

	/// Deletes an event (the event must be explicitly disconnected by hand)
	void DeleteEvent(sdpGtkEvent* Event);

	/// Grabs the application focus and begins a modal loop
	void DoModal();
	/// Grabs the application focus and begins a modal loop
	void DoModal(GtkWindow* TransientOwner);
	/// Grabs the application focus and begins a modal loop
	void DoModal(sdpGtkWindow& TransientOwner);
	/// Finishes the modal loop and releases the focus
	void CancelModal();
	/// Tests to see if the modal loop is active
	bool IsModal();
	
	/// Returns a resource by name
	std::string Resource(const std::string& ResourceName);
	/// Returns a resource by name
	std::string Resource(const std::string& ResourceName, const std::string& DefaultValue);
	
	/// Returns a custom object by name
	sdpGtkObject* CustomObject(const std::string& CustomObjectName);

	/// Interactively show a widget
	bool InteractiveShow(const std::string& Name, const gdouble Speed, const bool Pause);
	/// Interactively highlight a widget
	bool InteractiveHighlight(const std::string& Name, const gdouble Speed, const bool Pause);
	/// Interactively activate a button
	bool InteractiveActivateButton(const std::string& Name, const gdouble Speed, const bool Pause);
	/// Interactively activate a toggle-button
	bool InteractiveToggleButton(const std::string& Name, const gdouble Speed, const bool Pause);
	/// Interactively activate a menu item
	bool InteractiveActivateMenuItem(const std::string& Name, const gdouble Speed, const bool Pause);
	/// Interactively put text into a text control
	bool InteractiveSetText(const std::string& Name, const std::string& Text, const gdouble Speed, const bool Pause);
	/// Interactively move the mouse pointer to a control (and make sure it's visible)
	bool InteractiveMoveTo(const std::string& Name, const gdouble Speed, const bool Pause);

	// Object access with typecasting
	sdpGtkAccelLabel AccelLabel(const std::string& ControlName);
	sdpGtkAdjustment Adjustment(const std::string& ControlName);
	sdpGtkArrow Arrow(const std::string& ControlName);
	sdpGtkAspectFrame AspectFrame(const std::string& ControlName);
	sdpGtkAlignment Alignment(const std::string& ControlName);
	sdpGtkBin Bin(const std::string& ControlName);
	sdpGtkBox Box(const std::string& ControlName);
	sdpGtkButton Button(const std::string& ControlName);
	sdpGtkButtonBox ButtonBox(const std::string& ControlName);
	sdpGtkCalendar Calendar(const std::string& ControlName);
	sdpGtkCheckButton CheckButton(const std::string& ControlName);
	sdpGtkCheckMenuItem CheckMenuItem(const std::string& ControlName);
	sdpGtkCList CList(const std::string& ControlName);
	sdpGtkColorSelection ColorSelection(const std::string& ControlName);
	sdpGtkColorSelectionDialog ColorSelectionDialog(const std::string& ControlName);
	sdpGtkCombo Combo(const std::string& ControlName);
	sdpGtkContainer Container(const std::string& ControlName);
	sdpGtkCTree CTree(const std::string& ControlName);
	sdpGtkCurve Curve(const std::string& ControlName);
#ifndef K3D_HAVE_GTK2
	sdpGtkData Data(const std::string& ControlName);
#endif
	sdpGtkDialog Dialog(const std::string& ControlName);
	sdpGtkDrawingArea DrawingArea(const std::string& ControlName);
	sdpGtkEditable Editable(const std::string& ControlName);
	sdpGtkEntry Entry(const std::string& ControlName);
	sdpGtkEventBox EventBox(const std::string& ControlName);
	sdpGtkFileSelection FileSelection(const std::string& ControlName);
	sdpGtkFixed Fixed(const std::string& ControlName);
	sdpGtkFontSelection FontSelection(const std::string& ControlName);
	sdpGtkFontSelectionDialog FontSelectionDialog(const std::string& ControlName);
	sdpGtkFrame Frame(const std::string& ControlName);
	sdpGtkGammaCurve GammaCurve(const std::string& ControlName);
	sdpGtkHandleBox HandleBox(const std::string& ControlName);
	sdpGtkHBox HBox(const std::string& ControlName);
	sdpGtkHButtonBox HButtonBox(const std::string& ControlName);
	sdpGtkHPaned HPaned(const std::string& ControlName);
	sdpGtkHRuler HRuler(const std::string& ControlName);
	sdpGtkHScale HScale(const std::string& ControlName);
	sdpGtkHScrollbar HScrollbar(const std::string& ControlName);
	sdpGtkHSeparator HSeparator(const std::string& ControlName);
	sdpGtkImage Image(const std::string& ControlName);
	sdpGtkInputDialog InputDialog(const std::string& ControlName);
	sdpGtkItem Item(const std::string& ControlName);
	sdpGtkLabel Label(const std::string& ControlName);
	sdpGtkList List(const std::string& ControlName);
	sdpGtkListItem ListItem(const std::string& ControlName);
	sdpGtkMenu Menu(const std::string& ControlName);
	sdpGtkMenuBar MenuBar(const std::string& ControlName);
	sdpGtkMenuItem MenuItem(const std::string& ControlName);
	sdpGtkMenuShell MenuShell(const std::string& ControlName);
	sdpGtkMisc Misc(const std::string& ControlName);
	sdpGtkNotebook Notebook(const std::string& ControlName);
	sdpGtkObject Object(const std::string& ControlName);
	sdpGtkOptionMenu OptionMenu(const std::string& ControlName);
	sdpGtkPaned Paned(const std::string& ControlName);
	sdpGtkPixmap Pixmap(const std::string& ControlName);
	sdpGtkRange Range(const std::string& ControlName);
	sdpGtkScrollbar Scrollbar(const std::string& ControlName);
	sdpGtkScrolledWindow ScrolledWindow(const std::string& ControlName);
	sdpGtkSeparator Separator(const std::string& ControlName);
	sdpGtkSpinButton SpinButton(const std::string& ControlName);
	sdpGtkStatusbar Statusbar(const std::string& ControlName);
	sdpGtkTable Table(const std::string& ControlName);
	sdpGtkTearoffMenuItem TearoffMenuItem(const std::string& ControlName);
	sdpGtkText Text(const std::string& ControlName);
	sdpGtkTipsQuery TipsQuery(const std::string& ControlName);
	sdpGtkToggleButton ToggleButton(const std::string& ControlName);
	sdpGtkToolbar Toolbar(const std::string& ControlName);
	sdpGtkTooltips Tooltips(const std::string& ControlName);
	sdpGtkTree Tree(const std::string& ControlName);
	sdpGtkTreeItem TreeItem(const std::string& ControlName);
	sdpGtkVBox VBox(const std::string& ControlName);
	sdpGtkVButtonBox VButtonBox(const std::string& ControlName);
	sdpGtkViewport Viewport(const std::string& ControlName);
	sdpGtkVPaned VPaned(const std::string& ControlName);
	sdpGtkVRuler VRuler(const std::string& ControlName);
	sdpGtkVScale VScale(const std::string& ControlName);
	sdpGtkVScrollbar VScrollbar(const std::string& ControlName);
	sdpGtkVSeparator VSeparator(const std::string& ControlName);
 	sdpGtkWidget Widget(const std::string& ControlName);
	sdpGtkWindow Window(const std::string& ControlName);

	// Root object access with typecasting ...
	sdpGtkAccelLabel RootAccelLabel();
	sdpGtkAdjustment RootAdjustment();
	sdpGtkAlignment RootAlignment();
	sdpGtkArrow RootArrow();
	sdpGtkAspectFrame RootAspectFrame();
	sdpGtkBin RootBin();
	sdpGtkBox RootBox();
	sdpGtkButton RootButton();
	sdpGtkButtonBox RootButtonBox();
	sdpGtkCalendar RootCalendar();
	sdpGtkCheckButton RootCheckButton();
	sdpGtkCheckMenuItem RootCheckMenuItem();
	sdpGtkCList RootCList();
	sdpGtkColorSelection RootColorSelection();
	sdpGtkColorSelectionDialog RootColorSelectionDialog();
	sdpGtkCombo RootCombo();
	sdpGtkContainer RootContainer();
	sdpGtkCTree RootCTree();
	sdpGtkCurve RootCurve();
#ifndef K3D_HAVE_GTK2
	sdpGtkData RootData();
#endif
	sdpGtkDialog RootDialog();
	sdpGtkDrawingArea RootDrawingArea();
	sdpGtkEditable RootEditable();
	sdpGtkEntry RootEntry();
	sdpGtkEventBox RootEventBox();
	sdpGtkFileSelection RootFileSelection();
	sdpGtkFixed RootFixed();
	sdpGtkFontSelection RootFontSelection();
	sdpGtkFontSelectionDialog RootFontSelectionDialog();
	sdpGtkFrame RootFrame();
	sdpGtkGammaCurve RootGammaCurve();
	sdpGtkHandleBox RootHandleBox();
	sdpGtkHBox RootHBox();
	sdpGtkHButtonBox RootHButtonBox();
	sdpGtkHPaned RootHPaned();
	sdpGtkHRuler RootHRuler();
	sdpGtkHScale RootHScale();
	sdpGtkHScrollbar RootHScrollbar();
	sdpGtkHSeparator RootHSeparator();
	sdpGtkImage RootImage();
	sdpGtkInputDialog RootInputDialog();
	sdpGtkItem RootItem();
	sdpGtkLabel RootLabel();
	sdpGtkList RootList();
	sdpGtkListItem RootListItem();
	sdpGtkMenu RootMenu();
	sdpGtkMenuBar RootMenuBar();
	sdpGtkMenuItem RootMenuItem();
	sdpGtkMenuShell RootMenuShell();
	sdpGtkMisc RootMisc();
	sdpGtkNotebook RootNotebook();
	sdpGtkObject RootObject();
	sdpGtkOptionMenu RootOptionMenu();
	sdpGtkPaned RootPaned();
	sdpGtkPixmap RootPixmap();
	sdpGtkRange RootRange();
	sdpGtkScrollbar RootScrollbar();
	sdpGtkScrolledWindow RootScrolledWindow();
	sdpGtkSeparator RootSeparator();
	sdpGtkSpinButton RootSpinButton();
	sdpGtkStatusbar RootStatusbar();
	sdpGtkTable RootTable();
	sdpGtkTearoffMenuItem RootTearoffMenuItem();
	sdpGtkText RootText();
	sdpGtkTipsQuery RootTipsQuery();
	sdpGtkToggleButton RootToggleButton();
	sdpGtkToolbar RootToolbar();
	sdpGtkTooltips RootTooltips();
	sdpGtkTree RootTree();
	sdpGtkTreeItem RootTreeItem();
	sdpGtkVBox RootVBox();
	sdpGtkVButtonBox RootVButtonBox();
	sdpGtkViewport RootViewport();
	sdpGtkVPaned RootVPaned();
	sdpGtkVRuler RootVRuler();
	sdpGtkVScale RootVScale();
	sdpGtkVScrollbar RootVScrollbar();
	sdpGtkVSeparator RootVSeparator();
	sdpGtkWidget RootWidget();
	sdpGtkWindow RootWindow();

protected:
	/// Frees up all storage
	void Clear();
	/// Frees "normal" GTK+ objects
	void ClearObjects();
	/// Frees "custom" objects
	void ClearCustomObjects();
	/// Frees radio-button/radio menu item groups
	void ClearGroups();
	/// Frees event objects
	void ClearEvents();

	// sdpGtkIObjectContainer overrides ...
	void NotifyObject(GtkObject* Object);
	void MapObject(SDPCSTRING ObjectName, GtkObject* Object);
	void MapCustomObject(SDPCSTRING CustomObjectName, sdpGtkObject* CustomObject);
	void MapGroup(SDPCSTRING GroupName, GSList* Group);
	void MapResource(SDPCSTRING ResourceName, SDPCSTRING ResourceValue);
	void MapEvent(sdpxml::Document& Document, sdpxml::Element& Element, GtkObject* Object, bool Connect);
	sdpGtkObject* CreateCustomObject(sdpxml::Element& Element);
	GtkAccelGroup* GetAcceleratorGroup();
	GtkObject* GetObject(SDPCSTRING ObjectName);
	GSList* GetGroup(SDPCSTRING GroupName);
	const boost::filesystem::path reference_path();

private:
	/// Tests to see that there are no unused elements or attributes in a GTKML document
	bool TestCoverage(const sdpxml::Document& XML);
	/// Recursively tests to see that an element and its children were "used" by a GTKML document
	bool TestElementCoverage(const sdpxml::Document& Document, const sdpxml::Element& Element);

	/// Stores the state of the modal loop
	bool m_RunModal;

	typedef std::map<std::string, GtkObject*> ObjectMap;
	typedef ObjectMap::iterator ObjectIterator;
	/// Stores the mapping of names to objects
	ObjectMap m_Objects;
	
	typedef std::map<std::string, sdpGtkObject*> CustomObjectMap;
	typedef CustomObjectMap::iterator CustomObjectIterator;
	/// Stores the mapping of names to custom objects
	CustomObjectMap m_CustomObjects;
	
	typedef std::map<std::string, GSList*> GroupMap;
	typedef GroupMap::iterator GroupIterator;
	/// Stores the mapping of names to groups
	GroupMap m_Groups;

	typedef std::multimap<std::string, sdpGtkEvent*> EventMap;
	typedef EventMap::iterator EventIterator;
	/// Stores the mapping of names to events
	EventMap m_Events;

	/// Singleton accelerator group for handling accelerator keys
	GtkAccelGroup* m_AcceleratorGroup;
	
	typedef std::map<std::string, std::string> ResourceMap;
	typedef ResourceMap::iterator ResourceIterator;
	/// Stores the mapping of names to resources
	ResourceMap m_Resources;

	/// Stores the reference path for loading external resources (like pixmaps)
	boost::filesystem::path m_reference_path;
};

#endif // SDPGTKOBJECTCONTAINER_H

