/*****************************************************************************
 *
 * File     : AbstractButton.js   
 * 
 * Project  : WMS Viewer Client
 * 
 * Contents : This class implements a basic toolbar button behaviour. 
 *            The following are the guidelines for the creation and use:
 *            
 *            1. It is constructed with the html element and the container toolbar
 *               as parameters
 *            2. The html element must be the anchor (<a>) element
 *            3. It has to have an id ending with word "Button" (e.g. "selectButton")
 *            4. It can have the type attribute taking one of three values:
 *               plain, instantToggle, delayedToggle. If ommited, default is "plain"
 *            5. It should have the class attribute initially set to either "button"
 *               or "buttonPressed" (for one of the toggle buttons in a group)
 *            6. href attribute set to nothing: href="javascript:"
 *            7. onclick attribute set to user-defined function.
 *            8. A single <img> child element
 *            9. <img> must have the class attribute set to "buttonImage"
 *            10. The name of the image in the src attribute must...
 *            11. It can have other children, e.g. <span> for the button label.
 *
 * Some examples of buttons:
 * 
 * <a id="capabilitiesButton" class="button" href="javascript:" onclick="getCapabilities()">
 *   <img class="buttonImage" alt="GetCapabilities (HTTP GET)" src="images/capabilitiesActive.gif"/>
 *   <span class="buttonText">GetCapabilities</span>
 * </a>
 * 
 * <a id="selectButton" class="buttonPressed" type="instantToggle" href="javascript:" onclick="activateSelect(this)"><img id="selectButtonImage" class="buttonImage" alt="Select" src="images/selectActive.gif"/></a>
 * 
 * Note on the event handling implementation:
 * 
 * If you set as the event handler an instance method, like so:
 * 
 * htmlElement.attachEvent("onmousedown", this.handleMouseDown);
 * 
 * the handler (handleMouseDown) will be executed in global space and within the method,
 * "this" will refer to the top document, not to the particular instance. 
 * To avoid this, we had to use the adapter methods and the targetObject attribute. 
 * It's a bit convoluted in how it works, but in any case this was the cleanest approach found. 
 * There are some others, but this one preserves the encapsulation.
 * 
 * 
 * 
 * Author: Milan Trninic
 *
 * Copyright 1999-2005 Galdos Systems, Inc.
 * All rights reserved.
 * 
 ***|***************************|***********************|*******************|*/

/************************************************************************
*
*	Global declarations
*
*	
*
*************************************************************************/

/************************************************************************
*
*	function:	AbstractButton
*
*	purpose:	Constructor
*
*************************************************************************/
function AbstractButton(uiElement, toolbar)
{
	// method assignments
	this.init = AbstractButton.init;
	this.isEnabled = AbstractButton.isEnabled;
	this.setEnabled = AbstractButton.setEnabled;
	this.isSelected = AbstractButton.isSelected;
	this.setSelected = AbstractButton.setSelected;
	this.setClassName = AbstractButton.setClassName;
	this.getImage = AbstractButton.getImage;
	this.setImagePath = AbstractButton.setImagePath;
	this.setSelectedImagePath = AbstractButton.setSelectedImagePath;
	this.setDisabledImagePath = AbstractButton.setDisabledImagePath;
	this.getId = AbstractButton.getId;
	this.createEventFilter = AbstractButton.createEventFilter;
	
	this.setNormalClassName = AbstractButton.setNormalClassName;
	this.setDisabledClassName = AbstractButton.setDisabledClassName;
	this.setSelectedClassName = AbstractButton.setSelectedClassName;
	this.setSelectedDisabledClassName = AbstractButton.setSelectedDisabledClassName;
	this.setInflatedClassName = AbstractButton.setInflatedClassName;
	this.setEngagedClassName = AbstractButton.setEngagedClassName;
	this.setOnHoldClassName = AbstractButton.setOnHoldClassName;

	this.attachEvent = AbstractButton.attachEvent;
	this.detachEvent = AbstractButton.detachEvent;
	this.onNormal = AbstractButton.onNormal;
	this.onInflated = AbstractButton.onInflated;
	this.onEngaged = AbstractButton.onEngaged;
	this.onOnHold = AbstractButton.onOnHold;
	this.onClicked = AbstractButton.onClicked;
	this.setVisible = AbstractButton.setVisible;
	this.isVisible = AbstractButton.isVisible;

	// instance field declarations
	this._uiElement;
	this._eventFilter;
	this._image;
	this._label;
	this._toolbar;
	this._enabled;
	this._selected;
	this._id;
	this._defaultImagePath;
	this._selectedImagePath;
	this._disabledImagePath;

	this._normalClassName;
	this._disabledClassName;
	this._selectedClassName;
	this._selectedDisabledClassName;
	this._inflatedClassName;
	this._engagedClassName;
	this._onHoldClassName;

	// initialization
	this.init(uiElement, toolbar);
}

