define("dijit/a11yclick", [
	"dojo/on",
	"dojo/_base/array", // array.forEach
	"dojo/keys", // keys.ENTER keys.SPACE
	"dojo/_base/declare", // declare
	"dojo/has", // has("dom-addeventlistener")
	"dojo/_base/unload", // unload.addOnWindowUnload
	"dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent
], function(on, array, keys, declare, has, unload, win){

	// module:
	//		dijit/a11yclick

	// Keep track of where the last keydown event was, to help avoid generating
	// spurious ondijitclick events when:
	// 1. focus is on a <button> or <a>
	// 2. user presses then releases the ENTER key
	// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
	// 4. onkeyup event fires, causing the ondijitclick handler to fire
	var lastKeyDownNode = null;
	if(has("dom-addeventlistener")){
		win.doc.addEventListener('keydown', function(evt){
			lastKeyDownNode = evt.target;
		}, true);
	}else{
		// Fallback path for IE6-8
		(function(){
			var keydownCallback = function(evt){
				lastKeyDownNode = evt.srcElement;
			};
			win.doc.attachEvent('onkeydown', keydownCallback);
			unload.addOnWindowUnload(function(){
				win.doc.detachEvent('onkeydown', keydownCallback);
			});
		})();
	}

	function clickKey(/*Event*/ e){
		return (e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) &&
			!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey;
	}

	return function(node, listener){
		// summary:
		//		Custom a11yclick (a.k.a. ondijitclick) event
		//		which triggers on a mouse click, touch, or space/enter keyup.

		if(/input|button/i.test(node.nodeName)){
			// pass through, the browser already generates click event on SPACE/ENTER key
			return on(node, "click", listener);
		}else{
			// Don't fire the click event unless both the keydown and keyup occur on this node.
			// Avoids problems where focus shifted to this node or away from the node on keydown,
			// either causing this node to process a stray keyup event, or causing another node
			// to get a stray keyup event.

			var handles = [
				on(node, "keydown", function(e){
					//0 && console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
					if(clickKey(e)){
						// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
						lastKeyDownNode = e.target;

						// Prevent viewport scrolling on space key in IE<9.
						// (Reproducible on test_Button.html on any of the first dijit/form/Button examples)
						e.preventDefault();
					}
				}),

				on(node, "keyup", function(e){
					//0 && console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
					if(clickKey(e) && e.target == lastKeyDownNode){	// === breaks greasemonkey
						//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
						lastKeyDownNode = null;
						on.emit(e.target, "click", {
							cancelable: true,
							bubbles: true
						});
					}
				}),

				on(node, "click", function(e){
					// catch mouse clicks, plus the on.emit() calls from above and below
					listener.call(this, e);
				})
			];

			if(has("touch")){
				// touchstart-->touchend will automatically generate a click event, but there are problems
				// on iOS after focus has been programatically shifted (#14604, #14918), so setup a failsafe
				// if click doesn't fire naturally.

				var clickTimer;
				handles.push(
					on(node, "touchend", function(e){
						var target = e.target;
						clickTimer = setTimeout(function(){
							clickTimer = null;
							on.emit(target, "click", {
								cancelable: true,
								bubbles: true
							});
						}, 600);
					}),
					on(node, "click", function(e){
						// If browser generates a click naturally, clear the timer to fire a synthetic click event
						if(clickTimer){
							clearTimeout(clickTimer);
						}
					})
					// TODO: if the touchstart and touchend were <100ms apart, and then there's another touchstart
					// event <300ms after the touchend event, then clear the synthetic click timer, because user
					// is doing a zoom.   Alternately monitor screen.deviceXDPI (or something similar) to see if
					// zoom level has changed.
				);
			}

			return {
				remove: function(){
					array.forEach(handles, function(h){ h.remove(); });
					if(clickTimer){
						clearTimeout(clickTimer);
						clickTimer = null;
					}
				}
			};
		}
	};

	return ret;
});
