/**
 * Copyright (c) 2006-2015, JGraph Holdings Ltd
 * Copyright (c) 2006-2015, draw.io AG
 */
/**
 * Class: mxToolbar
 * 
 * Creates a toolbar inside a given DOM node. The toolbar may contain icons,
 * buttons and combo boxes.
 * 
 * Event: mxEvent.SELECT
 * 
 * Fires when an item was selected in the toolbar. The <code>function</code>
 * property contains the function that was selected in <selectMode>.
 * 
 * Constructor: mxToolbar
 * 
 * Constructs a toolbar in the specified container.
 *
 * Parameters:
 *
 * container - DOM node that contains the toolbar.
 */
function mxToolbar(container)
{
	this.container = container;
};

/**
 * Extends mxEventSource.
 */
mxToolbar.prototype = new mxEventSource();
mxToolbar.prototype.constructor = mxToolbar;

/**
 * Variable: container
 * 
 * Reference to the DOM nodes that contains the toolbar.
 */
mxToolbar.prototype.container = null;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxToolbar.prototype.enabled = true;

/**
 * Variable: noReset
 * 
 * Specifies if <resetMode> requires a forced flag of true for resetting
 * the current mode in the toolbar. Default is false. This is set to true
 * if the toolbar item is double clicked to avoid a reset after a single
 * use of the item.
 */
mxToolbar.prototype.noReset = false;

/**
 * Variable: updateDefaultMode
 * 
 * Boolean indicating if the default mode should be the last selected
 * switch mode or the first inserted switch mode. Default is true, that
 * is the last selected switch mode is the default mode. The default mode
 * is the mode to be selected after a reset of the toolbar. If this is
 * false, then the default mode is the first inserted mode item regardless
 * of what was last selected. Otherwise, the selected item after a reset is
 * the previously selected item.
 */
mxToolbar.prototype.updateDefaultMode = true;

/**
 * Function: addItem
 * 
 * Adds the given function as an image with the specified title and icon
 * and returns the new image node.
 * 
 * Parameters:
 * 
 * title - Optional string that is used as the tooltip.
 * icon - Optional URL of the image to be used. If no URL is given, then a
 * button is created.
 * funct - Function to execute on a mouse click.
 * pressedIcon - Optional URL of the pressed image. Default is a gray
 * background.
 * style - Optional style classname. Default is mxToolbarItem.
 * factoryMethod - Optional factory method for popup menu, eg.
 * function(menu, evt, cell) { menu.addItem('Hello, World!'); }
 */
mxToolbar.prototype.addItem = function(title, icon, funct, pressedIcon, style, factoryMethod)
{
	var img = document.createElement((icon != null) ? 'img' : 'button');
	var initialClassName = style || ((factoryMethod != null) ?
			'mxToolbarMode' : 'mxToolbarItem');
	img.className = initialClassName;
	img.setAttribute('src', icon);
	
	if (title != null)
	{
		if (icon != null)
		{
			img.setAttribute('title', title);
		}
		else
		{
			mxUtils.write(img, title);
		}
	}
	
	this.container.appendChild(img);

	// Invokes the function on a click on the toolbar item
	if (funct != null)
	{
		mxEvent.addListener(img, 'click', funct);
		
		if (mxClient.IS_TOUCH)
		{
			mxEvent.addListener(img, 'touchend', funct);
		}
	}

	var mouseHandler = mxUtils.bind(this, function(evt)
	{
		if (pressedIcon != null)
		{
			img.setAttribute('src', icon);
		}
		else
		{
			img.style.backgroundColor = '';
		}
	});

	// Highlights the toolbar item with a gray background
	// while it is being clicked with the mouse
	mxEvent.addGestureListeners(img, mxUtils.bind(this, function(evt)
	{
		if (pressedIcon != null)
		{
			img.setAttribute('src', pressedIcon);
		}
		else
		{
			img.style.backgroundColor = 'gray';
		}
		
		// Popup Menu
		if (factoryMethod != null)
		{
			if (this.menu == null)
			{
				this.menu = new mxPopupMenu();
				this.menu.init();
			}
			
			var last = this.currentImg;
			
			if (this.menu.isMenuShowing())
			{
				this.menu.hideMenu();
			}
			
			if (last != img)
			{
				// Redirects factory method to local factory method
				this.currentImg = img;
				this.menu.factoryMethod = factoryMethod;
				
				var point = new mxPoint(
					img.offsetLeft,
					img.offsetTop + img.offsetHeight);
				this.menu.popup(point.x, point.y, null, evt);

				// Sets and overrides to restore classname
				if (this.menu.isMenuShowing())
				{
					img.className = initialClassName + 'Selected';
					
					this.menu.hideMenu = function()
					{
						mxPopupMenu.prototype.hideMenu.apply(this);
						img.className = initialClassName;
						this.currentImg = null;
					};
				}
			}
		}
	}), null, mouseHandler);

	mxEvent.addListener(img, 'mouseout', mouseHandler);
	
	return img;
};