/************************************************************************
*
*	function:	init
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.init(uiElement, toolbar)
{
	this._uiElement = uiElement;
	this._uiElement.className = "buttonShell";
	
	var imageUI = selectNodes(uiElement, "img").get(0);
	this._image = new Image(imageUI);
	this._image.setClassName("buttonImage");
	
	var labelUI = selectNodes(uiElement, "span").get(0);
	if (labelUI != null)
	{
		this._label = new Label(labelUI);
		this._label.setClassName("buttonText");
	}
	
	this._eventFilter = this.createEventFilter(uiElement);
	
	this._toolbar = toolbar;
	this._enabled = true;
	this._selected = false;

	this._defaultImagePath = imageUI.getAttribute("src");
	this._id = uiElement.getAttribute("id");
	
	this._normalClassName = "button";
	this._disabledClassName = "buttonDisabled";
	this._selectedClassName = "buttonSelected";
	this._selectedDisabledClassName = "buttonSelectedDisabled";
	this._inflatedClassName = "buttonInflated";
	this._engagedClassName = "buttonEngaged";
	this._onHoldClassName = "buttonOnHold";
}

/************************************************************************
*
*	function:	createEventFilter
*
*	purpose:	We insert a <head> element to function as a glass panel or an
*           inner event listener to catch events before they are dispatched
* 					to user handlers.
* 					Main reason is becuase the "disabled" property is buggy and for
* 					example does not disable firing of events on <a> elements.
* 					User can add event handlers on <a> element either via HTML 
* 					"onXXX" attributes or programmatically (attachEvent), but this
* 					filter will still catch it first and then we can cancel bubbling
* 					if e.g. a button is disabled
* 					The reason we use the <head> element is becuase it doesn't 
* 					affect the layout. It's a rare characteristic - e.g. the <div>
* 					element was a natural choice, but you cannot line up several
* 					<div> elements in one line. This was the reason <a> element
* 					was used for a button as well.
* 					Oddly - the <head> element will catch mouse events even though
* 					the documentation says the opposite.
*
*************************************************************************/
function AbstractButton.createEventFilter(uiElement)
{
	var eventFilterUI = document.createElement("head");
	var size = uiElement.childNodes.length;
	for (var index = 0; index < size; index++)
	{
		var child = uiElement.childNodes.item(0);
		uiElement.removeChild(child);
		eventFilterUI.appendChild(child);
	}
	uiElement.appendChild(eventFilterUI);
	
	var eventFilter = new ButtonEventFilter(eventFilterUI, this);
	return eventFilter;
}

