/**
 *  ContextMenu: a library for generating context-menus on html elements.
 *  When enabled it will take over the onmousedown/oncontextmenu functions
 *  for the document, and works only where these are possible to override.
 *
 *  The classes rely on the prototype.js ( http://prototype.conio.net )
 *  and is released under the same terms as the prototype library.
 *
 *  Home: http://eide.org/js/contextmenu/
 *  @version 0.1
 *  @author Havard Eide
 *  @license MIT
 */
 
if( typeof Class == "undefined" )
{
    alert( "You have not included prototype.js!" );
}
// Global variable pointing to the last created ContextMenu element
// If you create more than one you will need to track all of these
// to be able to disable the contexmenus.
var __contextMenu = null;

var ContextMenu = Class.create();

/**
 *  When creating a new ContextMenu the menu itself
 *  is disabled and will need to be enabled:
 *  var menu = new ContextMenu();
 *  menu.addElement( "element", "element-menu" );
 *  menu.enable();
 */
ContextMenu.prototype = {
	initialize: function( ) {
		this.elements = new Array();
		this.enabled = false;
		this.ns = document.getElementById && !document.all;
		this.showingMenu = false;
		this.currentMenu = null;
		this.oldcontextmenu = document.oncontextmenu;
		this.oldmousedown = document.onmousedown;
	},
	/**
	 * Elements are of type ContextMenu.Element, these really
	 * don't do much for now, but because they will be extended
	 * they stay like this for now.
	 */
	addElement: function( id, target ) {
		var el = new ContextMenu.Element( id, target ); 
		this.elements.push( el );
		return el;
	},
	/**
	 * Call this on the ContextMenu object when you want to
	 * enable the menu.
	 */
	enable: function() {
		this.enabled = true;
		this.oldmousedown = document.onmousedown;
		this.oldcontextmenu = document.oncontextmenu;
		document.onmousedown    = this.mouseclick;
		document.oncontextmenu  = this.rightclick;
		__contextMenu = this;
	},
	/**
	 * If you, for some reason, want to disable the menu and get
	 * the old functionality of right-clicking: call this.
	 */
	disable: function () {
		this.enabled = false;
		document.onmousedown = this.oldmousedown;
		document.oncontextmenu = this.oldcontextmenu;
	},
	/**
	 * Close the current menu. Call this when working on 
	 * a menu and you want to close it after some work has been done:
	 * <a onclick="highlightText( 'javascript' ); menu.closeMenu();">Highlight</a>
	 */    
	closeMenu: function() {
	   if( this.showingMenu ) {
	       var el = $( this.currentMenu );
	       el.style.display = "none";
	       this.showingMenu = false;
	   }
	},
	/**
	 * Get a valid element ( the ones that can be right-clicked )
	 * based on a element ID
	 */
	validElement: function ( id ) {
		var n = this.elements.length;
		for( var i = 0; i < n; i++ ) {
			if( this.elements[i].id == id ) {
				return this.elements[i];
			}
		}
		return false;
	},
	/**
	 * Get a element based on the menu ID ( the one to display )
	 */
	validMenu: function ( id ) {
	   var n = this.elements.length;
	   for( var i = 0; i < n; i++ ) {
	       if( this.elements[i].menu == id ) {
	           return this.elements[i];
	       }
       }
       return false;
	},
	/**
	 * Called when the ContextMenu object is enabled and a click
	 * is registered
	 * Will return before the menu is closed if we click on a element
	 * inside a menu.
	 */
	mouseclick: function( e ) {	
       	if( __contextMenu.showingMenu ){
       	    var currentMenu = $( __contextMenu.currentMenu );
       	    var target = __contextMenu.ns ? e.target : event.srcElement;
       	    for( ; target; target = target.parentNode ) {
       	        if( target.id && target.id == currentMenu.id ){
       	            return;
                }
       	    }
			if( currentMenu ) {
                __contextMenu.showingMenu = false ;
				currentMenu.style.display = "none" ;
                return true;
			}
        }
        return true ;
	},
	/**
	 * Called when the ContextObject is enabled and a rightclick is
     * registered.
	 */
	rightclick: function( e ) {
        // Make sure we close any open menus ( should not happen though... )	
		if( __contextMenu.showingMenu ) {
			__contextMenu.mouseclick();
		}
		
		// What html element have we registered a rightclick on?
		var target = __contextMenu.ns ? e.target : event.srcElement;
		
		// Get the rightclick menu based on the ID of the 
		// element we just have clicked
		var menu = __contextMenu.validElement( target.id );
		// That element has not been registered for rightclick
		// menu: return before doing any harm :)
		if( !menu ) {
			return;
		}
		
		// Register the current menu that will be opened
		__contextMenu.currentMenu = menu.menu;
		var el = $( menu.menu );
		// Try to retrieve the menu we want to display, if we can't find it
		// ( which is odd, you should register valid menus! ) we just return
		if( !el ) {
			return;
		}
		
		// Position the element correctly
		if (__contextMenu.ns ){
			el.style.left = e.clientX+document.body.scrollLeft;
			el.style.top = e.clientY+document.body.scrollTop;
		}else{
			el.style.pixelLeft = event.clientX+document.body.scrollLeft;
			el.style.pixelTop = event.clientY+document.body.scrollTop;
		}
		el.style.display = "block";
		
		// Yes: we are now showing a menu, and everything has gone smoothly!
       __contextMenu.showingMenu = true;
       return false ;	
	}
}

/**
 *  The ContextMenu.Element object is nothing much for now.
 *  The plan is to extend it with more functionality, so it
 *  will change very soon.
 */
ContextMenu.Element = Class.create();
ContextMenu.Element.prototype = {
	initialize: function( id, target ) {
		this.id = id;
		this.menu = target;
	}
}