/**
 * Function: addCombo
 * 
 * Adds and returns a new SELECT element using the given style. The element
 * is placed inside a DIV with the mxToolbarComboContainer style classname.
 * 
 * Parameters:
 * 
 * style - Optional style classname. Default is mxToolbarCombo.
 */
mxToolbar.prototype.addCombo = function(style)
{
	var div = document.createElement('div');
	div.style.display = 'inline';
	div.className = 'mxToolbarComboContainer';
	
	var select = document.createElement('select');
	select.className = style || 'mxToolbarCombo';
	div.appendChild(select);
	
	this.container.appendChild(div);
	
	return select;
};

/**
 * Function: addActionCombo
 * 
 * Adds and returns a new SELECT element using the given title as the
 * default element. The selection is reset to this element after each
 * change.
 * 
 * Parameters:
 * 
 * title - String that specifies the title of the default element.
 * style - Optional style classname. Default is mxToolbarCombo.
 */
mxToolbar.prototype.addActionCombo = function(title, style)
{
	var select = document.createElement('select');
	select.className = style || 'mxToolbarCombo';
	this.addOption(select, title, null);
	
	mxEvent.addListener(select, 'change', function(evt)
	{
		var value = select.options[select.selectedIndex];
		select.selectedIndex = 0;
		
		if (value.funct != null)
		{
			value.funct(evt);
		}
	});
	
	this.container.appendChild(select);
	
	return select;
};

/**
 * Function: addOption
 * 
 * Adds and returns a new OPTION element inside the given SELECT element.
 * If the given value is a function then it is stored in the option's funct
 * field.
 * 
 * Parameters:
 * 
 * combo - SELECT element that will contain the new entry.
 * title - String that specifies the title of the option.
 * value - Specifies the value associated with this option.
 */
mxToolbar.prototype.addOption = function(combo, title, value)
{
	var option = document.createElement('option');
	mxUtils.writeln(option, title);
	
	if (typeof(value) == 'function')
	{
		option.funct = value;
	}
	else
	{
		option.setAttribute('value', value);
	}
	
	combo.appendChild(option);
	
	return option;
};

/**
 * Function: addSwitchMode
 * 
 * Adds a new selectable item to the toolbar. Only one switch mode item may
 * be selected at a time. The currently selected item is the default item
 * after a reset of the toolbar.
 */
mxToolbar.prototype.addSwitchMode = function(title, icon, funct, pressedIcon, style)
{
	var img = document.createElement('img');
	img.initialClassName = style || 'mxToolbarMode';
	img.className = img.initialClassName;
	img.setAttribute('src', icon);
	img.altIcon = pressedIcon;
	
	if (title != null)
	{
		img.setAttribute('title', title);
	}
	
	mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
	{
		var tmp = this.selectedMode.altIcon;
		
		if (tmp != null)
		{
			this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
			this.selectedMode.setAttribute('src', tmp);
		}
		else
		{
			this.selectedMode.className = this.selectedMode.initialClassName;
		}
		
		if (this.updateDefaultMode)
		{
			this.defaultMode = img;
		}
		
		this.selectedMode = img;
		
		var tmp = img.altIcon;
		
		if (tmp != null)
		{
			img.altIcon = img.getAttribute('src');
			img.setAttribute('src', tmp);
		}
		else
		{
			img.className = img.initialClassName+'Selected';
		}
		
		this.fireEvent(new mxEventObject(mxEvent.SELECT));
		funct();
	}));
	
	this.container.appendChild(img);
	
	if (this.defaultMode == null)
	{
		this.defaultMode = img;
		
		// Function should fire only once so
		// do not pass it with the select event
		this.selectMode(img);
		funct();
	}
	
	return img;
};

