/* @Packager.Header
<FileDescription>
	Control keyboard keystroke combinations.
</FileDescription>
<Author name="Frederico Caldeira Knabben" email="www.fckeditor.net" />
*/

var FCKKeystrokeHandler = function( cancelCtrlDefaults )
{
	this.Keystrokes = new Object() ;
	this.CancelCtrlDefaults = ( cancelCtrlDefaults !== false ) ;
}

/*
 * Listen to keystroke events in an element or DOM document object.
 *		@target: The element or document to listen to keystroke events.
 */
FCKKeystrokeHandler.prototype.AttachToElement = function( target )
{
	// For newer browsers, it is enough to listen to the keydown event only. 
	// Some browsers instead, don't cancel key events in the keydown, but in the
	// keypress. So we must do a longer trip in those cases.
	FCKTools.AddEventListenerEx( target, 'keydown', _FCKKeystrokeHandler_OnKeyDown, this ) ;
	if ( FCKBrowserInfo.IsGecko10 || FCKBrowserInfo.IsOpera || ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac ) )
		FCKTools.AddEventListenerEx( target, 'keypress', _FCKKeystrokeHandler_OnKeyPress, this ) ;
}

/*
 * Sets a list of keystrokes. It can receive either a single array or "n"
 * arguments, each one being an array of 1 or 2 elemenst. The first element
 * is the keystroke combination, and the second is the value to assign to it.
 * If the second element is missing, the keystroke definition is removed.
 */
FCKKeystrokeHandler.prototype.SetKeystrokes = function()
{
	// Look through the arguments.
	for ( var i = 0 ; i < arguments.length ; i++ )
	{
		var keyDef = arguments[i] ;
		
		if ( typeof( keyDef[0] ) == 'object' )		// It is an array with arrays defining the keystrokes.
			this.SetKeystrokes.apply( this, keyDef ) ;
		else
		{
			if ( keyDef.length == 1 )		// If it has only one element, removed the keystroke.
				delete this.Keystrokes[ keyDef[0] ] ;
			else							// Otherwise add it.
				this.Keystrokes[ keyDef[0] ] = keyDef[1] === true ? true : keyDef ;
		}
	}
}

function _FCKKeystrokeHandler_OnKeyDown( ev, keystrokeHandler )
{
	// Get the key code.
	var keystroke = ev.keyCode || ev.which ;

	// Combine it with the CTRL, SHIFT and ALT states.
	var keyModifiers = 0 ;
	
	if ( ev.ctrlKey || ev.metaKey )
		keyModifiers += CTRL ;
	
	if ( ev.shiftKey )
		keyModifiers += SHIFT ;
	
	if ( ev.altKey )
		keyModifiers += ALT ;

	var keyCombination = keystroke + keyModifiers ;
	
	var cancelIt = keystrokeHandler._CancelIt = false ;
	
	// Look for its definition availability.
	var keystrokeValue = keystrokeHandler.Keystrokes[ keyCombination ] ;
	
//	FCKDebug.Output( 'KeyDown: ' + keyCombination + ' - Value: ' + keystrokeValue ) ;
	
	// If the keystroke is defined
	if ( keystrokeValue )
	{
		// If the keystroke has been explicetly set to "true" OR calling the
		// "OnKeystroke" event, it doesn't return "true", the default behavior
		// must be preserved.
		if ( keystrokeValue === true || !( keystrokeHandler.OnKeystroke && keystrokeHandler.OnKeystroke.apply( keystrokeHandler, keystrokeValue ) ) )
			return true ;

		cancelIt = true ;
	}

	// By default, it will cancel all combinations with the CTRL key only (except positioning keys).
	if ( cancelIt || ( keystrokeHandler.CancelCtrlDefaults && keyModifiers == CTRL && ( keystroke < 33 || keystroke > 40 ) ) )
	{
		keystrokeHandler._CancelIt = true ;

		if ( ev.preventDefault )
			return ev.preventDefault() ;
		
		ev.returnValue = false ;
		ev.cancelBubble = true ;
		return false ;
	}

	return true ;
}

function _FCKKeystrokeHandler_OnKeyPress( ev, keystrokeHandler )
{
	if ( keystrokeHandler._CancelIt )
	{
//		FCKDebug.Output( 'KeyPress Cancel', 'Red') ;

		if ( ev.preventDefault )
			return ev.preventDefault() ;

		return false ;
	}

	return true ;
}