/*______________
|       ______  |   U I Z E     J A V A S C R I P T     A P I
|     /      /  |   -----------------------------------------
|    /    O /   |    MODULE : Uize.Widget Class (version 1.1.0)
|   /    / /    |    AUTHOR : Chris van Rensburg (http://www.tomkidding.com)
|  /    / /  /| |    ONLINE : http://www.tomkidding.com/uize/uize-js-api
| /____/ /__/_| | COPYRIGHT : (c)2005-2006 Chris van Rensburg
|          /___ |   LICENSE : Distributed under the terms of the GNU General Public License
|_______________|             http://www.gnu.org/licenses/gpl.txt
*/

/*
	TO DO
		- DOCUMENT
			- setNodeClipRect
			- setNodeInnerHtml
			- showNode
			- wireNodeEvent
			- wireNodeEvents
			- unwireNodeEventsByMatch
			- checkInherited
			- insertUi
			- Uize.Widget.spawn

		- decide new semantics for child widgets
			widgets (concise)
				addWidget ()
				removeWidget ()
				widgets
				parent

				EXAMPLE: this.widgets.option0.widgets.selector
				VOTES: Jan

			widgets (very concise, possibly too ambiguous / unclear)
				add () - add may conflict with add in Zazzle.ProductAttributes
				remove ()
				widgets
				parent

				EXAMPLE: this.widgets.option0.widgets.selector

			childWidgets - parent/child (verbose)
				addChildWidget ()
				removeChildWidget ()
				childWidgets
				parentWidget

				EXAMPLE: this.childWidgets.option0.childWidgets.selector

			children (very concise, possibly too ambiguous / unclear)
				add () - add may conflict with add in Zazzle.ProductAttributes
				remove ()
				children
				parent

				EXAMPLE: this.children.option0.children.selector
				VOTES: Ben

			children (not as short as I'd like)
				addChild ()
				removeChild ()
				children
				parent

				EXAMPLE: this.children.option0.children.selector

			own (very concise, but maybe strange & unfamiliar)
				own ()
				disown ()
				owned
				owner

				EXAMPLE: this.owned.option0.owned.selector

			contain (not as short as I'd like, with no added clarity value)
				contain ()
				release ()
				contained
				container

				EXAMPLE: this.contained.option0.contained.selector

		- insertion-into-shell modes (replace, append)
		- when html property is a function, supply it with outer dimensions, based on shell size
*/

/*ScruncherSettings Mappings="=b" LineCompacting="TRUE"*/

/*?
	Introduction
		Summary
			Provides a set of services and a framework for developing UI widget classes.

		Requires
			- Uize.js (base class)
			- Uize.Node.js

		An Abstract Class
			The =Uize.Widget= class is primarily an abstract class, intended for the creation of widget subclasses. However, it is possible and sometimes useful to create instances of this class that will act as wrappers for sets of child widgets in order to achieve functional grouping for the child widgets within a widget class. Child widgets grouped together in this way can then be enabled or disabled as a group, separately from the other child widgets.

		### Concepts
			Child Widgets

		Widget Principles
			Self-maintaining UI
				The =updateUi= method - as a general rule - should never be called by code that is using a particular widget. The code using a widget should not be responsible for knowing that the user interface of a widget needs to be updated. The code using a widget should only change state of a widget using the properties interface (or, in rare cases, special state setting combo methods). If a widget's state is changed in a way that should be reflected in its user interface, then it is the responsibility of the widget code to detect this and update its UI accordingly.

			Recoverable UI
				All the state properties that influence a widget's UI should be maintained in the widget instance. In other words, parameters should not be used to qualify how a widget's UI is represented and then forgotten to the widget. So, at any given moment if a widget is coerced to regenerate its UI, the result should exactly match the last generated UI.

			Update Optimization
				- setting a widget repeatedly to the same state should not result in repeated redundant refreshes
				- changing the state of multiple properties that will affect a widget's UI in a batch =set= method call should only result in a single refresh
				- a widget's UI generation code may be optimized such that subcomponents of the UI are only regenerated or refreshed if the state properties that relate to them have changed since the last time the UI was updated.
*/