/**
 * Function: addMode
 * 
 * Adds a new item to the toolbar. The selection is typically reset after
 * the item has been consumed, for example by adding a new vertex to the
 * graph. The reset is not carried out if the item is double clicked.
 * 
 * The function argument uses the following signature: funct(evt, cell) where
 * evt is the native mouse event and cell is the cell under the mouse.
 */
mxToolbar.prototype.addMode = function(title, icon, funct, pressedIcon, style, toggle)
{
	toggle = (toggle != null) ? toggle : true;
	var img = document.createElement((icon != null) ? 'img' : 'button');
	
	img.initialClassName = style || 'mxToolbarMode';
	img.className = img.initialClassName;
	img.setAttribute('src', icon);
	img.altIcon = pressedIcon;

	if (title != null)
	{
		img.setAttribute('title', title);
	}
	
	if (this.enabled && toggle)
	{
		mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
		{
			this.selectMode(img, funct);
			this.noReset = false;
		}));
		
		mxEvent.addListener(img, 'dblclick', mxUtils.bind(this, function(evt)
		{
			this.selectMode(img, funct);
			this.noReset = true;
		}));
		
		if (this.defaultMode == null)
		{
			this.defaultMode = img;
			this.defaultFunction = funct;
			this.selectMode(img, funct);
		}
	}

	this.container.appendChild(img);					

	return img;
};

/**
 * Function: selectMode
 * 
 * Resets the state of the previously selected mode and displays the given
 * DOM node as selected. This function fires a select event with the given
 * function as a parameter.
 */
mxToolbar.prototype.selectMode = function(domNode, funct)
{
	if (this.selectedMode != domNode)
	{
		if (this.selectedMode != null)
		{
			var tmp = this.selectedMode.altIcon;
			
			if (tmp != null)
			{
				this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
				this.selectedMode.setAttribute('src', tmp);
			}
			else
			{
				this.selectedMode.className = this.selectedMode.initialClassName;
			}
		}
		
		this.selectedMode = domNode;
		var tmp = this.selectedMode.altIcon;
		
		if (tmp != null)
		{
			this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
			this.selectedMode.setAttribute('src', tmp);
		}
		else
		{
			this.selectedMode.className = this.selectedMode.initialClassName+'Selected';
		}
		
		this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct));
	}
};

/**
 * Function: resetMode
 * 
 * Selects the default mode and resets the state of the previously selected
 * mode.
 */
mxToolbar.prototype.resetMode = function(forced)
{
	if ((forced || !this.noReset) && this.selectedMode != this.defaultMode)
	{
		// The last selected switch mode will be activated
		// so the function was already executed and is
		// no longer required here
		this.selectMode(this.defaultMode, this.defaultFunction);
	}
};

/**
 * Function: addSeparator
 * 
 * Adds the specifies image as a separator.
 * 
 * Parameters:
 * 
 * icon - URL of the separator icon.
 */
mxToolbar.prototype.addSeparator = function(icon)
{
	return this.addItem(null, icon, null);
};

/**
 * Function: addBreak
 * 
 * Adds a break to the container.
 */
mxToolbar.prototype.addBreak = function()
{
	mxUtils.br(this.container);
};

/**
 * Function: addLine
 * 
 * Adds a horizontal line to the container.
 */
mxToolbar.prototype.addLine = function()
{
	var hr = document.createElement('hr');
	
	hr.style.marginRight = '6px';
	hr.setAttribute('size', '1');
	
	this.container.appendChild(hr);
};

/**
 * Function: destroy
 * 
 * Removes the toolbar and all its associated resources.
 */
mxToolbar.prototype.destroy = function ()
{
	mxEvent.release(this.container);
	this.container = null;
	this.defaultMode = null;
	this.defaultFunction = null;
	this.selectedMode = null;
	
	if (this.menu != null)
	{
		this.menu.destroy();
	}
};
