/*______________
|       ______  |   U I Z E     J A V A S C R I P T     A P I
|     /      /  |   -----------------------------------------
|    /    O /   |    MODULE : Uize.Widget.PopupPalette Class (version 1.2.0)
|   /    / /    |    AUTHOR : Chris van Rensburg (original code donated by Zazzle, Inc.)
|  /    / /  /| |    ONLINE : http://www.tomkidding.com/uize/uize-js-api
| /____/ /__/_| | COPYRIGHT : (c)2005-2006 UIZE
|          /___ |   LICENSE : Distributed under the terms of the GNU General Public License
|_______________|             http://www.gnu.org/licenses/gpl.txt
*/

/*ScruncherSettings Mappings="=c" LineCompacting="TRUE"*/

/*?
	Introduction
		Summary
			A class to manage state for a generic popup palette control.

		Requires
			- Uize.Widget.js (base class)
			- Uize.Node.js
			- Uize.Fade.js
			- Uize.Widget.Button.js
*/

(function () {
	/*** Object Constructor ***/
		var
			_superclass = Uize.Widget,
			_class = _superclass.PopupPalette = _superclass.subclass (
				function () {
					var _this = this;

					/*** set up the fade instance ***/
						_this.fade = new Uize.Fade ({
							duration:750,
							acceleration:0,
							deceleration:1
						});
						_this.fade.addEventHandlers ({
							'Changed.value':
								function () {_this.setNodeOpacity ('palette',_this.fade.get ('value'))},
							Done:
								function () {_this._showPalette (_this.fade.get ('value') != 0)}
						});
						/*?
							Instance Properties
								fade
									An instance of the =Uize.Fade= class that is used to animate the optional fade in and out effect when the popup palette is shown or hidden.

									Because this instance is exposed through a public property, you can use this reference to modify the behavior of the fade in/out effect.
						*/

					/*** create the selector button ***/
						var _selector = _this._selector = _this._addChildButton (
							'selector',
							function (_event) {
								if (!_this._showWhenOver) _this._togglePalette (_event.domEvent);
							}
						);
						_selector.set ({clickToDeselect:true});
						function _handleOverOut (_event) {
							if (_this._showWhenOver && _this._selector.get ('selected') == (_event.name == 'Out'))
								_this._togglePalette (_event.domEvent)
							;
						}
						_selector.addEventHandlers ({
							Down:_setMouseDownOnPaletteTrue,
							Over:_handleOverOut,
							Out:_handleOverOut
						});
						/*?
							Child Widgets
								selector
									An instance of =Uize.Widget.Button= that lets the user trigger the popup palette.
						*/

					/*** Initialization ***/
						_instances [_this.objectName] = _this;
				}
			),
			_classPrototype = _class.prototype,
			_instances = {}
		;

	/*** Private Instance Methods ***/
		_classPrototype._addChildButton = _superclass.Button.addChildButton;

		_classPrototype._showPalette = function (_mustShow) {
			var _this = this;
			_this.displayNode ('palette',_mustShow);
			if (_mustShow)
				_this.setNodeStyle ('palette',{filter:''})
			;
			_this.fireEvent ({name:'Palette ' + (_mustShow ? 'Shown' : 'Dismissed'), bubble:true});
		};

		_classPrototype._togglePalette = function (_domEvent) {
			var
				_this = this,
				_selector = _this.widgets.map.selector,
				_selected = !_selector.get ('selected')
			;
			_selector.set ({selected:_selected});
			if (_selected) {
				_this.fireEvent ('Before Palette Shown');
				if (_this._exclusive) _hideAllExclusiveExcept (_this);
				if (_this._positioning == 'absolute' && _domEvent) {
					var
						_docBody = document.documentElement ? document.documentElement : document.body,
						_clientX = _domEvent.clientX,
						_clientY = _domEvent.clientY,
						_scrollLeft = typeof window.pageXOffset == 'number' ? window.pageXOffset : _docBody.scrollLeft,
						_scrollTop = typeof window.pageYOffset == 'number' ? window.pageYOffset : _docBody.scrollTop,
						_paletteDims = Uize.Node.getDimensions (_this.getNode ('palette')),
						_right = _scrollLeft + _clientX + _paletteDims.width * (1 - _this._alignX) + _this._offsetX,
						_bottom = _scrollTop + _clientY + _paletteDims.height * (1 - _this._alignY) + _this._offsetY
					;
					if (_right > _scrollLeft + _docBody.offsetWidth) _right = _clientX;
					if (_bottom > _scrollTop + _docBody.offsetHeight) _bottom = _clientY;
					_this.setNodeStyle (
						'palette',
						{
							left:Math.max (_right - _paletteDims.width,_scrollLeft) + 'px',
							top:Math.max (_bottom - _paletteDims.height,_scrollTop) + 'px'
						}
					);
				}
			}
			/*** start opacity fade ***/
				if (_this.fade.get ('duration') > 0) {
					if (_selected) _this.displayNode ('palette');
					_this.fade.set ({
						startValue:_selected ? 0 : 1,
						endValue:_selected ? 1 : 0
					});
					_this.fade.start ();
				} else {
					_this._showPalette (_selected);
				}
		};

	/*** Public Instance Methods ***/
		_classPrototype.kill = function () {
			delete _instances [this.objectName];
			_superclass.prototype.kill.call (this);
		};

		_classPrototype.togglePalette = _classPrototype._togglePalette;
			/*?
				Instance Methods
					togglePalette
						Toggles the popup palette's shown/hidden state.

						SYNTAX
						................................
						myPopupPalette.togglePalette ();
						................................

						NOTES
						- this method has no return value
			*/

		_classPrototype.wireUi = function () {
			var _this = this;
			if (!_this.wired ()) {
				/*** capture mousedown event for palette ***/
					_this.wireNodeEvent ('palette','onmousedown',_setMouseDownOnPaletteTrue);

				/*** wire up palette close button ***/
					_this.wireNodeEvent ('paletteClose','onclick',function () {_this._togglePalette ()});

				/*** move palette to child of root, if positioning is absolute ***/
					if (_this._positioning == 'absolute') {
						/* IMPORTANT: There is a problem in Firefox where moving palettes to the root of the DOM like this adds entries to the browser's history for palettes that contain iframes - go figure! */
						var
							_docBody = document.body,
							_paletteWidthBeforeInsertAtRoot = Uize.Node.getDimensions (_this.getNode ('palette')).width
						;
						_docBody.insertBefore (_this.getNode ('palette'),_docBody.childNodes [0]);
						_this.setNodeStyle (
							'palette',
							{
								zIndex:'10000',
								position:'absolute',
								left:'',
								top:'',
								right:'',
								bottom:'',
								width:_paletteWidthBeforeInsertAtRoot + 'px'
							}
						);
					}

				_superclass.prototype.wireUi.call (_this);
			}
		};

	/*** Setup Properties ***/
		_class.registerProperties ({
			_alignX:{
				name:'alignX',
				value:0
			},
			_alignY:{
				name:'alignY',
				value:0
			},
			_exclusive:{
				name:'exclusive',
				value:true
			},
			_offsetX:{
				name:'offsetX',
				value:0
			},
			_offsetY:{
				name:'offsetY',
				value:0
			},
			_positioning:{
				name:'positioning',
				value:'none'
			},
			_showWhenOver:{
				name:'showWhenOver',
				value:false
			}
		});

	/*** Code for Managing Exclusive Display ***/
		function _hideAllExclusiveExcept (_instanceToPermitShown) {
			for (var _instanceName in _instances) {
				var _instance = _instances [_instanceName];
				if (
					_instance != _instanceToPermitShown &&
					_instance.wired () &&
					_instance._exclusive &&
					_instance.widgets.map.selector.get ('selected')
				)
					_instance._togglePalette ()
				;
			}
		}

		function _setMouseDownOnPaletteTrue () {_mouseDownOnPalette = true}

		var
			_mouseDownOnPalette = false,
			_oldOnMouseDown = document.onmousedown
		;
		document.onmousedown = function (_event) {
			if (!_event) _event = event;
			if (_mouseDownOnPalette) {
				_mouseDownOnPalette = false;
			} else {
				_hideAllExclusiveExcept ();
			}
			if (typeof _oldOnMouseDown == 'function') _oldOnMouseDown (_event);
		}
}) ();