(function () {
	/*** Variables for Scruncher Optimization ***/
		var
			_null = null,
			_true = true,
			_false = false,
			_string = 'string',
			_undefined,
			_Uize_Node = Uize.Node,
			_typeFunction = 'function'
		;

	/*** Object Constructor ***/
		var
			_superclass = Uize,
			_class = _superclass.Widget = _superclass.subclass (
				function () {
					var _this = this;

					/*** Public Instance Properties ***/
						_this.widgets = _this._widgets = {
							/*?
								Instance Properties
									widgets
										The =widgets= instance property is an object that serves to contain and manage child widgets that are used in the implementation of a widget.
							*/
							add:function (_widgetName,_widget) {
								this.map [_widgetName] = _widget;
								_widget.parent = _this;
								_widget._name = _widgetName;
								if (!_widget._idPrefix && _this._idPrefix)
									_widget.set ({_idPrefix:_this._getChildWidgetIdPrefix (_widgetName)})
								;
								return _widget;
								/*?
									Instance Properties
										widgets
											add
												The =add= method lets you add a child widget to a widget.

												SYNTAX
												.................................................
												myWidget.add (childWidgetNameSTR,childWidgetOBJ);
												.................................................

												NOTES
												- see also the =remove= method of the =widgets= object
								*/
							},
							map:{
								/*?
									Instance Properties
										widgets
											map
												The =map= property is an object, each of who's properties is a reference to one of a widget's child widgets. For example, an instance of the =Uize.Widget.SlideShow= class may have child widgets that can be referenced as follows...

												................................
												mySlideShow.widgets.map.first
												mySlideShow.widgets.map.last
												mySlideShow.widgets.map.previous
												mySlideShow.widgets.map.next
												................................
								*/
							},
							remove:function (_widget) {
								var _map = this.map;
								function _removeWidgetByName (_widgetName) {
									_map [_widgetName].unwireUi ();
									delete _map [_widgetName].parent;
									delete _map [_widgetName];
								}
								if (typeof _widget == _string) {
									if (_map [_widget]) _removeWidgetByName (_widget);
								} else {
									for (var _widgetName in _map) {
										if (_map [_widgetName] === _widget) {
											_removeWidgetByName (_widgetName);
											break;
										}
									}
								}
								/*?
									Instance Properties
										widgets
											remove
												The =remove= method lets you remove a child widget from a widget.

												SYNTAX
												......................................
												myWidget.remove (childWidgetSTRorOBJ);
												......................................

												When using this method, the child widget to remove can be specified by its name, or by an object reference to it.

												NOTES
												- see also the =add= method of the =widgets= object
								*/
							}
						};

					/*** Private Instance Properties ***/
						_this._inherited = {};
						_this._nodeCache = {};
				}
			),
			_classPrototype = _class.prototype
		;

	/*** Private Instance Methods ***/
		/* NOTE:
			it's unlike me to write code like this, where two identical patterns aren't reduced to a common function that is parameterized, but this is for performance optimization until the inherited properties system is refactored to "cache" resultant values in an "update downwards" manner
		*/
		_classPrototype._getInheritedBusy = function () {
			var
				_instance = this,
				_value
			;
			do {
				_value = _instance._busy;
				_instance = _instance.parent;
			} while (
				_value === 'inherit' && _instance
			);
			return this._inherited.busy = _value;
		};

		_classPrototype._getInheritedEnabled = function () {
			var
				_instance = this,
				_value
			;
			do {
				_value = _instance._enabled;
				_instance = _instance.parent;
			} while (
				_value === 'inherit' && _instance
			);
			return this._inherited.enabled = _value;
		};

		_classPrototype._getChildWidgetIdPrefix = function (_widgetName) {
			return this._getOrResolveIdPrefix () + (this._useNewIdSyntax ? '_' : '') + _widgetName;
		};

		_classPrototype._getOrResolveIdPrefix = function () {
			var _this = this;
			return _this._idPrefix || (_this.parent ? _this.parent._getChildWidgetIdPrefix (_this._name) : '');
		};

		_classPrototype._insertOrWireUiOfChildren = function (_methodName) {
			var
				_this = this,
				_widgetsMap = _this._widgets.map,
				_isInsertUi = _methodName == 'insertUi'
			;
			if (!_this._idPrefix)
				_this.set ({_idPrefix:_this._getOrResolveIdPrefix ()})
			;
			for (var _widgetName in _widgetsMap) {
				var _widget = _widgetsMap [_widgetName];
				if (!_widget._idPrefix)
					_widget.set ({_idPrefix:_this._getChildWidgetIdPrefix (_widgetName)})
				;
				_isInsertUi || !_widget._built ? _widget.insertUi () : _widget.wireUi ();
			}
		};

	/*** Public Instance Methods ***/
			_classPrototype.wired = function (_wired) {
				if (typeof _wired == 'boolean') this.set ({_wired:_wired});
				return this._wired;
				/*?
					Instance Methods
						wired
							Lets you set or query the value of the =wired= set-get property. This method is primarily a convenience method, since the =wired= set-get property is accessed many times in many widget class files.

							SYNTAX
							..................
							myWidget.wired ();
							..................

							When no parameter is specified, this method returns the current value for the =wired= set-get property. This is equivalent to =myWidget.get ('wired')=.

							SYNTAX
							...........................
							myWidget.wired (wiredBOOL);
							...........................

							When a boolean value is specified, this method sets the =wired= set-get property to the specified value. This is equivalent to =myWidget.set ({wired:wiredBOOL})=.

							NOTES
							- see also the =wired= set-get property
				*/
			};

		/*** UI Node Methods ***/
			_classPrototype.getNode = function (_nodeBlob) {
				var _result = _null;
				if (_nodeBlob !== _null) {
					var
						_this = this,
						_idDelimiter = _this._useNewIdSyntax ? '-' : ''
					;
					if (!_nodeBlob) _nodeBlob = '';
					if (_this._nodeMap && typeof _nodeBlob == _string) {
						var _remappedNode = _this._nodeMap [_nodeBlob];
						if (_remappedNode !== _undefined)
							_nodeBlob = _remappedNode
						;
					}
					if (_Uize_Node.isNode (_nodeBlob)) {
						_result = _nodeBlob;
					} else if (typeof _nodeBlob == _string) {
						_result = _Uize_Node.getById (_nodeBlob,_this._idPrefix,_idDelimiter,_this._nodeCache);
					} else {
						_Uize_Node.doForAll (
							_nodeBlob,
							function (_node) {(_result || (_result = [])).push (_node)},
							_this._idPrefix,
							_idDelimiter,
							_this._nodeCache
						);
					}
				}
				return _result;
				/*?
					Instance Methods
						getNode
							Returns a reference to the specified implied node of the widget.

							SYNTAX
							........................................
							myWidget.getNode (impliedNodeSTRorBLOB);
							........................................

							EXAMPLE
							...........................................
							var sliderKnob = mySlider.getNode ('knob');
							...........................................

							Returns the "knob" implied node of the slider widget.

							EXAMPLE
							.........................................
							var sliderRootNode = mySlider.getNode ();
							.........................................

							Returns the =root node= of the slider widget.

							NOTES
							- The =impliedNodeSTRorOBJ= parameter can be a string specifying the name of the implied node, or an object reference to the implied node. When a reference is specified, it is simply returned.
							- When the =impliedNodeSTRorOBJ= parameter has a value of =null=, then the value =null= is returned.
							- When the =impliedNodeSTRorOBJ= parameter has a value of =undefined= or is not specified, then the =root node= of the widget is returned. This has the same effect as specifying the empty string. (ie. =getNode ()= is equivalent to =getNode ('')=)
				*/
			};

			_classPrototype.flushNodeCache = function (_impliedNodeName) {
				delete this._nodeCache [
					_Uize_Node.joinIdPrefixAndNodeId (this._idPrefix,_impliedNodeName,this._useNewIdSyntax ? '-' : '')
				];
			};

			_classPrototype.displayNode = function (_impliedNode,_mustDisplay) {
				return _Uize_Node.display (this.getNode (_impliedNode),_mustDisplay);
				/*?
					Instance Methods
						displayNode
							Lets you display or hide the specified implied node.

							SYNTAX
							...............................................................
							myWidget.displayNode (impliedNodeSTRorBLOB,mustDisplayANYTYPE);
							...............................................................

							While typically a Boolean, the =mustDisplayANYTYPE= parameter can be of any type and the node will be displayed if it resolves to =true=, and hidden if it resolves to =false= - with the exception of =undefined=, when the node will be displayed (see explanation below).

							VARIATIONS
							............................................
							myWidget.displayNode (impliedNodeSTRorBLOB);
							............................................

							When no =mustDisplayANYTYPE= parameter is specified (or when its value is =undefined=), the node will be displayed.

							NOTES
							- compare to the =showNode= instance method
				*/
			};

			_classPrototype.removeNode = function (_impliedNode) {
				return _Uize_Node.remove (this.getNode (_impliedNode));
				/*?
					Instance Methods
						removeNode
							Removes the specified implied node (or nodes) from the DOM.

							SYNTAX
							...........................................
							myWidget.removeNode (impliedNodeSTRorBLOB);
							...........................................
				*/
			};

			_classPrototype.setNodeProperties = function (_impliedNode,_properties) {
				return _Uize_Node.setProperties (this.getNode (_impliedNode),_properties);
				/*?
					Instance Methods
						setNodeProperties
							Sets the specified properties for the specified implied node (or nodes).

							SYNTAX
							................................................................
							myWidget.setNodeProperties (impliedNodeSTRorBLOB,propertiesOBJ);
							................................................................

							EXAMPLE
							............................
							myWidget.setNodeProperties (
								'thumbnail',
								{
									src:...,
									width:...,
									height:...,
									title:...
								}
							);
							............................
				*/
			};

			_classPrototype.setNodeOpacity = function (_impliedNode,_opacity) {
				return _Uize_Node.setOpacity (this.getNode (_impliedNode),_opacity);
				/*?
					Instance Methods
						setNodeOpacity
							Sets the opacity (and, therefore, the transparency) of the specified implied node (or nodes).

							SYNTAX
							............................................................
							myWidget.setNodeOpacity (impliedNodeSTRorBLOB,opacityFLOAT);
							............................................................

							=opacityFLOAT= should be a number in the range of =0= to =1=, where =0= represents completely invisible, =1= represents completely opaque, and any fractional values inbetween represent varying degrees of transparency / opacity.
				*/
			};

			_classPrototype.setNodeStyle = function (_impliedNode,_style) {
				return _Uize_Node.setStyle (this.getNode (_impliedNode),_style);
				/*?
					Instance Methods
						setNodeStyle
							Sets values for an arbitrary set of style attributes for the specified implied node (or nodes).

							SYNTAX
							...........................................................
							myWidget.setNodeStyle (impliedNodeSTRorBLOB,propertiesOBJ);
							...........................................................

							EXAMPLE
							..................................................
							myWidget.setNodeStyle (
								'selector',
								{
									display:'block',
									position:'absolute',
									visibility:'inherit',
									top:'100px'
								}
							);
							..................................................
				*/
			};

			_classPrototype.setNodeClipRect = function (_impliedNode,_left,_top,_right,_bottom) {
				return _Uize_Node.setClipRect (this.getNode (_impliedNode),_left,_top,_right,_bottom);
				/*?
					Instance Methods
						setNodeClipRect

				*/
			};

			_classPrototype.setNodeInnerHtml = function (_impliedNode,_html) {
				return _Uize_Node.setInnerHtml (this.getNode (_impliedNode),_html);
			};

			_classPrototype.showNode = function (_impliedNode,_mustShow) {
				return _Uize_Node.show (this.getNode (_impliedNode),_mustShow);
			};

			_classPrototype.wireNodeEvent = function (_impliedNode,_eventName,_handler) {
				_Uize_Node.wireEvent (this.getNode (_impliedNode),_eventName,_handler,this.objectName);
			};

			_classPrototype.wireNodeEvents = function (_impliedNode,_eventsToHandlers) {
				_Uize_Node.wireEvents (this.getNode (_impliedNode),_eventsToHandlers,this.objectName);
			};

			_classPrototype.unwireNodeEventsByMatch = function (_impliedNode,_eventMatch) {
				_Uize_Node.unwireEventsByOwnerId (
					this.objectName,
					_class.copyInto ({node:this.getNode (_impliedNode)},_eventMatch)
				);
			};

		/*** Hierarchy Related Methods ***/
			_classPrototype.checkInherited = function (_property) {
				var
					_this = this,
					_inherited = _this._inherited,
					_oldValue = _inherited [_property] !== _undefined ? _inherited [_property] : 'inherit'
				;
				if (_property == 'busy') {
					_this._getInheritedBusy ();
				} else if (_property == 'enabled') {
					_this._getInheritedEnabled ();
				} else {
					_this.getInherited (_property);
				}
				if (_inherited [_property] != _oldValue) {
					if (_property != 'busy') {
						_this.updateUi ();
					} else if (_this.updateUiBusy) {
						/* NOTE:
							until a better solution is found, for performance reasons don't perform a UI update for the widget when the busy property changes unless it implements a lightweight updateUiBusy method (which most widgets don't implement and which buttons do)
						*/
						_this.updateUiBusy ();
					}
					_class.callOn (_this._widgets.map,'checkInherited',[_property])
				}
			};

			_classPrototype.getProvider = function (_property) {
				var
					_instance = this,
					_value
				;
				while (_instance) {
					_value = _instance.get (_property);
					if (_value === 'inherit' || _value === _undefined) {
						_instance = _instance.parent;
					} else {
						break;
					}
				}
				return _instance;
				/*?
					Instance Methods
						getProvider
							Returns a reference to the nearest widget instance up the parent widget chain that provides a value for the specified get-set property.

							SYNTAX
							.........................................
							myWidget.getProvider (setGetPropertySTR);
							.........................................

							If a value other than ='inherit'= or =undefined= is set for the specified set-get property of the instance, then a reference to the instance will be returned. Otherwise, this method will walk up the parent widget chain until a widget is found that has a value other than ='inherit'= or =undefined= set for this set-get property. If none is found, then the value =undefined= will be returned.

							NOTES
							- see also the =callInherited=, =checkInherited=, =getInherited=, and =setInherited= instance methods
				*/
			};

			_classPrototype.getInherited = function (_property) {
				var _provider = this.getProvider (_property);
				return _provider ? _provider.get (_property) : _undefined;
				/*?
					Instance Methods
						getInherited
							Returns the inherited value for the specified get-set property.

							SYNTAX
							..........................................
							myWidget.getInherited (setGetPropertySTR);
							..........................................

							If a value other than ='inherit'= or =undefined= is set for the specified set-get property of the instance, then the property's value will be returned. Otherwise, this method will walk up the parent widget chain until a widget is found that has a value other than ='inherit'= or =undefined= set for this set-get property. If none is found, then the value =undefined= will be returned.

							NOTES
							- see also the =callInherited=, =checkInherited=, =getProvider=, and =setInherited= instance methods
				*/
			};

			_classPrototype.setInherited = function (_properties) {
				var _this = this;
				for (var _propertyName in _properties) {
					var _provider = _this.getProvider (_propertyName);
					if (_provider) {
						var _propertyNameValue = {};
						_propertyNameValue [_propertyName] = _properties [_propertyName];
						_provider.set (_propertyNameValue);
					}
				}
			};

			_classPrototype.callInherited = function (_property) {
				var _this = this;
				return (
					function () {
						var
							_provider = _this.getProvider (_property),
							_result
						;
						if (_provider) {
							var _inheritedMethod = _provider.get (_property);
							if (typeof _inheritedMethod == _typeFunction)
								_result = _inheritedMethod.apply (_provider,arguments)
							;
						}
						return _result;
					}
				);
			};

			_classPrototype.isEnabled = function () {
				return this._getInheritedEnabled () !== _false
				/*?
					Instance Methods
						isEnabled
							Returns a boolean, indicating whether or not the instance is enabled. A widget subclass can use this method when performing UI updates in order to reflect a disabled state.

							This method will return =true= if the =enabled= set-get property is set to =true=, or if this property is set to ='inherit'= and the inherited value resolves to either ='inherit'= or =true=.

							NOTES
							- see also the =enabled= set-get property
							- see also the =getInherited= instance method
				*/
			};

			_classPrototype.isBusy = function () {
				return this._getInheritedBusy () === _true
				/*?
					Instance Methods
						isBusy
							Returns a boolean, indicating whether or not the instance is busy. A widget subclass can use this method when performing UI updates in order to reflect a busy state.

							This method will return =true= if the =busy= set-get property is set to =true=, or if this property is set to ='inherit'= and the inherited value resolves to =true=. If an inherited value resolves to =inherit=, then this method will return =false=.

							NOTES
							- see also the =busy= set-get property
							- see also the =getInherited= instance method
				*/
			};

		/*** Overridable Wiring and Updating Methods ***/
			_classPrototype.kill = function () {
				_class.callOn (this._widgets.map,'kill');
				_superclass.prototype.kill.call (this);
				/*?
					Instance Methods
						kill
							Overrides the =kill= method of the =Uize= base class to call the =kill= method on all of an instance's child widgets.

							SYNTAX
							.................
							myWidget.kill ();
							.................
				*/
			};

			_classPrototype.insertUi = function () {
				var _this = this;
				if (!_this._idPrefix)
					_this.set ({_idPrefix:_this.objectName + (_this._useNewIdSyntax ? '' : '_')})
					/* NOTE: in the old scheme, we appended an underscore for the case where no idPrefix was specified */
				;
				if (_this._html) {
					var
						_html = _class.substituteInto (
							typeof _this._html == _string ? _this._html : _this._html (),
							_class.copyInto (
								{
									idPrefix:_this._idPrefix,
									pathToResources:_this.objectClass.pathToResources,
									blankGif:Uize.getBlankImageUrl ()
								},
								_this._htmlSubstitutions
							)
						),
						_nodeToInsertInto = _this._container || _this.getNode () || _this.getNode ('shell')
					;
					_nodeToInsertInto ? _Uize_Node.setInnerHtml (_nodeToInsertInto,_html) : document.write (_html);
				}
				_this._insertOrWireUiOfChildren ('insertUi');
				_this.wireUi ();
			};

			_classPrototype.removeUi = function () {
				var _this = this;
				_this.unwireUi ();
				_this.removeNode ();
				_class.callOn (_this._widgets.map,'removeUi')
				/*?
					Instance Methods
						removeUi
							Unwires the UI of the widget, removes the widget's root node from the DOM, and calls this method on all the widget's child widgets.

							SYNTAX
							.....................
							myWidget.removeUi ();
							.....................
				*/
			};

			_classPrototype.updateUi = function () {
				/*?
					Instance Methods
						updateUi
							Not implemented in this class, this method is intended to be overrided / implemented in a subclass.

							SYNTAX
							.....................
							myWidget.updateUi ();
							.....................

							The =updateUi= method is called on the instance as the last step of this class' =wireUi= method implementation. The =updateUi= method should perform any DOM updates necessary in order that the UI correctly reflect the widget's state.

							Child Widgets
								It is generally not necessary for the implementation of this method to invoke updates on child widgets, unless the child widgets are used to represent some aspects of the widget's state and may have become out of sync with that state. Typically, state of a widget that is reflected using its child widgets is set on those child widgets whenever that state changes using private update handlers that are more granular than the =updateUi= method. It might be desirable in one's implementation to break granular update code out into private methods so that this code can be called for those state changes as well as from the =updateUi= method's implementation.

							NOTES
							- although this method currently has no implementation in this class, it is suggested that subclasses call this method on their superclass as the last step in their implementation, as this method may someday perform other operations in this class
				*/
			};

			_classPrototype.wireUi = function () {
				var _this = this;
				if (!_this._wired) {
					_this._wired = _true;
					_this._insertOrWireUiOfChildren ('wireUi');
					_this.updateUi ();
				}
				/*?
					Instance Methods
						wireUi
							Wires the widget's UI.

							After the UI has been wired, all of the widget's child widgets are wired by calling this method on each of them. Finally, the widget's UI is updated through a call to the =updateUi= instance method, which also has the effect of updating the UI of all child widgets down the widget tree.

							When creating a subclass of Uize.Widget, this method should be overrided according to the following structure...

							................................................
							_classPrototype.wireUi = function () {
								var _this = this;
								if (!_this.wired ()) {

									// do a
									// whole bunch
									// of wiring

									_superclass.prototype.wireUi.call (_this);
								}
							};
							................................................

							...where =_classPrototype= is the prototype property of the widget subclass being implemented, and =_superclass= is the superclass from which the new widget class is being subclassed.

							NOTES
							- if the widget's UI has already been wired, this method has no effect.
							- see also the =wired= set-get property
							- see also the =updateUi= and =unwireUi= instance methods
				*/
			};

			_classPrototype.unwireUi = function () {
				var _this = this;
				if (_this._wired) {
					_this._nodeCache = {};
					_Uize_Node.unwireEventsByOwnerId (_this.objectName);
					_class.callOn (_this._widgets.map,'unwireUi');
					_this._wired = _false;
				}
				/*?
					Instance Methods
						unwireUi
							Unwires all the events associated to the instance and all of its child widgets. After this method has been called, the =wired= set-get property will be set to =false=.

							SYNTAX
							.....................
							myWidget.unwireUi ();
							.....................

							NOTES
							- see also the =wireUi= instance method
				*/
			};

	/*** Public Static Methods ***/
		_class.spawn = function (_properties) {
			var
				_this = this,
				_instances = []
			;
			_Uize_Node.doForAll (
				_properties.idPrefix,
				function (_node) {
					_properties.idPrefix = _node;
					var _instance = new _this (_properties);
					_instance.wireUi ();
					_instances.push (_instance);
				}
			);
			return _instances;
		};

	/*** Setup Properties ***/
		_class.registerProperties ({
			_built:{
				name:'built',
				value:_true
				/*?
					Set-get Properties
						built
							A boolean, indicating whether or not a specific child widget's UI has already been built and inserted into the DOM by the time that its parent widget wires up the child widgets.

							NOTES
							- the initial value is =true=
				*/
			},
			_busy:{
				name:'busy',
				onChange:function () {this.checkInherited ('busy')},
				value:'inherit'
				/*?
					Set-get Properties
						busy
							A boolean, indicating whether or not the widget is busy.

							The busy state can be useful when a complex set of processes needs to be performed and user interaction with certain widgets needs to be blocked during that time. Widgets that are in a busy state should not allow user interaction. It is up to an individual widget class to provide its own implementation for the busy state.

							NOTES
							- the initial value is =true=
							- this set-get property has a significantly different effect to the =enabled= set-get property
				*/
			},
			_container:'container',
				/*?
					Set-get Properties
						container
							A string, representing the ID of a container node, or an object reference to a container node, into which the HTML for a widget should be inserted when the =insertUi= instance method is called.

							NOTES
							- the initial value is undefined
				*/
			_idPrefix:{
				name:'idPrefix|node',
				onChange:function () {
					var _this = this;
					/*** if the idPrefix is a node reference, convert it to a string ***/
						if (_Uize_Node.isNode (_this._idPrefix)) {
							if (!_this._idPrefix.id)
								_this._idPrefix.id = Uize.getGuid ()
							;
							_this._idPrefix = _this._idPrefix.id;
						}

					/*** apply global qualifier properties ***/
						if (!_this.parent || _this._idPrefix != _this.parent._idPrefix) {
							/* NOTE:
								There are still some widgets that are implemented using child widgets where the idPrefix of the child widgets is set to that of the parent widget, and we don't want the global qualifier properties being applied to those child widgets, so we check for this condition.
							*/
							var _globalQualifierProperties = window ['$' + _this._idPrefix];
							if (_globalQualifierProperties) {
								_this.set (_globalQualifierProperties);
								window ['$' + _this._idPrefix] = _null; /* once we've applied the global qualifier properties, we clean them up so that they don't continue taking up space in memory */
							}
						}

					/*** rewire the widget, if it's already wired ***/
						if (_this._wired) {
							// perhaps any previously wired nodes should also be unwired first
							_this._wired = _false;
							_this.wireUi ();
						}
				},
				value:''
				/*?
					Set-get Properties
						idPrefix
							A string, specifying the ID prefix to be used when resolving implied nodes and child widgets to DOM node references.

							NOTES
							- the initial value is undefined
				*/
			},
			_enabled:{
				name:'enabled',
				onChange:function () {this.checkInherited ('enabled')},
				value:'inherit'
				/*?
					Set-get Properties
						enabled
							A boolean, specifying whether or not the widget is enabled.

							The enabled state can be useful when a complex set of processes needs to be performed and user interaction with certain widgets needs to be blocked during that time. Widgets that are not in an enabled state (ie. disabled) should not allow user interaction. It is up to an individual widget class to provide its own implementation for the enabled state.

							NOTES
							- the initial value is =true=
							- this set-get property has a significantly different effect to the =busy= set-get property
				*/
			},
			_html:'html',
				/*?
					Set-get Properties
						html
							A string, representing the HTML template that should be used by the =insertUi= instance method, or a function that will return the string HTML template.

							NOTES
							- the initial value is undefined
				*/
			_htmlSubstitutions:{
				name:'htmlSubstitutions',
				value:{}
				/*?
					Set-get Properties
						htmlSubstitutions
							An object, whose properties are substituted into a widget's HTML template when using the =insertUi= instance method.

							NOTES
							- the initial value is ={}= (and empty object)
				*/
			},
			_name:{
				name:'name',
				value:''
			},
			_nodeMap:'nodeMap',
				/*?
					Set-get Properties
						nodeMap
							An object which, if defined, allows you to provide override mappings for implied nodes. Each property's name-value pair is a single implied node mapping, where the property name is the natural name (as implemented in the widget subclass) for the implied node, and where the property value is the override (which can be either an alternate node name, or an actual node reference).

							NOTES
							- the initial value is undefined
				*/
			_useNewIdSyntax:{
				name:'useNewIdSyntax',
				value:_true
				/*?
					Set-get Properties
						useNewIdSyntax
							A boolean, indicating whether or not the new ID syntax for the implied nodes of widget's UI should be used. This property can be set to =false= in the implementation of a widget subclass that has not yet been updated to use the new syntax.

							NOTES
							- the initial value is =true=
				*/
			},
			_wired:{
				name:'wired|uiWired',
				value:_false
				/*?
					Set-get Properties
						wired
							A boolean, indicating whether or not the widget's UI has been wired up. This property is set to =true= after the =wireUi= instance method has been called on a widget and all its child widgets.

							NOTES
							- the initial value is =false=
							- see also the =wired= instance method
				*/
			}
		});

		/*** wire up some window events ***/
			/* IMPORTANT:
				can't use the Uize.Node.wireEvent method here, because it fails in IE on testing window as an HTML element node -- perhaps that method needs to get fixed to allow it to be called for window objects
			*/
			/*** code for firing "Document Loaded" event ***/
				function _documentLoaded () {
					clearTimeout (_documentLoadedTimeout);
					if (typeof _oldWindowOnload == _typeFunction) _oldWindowOnload ();
					_class.fireEvent ('Document Loaded');
					/*?
						Static Events
							Document Loaded
								The =Document Loaded= event is fired for the class when the document has loaded (ie. the =window.onload= event has fired) or if the =window.onload= event hasn't fired after 15 seconds has passed.

								Event Properties
									This event does not pass any additional event properties.
					*/
				}
				var
					_oldWindowOnload = window.onload,
					_documentLoadedTimeout = setTimeout (_documentLoaded,15000)
				;
				window.onload = _documentLoaded;

			/*** code for firing "Document Unload" event ***/
				var _oldWindowOnunload = window.onunload;
				window.onunload = function () {
					_class.fireEvent ('Document Unload');
					if (typeof _oldWindowOnunload == _typeFunction) _oldWindowOnunload ();
					/*?
						Static Events
							Document Unload
								The =Document Unload= event is fired for the class when the document unloads (ie. the =window.onunload= event fires).

								Event Properties
									This event does not pass any additional event properties.
					*/
				};

			/*** code for firing "Window Resized" event ***/
				var _oldOnresize = window.onresize;
				window.onresize = function () {
					_class.fireEvent ('Window Resized');
					if (typeof _oldOnresize == _typeFunction) _oldOnresize ();
					/*?
						Static Events
							Window Resized
								The =Window Resized= event is fired for the class when the document is resized (ie. the =window.onresize= event fires).

								Event Properties
									This event does not pass any additional event properties.
					*/
				};

			/*** code for firing "Window Resized" event ***/
				var _oldOnscroll = window.onscroll;
				window.onscroll = function () {
					_class.fireEvent ('Window Scrolled');
					if (typeof _oldOnscroll == _typeFunction) _oldOnscroll ();
					/*?
						Static Events
							Window Scrolled
								The =Window Scrolled= event is fired for the class when the document is scrolled (ie. the =window.onscroll= event fires).

								Event Properties
									This event does not pass any additional event properties.
					*/
				};
}) ();

