/* ***************************************************************** */
/*                                                                   */
/* IBM Confidential                                                  */
/*                                                                   */
/* OCO Source Materials                                              */
/*                                                                   */
/* (C) Copyright IBM Corp. 2006                                      */
/*                                                                   */
/* The source code for this program is not published or otherwise    */
/* divested of its trade secrets, irrespective of what has been      */
/* deposited with the U.S. Copyright Office.                         */
/*                                                                   */
/* ***************************************************************** */

/* Menu.js
   
   Author: Tim Finley (finleyt@us.ibm.com)
   Based off of Chris Samoiloff's menu.js
   Depends on prototype.js for two effects and some $(), but that could be easily removed.
   
   A small library to help display "modal" and "modeless" popups. Note these are not
   the true definition of modal and modeless, but close enough.
   
   For "modal" popups use the Popup object. These popups will not disappear unless you
   explicitly call Popup.hide( <id> )
   
   For "modeless" popups use the MenuPopup object. Only one "modeless" popup can be open
   at a time. Also these popus will automatically disappear if the user presses ESC or
   clicks the mouse anywhere on the page (other than the popup).
   
   !!! IMPORTANT NOTES !!!
   
   For Popups to work every popup needs to have certain styles. I recommend to make your
   popup html like this:
   
	   <div id="popupId" class="popup">
	   		... popup contents ...
	   </div>
   
   And use the following CSS styles
   
	   .popup { position: absolute;
	   			left: -9999px;
	   			z-index: 200;
	   			
	   			// These last styles are optional, just my suggested defaults
	   			background-color: white;
	            width: 20em;
	            float: none;
	            text-align: left;
	          }
   
   For MenuPopups to work you need to use this javascript. I haven't included it in this
   js file just in case you already have functions for doc onclick or onkeyup. 
   
		document.onclick = function () {
			MenuPopup.hideMenu();
		};
		document.onkeyup = function ( event ) {
			MenuPopup.hideOnKeypress( event );
		};
	
	!!! !!!
   
   
   Examples:
   
   This will show a popup. Note the third parameter is optional.
   
   		Popup.show( <idOfPopup>, event, { focus: <Element to focus on popup close. If you
                                                  care to return focus then most of the time
                                                  you'll pass "this" here>,
                                          state: { <This state is used to store data that
                                                    other javascript code may need to use.
                                                    Use this instead of setting global
                                                    variables> }
   		} );
   
   This will hide a popup.
   
	   Popup.hide( <idOfPopup> );
   
   This will show a the object with id 'helpbubbleId' as a MenuPopup, the options are the
   same as above.
   
	   MenuPopup.showMenu( 'helpbubbleId', event, { focus: this } );
   
   This will hide the currently open MenuPopup (since only one is 
   open at a time.
   
   		MenuPopup.hide();
 

   Some other useful functions are
   		Popup.getState( <id> ) - return the saved state of a particular popup
   		Popup.getReturnFocus() - return focus that will be set after the popup closes
   		Popup.setReturnFocus() - change the return focus
   		Popup.isOpen( <id> )   - see if a particular popup is open
   		
   		MenuPopup.getState( )  - get the state of the currently open MenuPopup
   		MenuPopup.isOpen()     - check to see if there is a MenuPopup open
   		
   
*/
function PopupClass() { };
PopupClass.prototype = {

	open: { },		//array of the open popups
	returnFocusElement: false,
	numOpenPopups: 0,
	passedState: { },
	
	CONTAINER: 'oa-popup-container',
	
	initialize: function( ) {

	},
	
	show: function ( id, event, options ) {
	
		options = options || {};
		
		/* don't open the menu if it was previously open. This will cause clicking the link
	       to open the menu twice to toggle the popup */
		if ( this.isOpen( id ) ) {
		
			this.hide( id );
			
		} else {
		
			if ( options.focus ) {
				this.returnFocusElement = options.focus;
			}
		
			var eventSource = (event.target) ? event.target : event.srcElement; /*gets event target, depending on browser*/
			var popupElement = document.getElementById(id);
			
			var position = this.calculatePosition( popupElement, eventSource );
				
			var popupContainer = this.getPopupContainer();
			popupContainer.appendChild( popupElement); 
			
			var openPopupArray = {
				element: popupElement,
				state: options.state || {}
			};
			
			this.open[ id ] = openPopupArray;
			
			this.numOpenPopups++;
			
			new Popup.Effect.Appear( id, position.left, position.top );
			
			event.cancelBubble = true;
			
		}
		
	},
	
	hide: function ( id, options ) {
		var element = $( id );
		
		new Popup.Effect.Fade( element );
		var popup = this.open[ id ];
		
		this.numOpenPopups--;
		
		if ( this.numOpenPopups == 0 && this.returnFocusElement ) {
			$( this.returnFocusElement ).focus();
			this.returnFocusElement = false;
		}
		
		this.open[ id ] = false;
	},
	
	isOpen: function ( id ) {
		var popup = this.open[ id ];
		return popup != false && popup !== null && popup !== undefined;
	},
	
	getState: function( id ) {
		return this.open[ id ].state;
	},
	
	getReturnFocus: function() {
		return this.returnFocusElement;
	},
	
	clearReturnFocus: function() {
		var returnFocus = this.returnFocusElement;
		this.returnFocusElement = false;
		return returnFocus;
	},
	
	getPopupContainer: function ( ) {
	
		var popupContainer = $( this.CONTAINER );
		
		if ( popupContainer == null ) {
		
			var popupContainer = document.createElement( 'div' );
			popupContainer.setAttribute( 'id', this.CONTAINER );
			
			// Make the popupContainer be a separate containg block with a high z-index
			// This is necessary since separate containing blocks have separate z orderings
			// and we need to make the popupContainer "layer" on top of everything else
			popupContainer.setAttribute( 'style', 'position: absolute; left: 0px; top: 0px; z-index: 900;' );
			document.body.appendChild( popupContainer ); 
		}
		
		return popupContainer;
		
	},
	
	/* Calculate postion will ensure that the popup is placed on the screen near the clicked element,
	   according to the following rules. 
	   
	   If the whole popup will fit on screen where it was intended (just below the clicked element) this
	   fuction will return those x and y values.
	   
	   If the popup will appear below the bottom of the page (part of the popup is cut off the bottom)
	   then the popup will appear above the clicked element, except...
	   
	   If when the popop is displayed above the element it cuts cut off the top of the page, or the general case
	   the popup has a height larger than the page then the popup will just appear flush to the top of the page.
	   
	   These rules also apply similarly to the left-right of the page.
	   
	   To sum it up, this just trys to display as much of the popup as possible preventing overlapping the edges
	   of the page when possible.
    */
	calculatePosition: function ( popupElement, eventSource ) {
		
		//sets the menu position
		//normal position is a tad offset from the element that triggered the menu
		
		// to get the position for the drop down menu in case of RTL and LTR
		var menuLeftOffset;
		if( typeof( bidir) != "undefined" && bidir != null && bidir =='rtl') {
			menuLeftOffset = (popupElement.offsetWidth > 0)? popupElement.offsetWidth : 175; // assume default value for menu if offsetWidth is zero. 		
			menuLeftOffset = 24 - menuLeftOffset;
		}else{
			menuLeftOffset = eventSource.offsetWidth - 24	;
		}
		
		var popupY = ( this.menuGetOffsetTop(eventSource,0) + eventSource.offsetHeight - 10);	
		var popupX = ( this.menuGetOffsetLeft(eventSource,0) + menuLeftOffset);
		
		//check to make sure position is not offscreen and adjust, if it is
		
		// IE vs Firefox properties
		var body = document.documentElement ? document.documentElement : document.body;
		var windowHeight = window.innerHeight ? window.innerHeight : body.clientHeight;
		var windowWidth = window.innerWidth ? window.innerWidth : body.clientWidth;
		var scrollX = document.all ? document.body.scrollLeft : window.pageXOffset;
		var scrollY = document.all ? document.body.scrollTop : window.pageYOffset;
		
		if ((popupY + popupElement.offsetHeight) > windowHeight + scrollY ) popupY -= popupElement.offsetHeight;	
		if ((popupX + popupElement.offsetWidth) > windowWidth + scrollX ) popupX -= popupElement.offsetWidth;
		
		//check to make sure our adjustments didn't result in values less than the scrolled edge of the page
		if (popupY < scrollY) popupY = scrollY;
		if (popupX < scrollX) popupX = scrollX;
		
		return { left: popupX  + "px", top: popupY + "px" };
	},
	
	
	menuGetOffsetTop: function (pElem,pOTOP){
		//this function is called recursively until we get to the body element.  Not needed for absolutely positioned items.
		var offset = 0;
		var curElem = pElem;
		while (curElem){
			offset += curElem.offsetTop;
	   		curElem = curElem.offsetParent;
	   		if (curElem) offset -= curElem.scrollTop;
	   	}
		return offset;
	},
	
	menuGetOffsetLeft: function (pElem,pOLEFT){
		//this function is called recursively until we get to the body element. Not needed for absolutely positioned items.
		var offset = 0;
		var curElem = pElem;
		while (curElem){
			offset += curElem.offsetLeft;
	   		curElem = curElem.offsetParent;
	   		if (curElem) offset -= curElem.scrollLeft;
	   	}
		return offset;
	}
	
	
};

