/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of "Scrivo" nor the names of its contributors may be
 *    used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: ToolbarButton.js 616 2013-04-22 23:48:38Z geert $
 */

"use strict";

SUI.ToolbarButton = SUI.defineClass(
	/** @lends SUI.ToolbarButton.prototype */{

	/** @ignore */ baseClass: SUI.Box,

	/**
	 * @class
	 * A SUI.ToolbarButton is an icon-button component. Although designed for
	 * use on a toolbar it can be used stand-alone as well. By default it is
	 * a clickable button but you can set it 'pressed' state, and thereby
	 * making it behave like a push-button. The button data (title, icon,
	 * action, etc) can be set directly, but can by supplied through an action
	 * list as well.
	 *
	 * @augments SUI.Box
	 *
	 * @description
	 * Create a toolbar button.
	 *
	 * @constructs
	 * @param see base class
	 * @param {String} arg.actionId Action id if an action in a action list
	 * @param {Function} arg.handler Reference to a function to execute when
	 *     the button is pressed
	 * @param {String} arg.title Mouse over title of the button
	 * @param {String} arg.icon Location of the icon
	 * @param {boolean} arg.disabled The enabled state of the button (true
	 *     to disable)
	 */
	initializer: function(arg) {

		// set the default size for the button
		if (!arg.width) {
			arg.width = this.BUTTON_SIZE;
		}
		if (!arg.height) {
			arg.height = this.BUTTON_SIZE;
		}

		SUI.ToolbarButton.initializeBase(this, arg);

		// set values from arguments
		this._actionId = arg.actionId || null;
		this._handler = arg.handler || null;
		this._title = arg.title || null;
		this._icon = arg.icon || null;

		// set the button's border and padding
		this.border(new SUI.Border(this.BORDER_WIDTH));
		this.padding(new SUI.Padding(
		 (this.clientWidth() - this.ICON_SIZE) / 2 | 0));

		// create the icon and add it to the button
		var img = document.createElement("IMG");
		if (this._icon) {
			img.src = SUI.imgDir + "/" + this._icon;
		}
		this.el().appendChild(img);

		// set the button's title, CSS class and enabled state
		this.el().title = this._title || "";
		this.addClass("sui-tb-button");
		this.enable(arg.disabled ? false : true);

		// add the event listeners
		this._addEventListeners();
	},

	/**
	 * The width and height of the button.
	 */
	BUTTON_SIZE: 26,

	/**
	 * The size (width, height) of the button's icon.
	 */
	ICON_SIZE: 16,

	/**
	 * Border width of the button.
	 */
	BORDER_WIDTH: 1,

	/**
	 * Get the enabled state of the button.
	 * @return {boolean} a The button's enabled state.
	 */
	enabled: function(a) {
		return this._enabled;
	},

	/**
	 * set the enabled state of the button.
	 * @param {boolean} a The button's enabled state.
	 */
	enable: function(a) {
		this._enabled = a;
		if (this._enabled) {
			this.removeClass("sui-tb-button-disabled");
		} else {
			this.addClass("sui-tb-button-disabled");
		}
	},

	/**
	 * Get data from the button so that it can be used to create a menu item
	 * in a PopupMenu
	 * @return {Object} An object with button data.
	 */
	menuItemData: function() {
		return {
			icon: this._icon,
			title: this._title,
			actionId: this._actionId,
			handler: this._handler,
			disabled: !this._enabled
		};
	},

	/**
	 * Show the button in pressed or un-pressed state.
	 * @param {boolean} pr The button's pressed state.
	 */
	select: function(pr) {
	 // set the pressed state ...
		this._selected = pr;
		// ... and show the pressed state
		if (!this._selected) {
		 this._showUnpressed();
		} else {
		 this._showPressed();
		}
	},

	/**
	 * Set button parameters from an action list item if the button's actionId
	 * is an entry in the list.
	 * @param {SUI.ActionList} actionList An action list containing an action
	 *   entry that corresponds with this button's actionId
	 */
	setAction: function(actionList) {
	 // get the action from the list
	 var a = actionList.get(this._actionId);
		// if found ...
	 if (a) {
			// ... set the title from action list data if not title was set ...
			if (!this._title) {
			 this._title = a.title;
				this.el().title = this._title || "";
			}
			// ... set the icon from action list data if no icon was set ...
			if (!this._icon) {
			 this._icon = SUI.imgDir + "/" + a.icon;
				this.el().firstChild.src = this._icon;
			}
			// ... set the enabled state and action handler ...
			this.enable(a.enabled);
			this._handler = a.handler;
			// ... add the button to the list's listener array
			actionList.get(this._actionId).listeners.push(this);
		}
	},

	// the action id of an action list
	_actionId: null,

	// the button's action handler
	_handler: null,

	// the button's icon
	_icon: null,

	// pressed: used to keep the button in pressed state
	_selected: false,

	// the button's title (mouseover)
	_title: null,

	/* Set the event handlers of the button.
	 * On the row-div set:
	 *   onclick => _selectNode
	 *   onmouseover => _addHighlight
	 *   onmouseout => _removeHighlight
	 *   onmousedown => _showPressed
	 *   onmouseup => _showUnpressed
	 */
	_addEventListeners: function() {

		var that = this;

		// do _addHighlight on the mouseover event of a node-row.
		SUI.browser.addEventListener(this.el(), "mouseover",
			function(e) {
				if (!that._addHighlight()) {
					SUI.browser.noPropagation(e);
				}
			}
		);

		// do _removeHighlight on the mouseout event of a node-row.
		SUI.browser.addEventListener(this.el(), "mouseout",
			function(e) {
				if (!that._removeHighlight()) {
					SUI.browser.noPropagation(e);
				}
			}
		);

		// do _showPressed on the mousedown event of a node-row.
		SUI.browser.addEventListener(this.el(), "mousedown",
			function(e) {
			 if (!that._showPressed()) {
					SUI.browser.noPropagation(e);
				}
			}
		);

		// do _showUnpressed on the mouseup event of a node-row.
		SUI.browser.addEventListener(this.el(), "mouseup",
			function(e) {
		   if (!that._showUnpressed()) {
					SUI.browser.noPropagation(e);
				}
			}
		);

		// do _execute on the click event of a node-row.
		SUI.browser.addEventListener(this.el(), "click",
			function(e) {
				if (!that._execute()) {
					SUI.browser.noPropagation(e);
				}
			}
		);

	},

	/* Add the CCS class for highlighting to the button.
	 */
	_addHighlight: function() {
		this.addClass("sui-tb-button-highlight");
	},

	/* Execute the buttons action handler.
	 */
	_execute: function() {
	 // check the button's enabled state
		if (this._enabled) {
		 // 'unpress' the button
			this._selected = false;
			// execute the hander
			if (this._handler) {
			 this._handler();
			}
		}
	},

	/* Remove the CCS class for highlighting from the button.
	 */
	_removeHighlight: function(e) {
	 this.removeClass("sui-tb-button-highlight");
	 this._showUnpressed();
	},

	/* Show the button in pressed state
	 */
	_showPressed: function(e) {
	 this.addClass("sui-tb-button-pressed");
	},

	/* Show the button in normal un-pressed state if (unless its pressed state
	 * is on)
	 */
	_showUnpressed: function(e) {
		if (!this._selected) {
		 this.removeClass("sui-tb-button-pressed");
		}
	}

});