/************************************************************************
*
*	function:	attachEvent
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.attachEvent(eventName, handler)
{
	this._uiElement.attachEvent(eventName, handler);
}

/************************************************************************
*
*	function:	detachEvent
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.detachEvent(eventName, handler)
{
	this._uiElement.detachEvent(eventName, handler);
}

/************************************************************************
*
*	function:	getId
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.getId()
{
	return this._id;
}

/************************************************************************
*
*	function:	isEnabled
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.isEnabled()
{
	return this._enabled;
}

/************************************************************************
*
*	function:	setEnabled
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setEnabled(enable)
{
	if (this._enabled == enable) return;
	
	this._enabled = enable;
	this._eventFilter.setEnabled(enable);
	this._image.setEnabled(enable);
	if (this._label != null) this._label.setEnabled(enable);

	var imagePath;
	var className;
	
	if (this._enabled) 
	{
		imagePath = this._defaultImagePath;
		if (this._selected && this._selectedImagePath) imagePath = this._selectedImagePath;
		if (this._selected) className = this._selectedClassName;
		else className = this._normalClassName;
	}
	else
	{
		if (this._disabledImagePath != null) imagePath = this._disabledImagePath;
		else imagePath = this._defaultImagePath;
		if (this._selected) className = this._selectedDisabledClassName;
		else className = this._disabledClassName;
	}
	
	this._eventFilter.setClassName(className);
	this._image.setPath(imagePath);

}

/************************************************************************
*
*	function:	setClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setClassName(className)
{
	this._eventFilter.setClassName(className);
}

/************************************************************************
*
*	function:	isSelected
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.isSelected()
{
	return this._selected;
}

/************************************************************************
*
*	function:	setSelected
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setSelected(selected)
{
	if (this._selected == selected) return;
	if (this._enabled == false) return;
	this._selected = selected;

	var imagePath = this._defaultImagePath;
	if (this._selected && this._selectedImagePath) imagePath = this._selectedImagePath;

	var className;
	if (this._selected) className = this._selectedClassName;
	else className = this._normalClassName;

	this._eventFilter.setClassName(className);
	this._image.setPath(imagePath);
}

/************************************************************************
*
*	function:	onNormal
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.onNormal()
{
	this.setClassName(this._normalClassName);
}

/************************************************************************
*
*	function:	onInflated
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.onInflated()
{
	this.setClassName(this._inflatedClassName);
}

/************************************************************************
*
*	function:	onEngaged
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.onEngaged()
{
	this.setClassName(this._engagedClassName);
}

/************************************************************************
*
*	function:	onOnHold
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.onOnHold()
{
	this.setClassName(this._onHoldClassName);
}

/************************************************************************
*
*	function:	onClicked
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.onClicked()
{
}

/************************************************************************
*
*	function:	getImage
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.getImage()
{
	return this._image;
}

/************************************************************************
*
*	function:	setImagePath
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setImagePath(imagePath)
{
	this._defaultImagePath = imagePath;
}

/************************************************************************
*
*	function:	setSelectedImagePath
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setSelectedImagePath(imagePath)
{
	this._selectedImagePath = imagePath;
}

/************************************************************************
*
*	function:	setDisabledImagePath
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setDisabledImagePath(imagePath)
{
	this._disabledImagePath = imagePath;
}

/************************************************************************
*
*	function:	setNormalClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setNormalClassName(className)
{
	this._normalClassName = className;
}

/************************************************************************
*
*	function:	setDisabledClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setDisabledClassName(className)
{
	this._disabledClassName = className;
}

/************************************************************************
*
*	function:	setSelectedClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setSelectedClassName(className)
{
	this._selectedClassName = className;
}

/************************************************************************
*
*	function:	setSelectedDisabledClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setSelectedDisabledClassName(className)
{
	this._selectedDisabledClassName = className;
}

/************************************************************************
*
*	function:	setInflatedClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setInflatedClassName(className)
{
	this._inflatedClassName = className;
}

/************************************************************************
*
*	function:	setEngagedClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setEngagedClassName(className)
{
	this._engagedClassName = className;
}

/************************************************************************
*
*	function:	setOnHoldClassName
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setOnHoldClassName(className)
{
	this._onHoldClassName = className;
}

/************************************************************************
*
*	function:	setVisible
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.setVisible(visible)
{
	if (visible) this._uiElement.style.display = "";
	else this._uiElement.style.display = "none";
}

/************************************************************************
*
*	function:	isVisible
*
*	purpose:	
*
*************************************************************************/
function AbstractButton.isVisible()
{
	return (this._uiElement.style.display != "none");
}