MenuPopupClass.prototype = new PopupClass();
MenuPopupClass.prototype.constructor = MenuPopupClass();
function MenuPopupClass() { };

MenuPopupClass.prototype.currentMenu = false;

MenuPopupClass.prototype.hideMenu = function ( options ) {
	if ( this.currentMenu ) {
		this.hide( this.currentMenu );
		this.currentMenu = false;
	}
};

MenuPopupClass.prototype.showMenu = function ( id, event, options ) {
	var tempCurrentMenu = this.currentMenu;
	
	this.hideMenu();
	
	// if you are trying open the existing menu then don't reshow it (causing it to toggle off)
	if ( id != tempCurrentMenu ) {
		this.currentMenu = id;
		this.show( id, event, options );
	}
};


MenuPopupClass.prototype.hideOnKeypress =  function (event){
	if( typeof(event) != "undefined" && event !== null && event.keyCode == Event.KEY_ESC) {
		MenuPopup.hideMenu();
	}
};

MenuPopupClass.prototype.isMenuOpen = function () {
	if ( this.currentMenu ) {
		return true;
	}
	return false;
};

MenuPopupClass.prototype.getState = function () {
	if ( this.currentMenu ) {
		return this.open[ this.currentMenu ].state;
	}
};


var Popup = new PopupClass();
var MenuPopup = new MenuPopupClass();

/* Custom Popup Effects */

Popup.Effect = {};

Popup.Effect.DURATION = 0.25;

/* Fade out the popup to 0 opacity and move it off the page
   We can't set display: none since that will break our offset
   calculations in some Firefox versions */
Popup.Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
  from: element.getOpacity() || 1.0,
  to:   0.0,
  duration: Popup.Effect.DURATION,
  afterFinishInternal: function(effect) { 
    if(effect.options.to!=0) return;
    effect.element.setStyle({opacity: oldOpacity, left: '-9999px'}); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

/* Fade in the popup and move it to (x,y) on the page */
Popup.Effect.Appear = function(element, x, y) {
  element = $(element);
  var options = Object.extend({
  from: 0.0,
  to:   1.0,
  duration: Popup.Effect.DURATION,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from);
    effect.element.setStyle({ left: x, top: y});
    effect.element.show(); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}