(function () {

	var Overlay = YAHOO.widget.Overlay,
		Prototype = Overlay.prototype,
		Dom = YAHOO.util.Dom;
	

    Prototype.getConstrainedX = function (x) {

		var oOverlay = this,
			oOverlayEl = oOverlay.element,
			nOverlayOffsetWidth = oOverlayEl.offsetWidth,

			nViewportOffset = Overlay.VIEWPORT_OFFSET,
			viewPortWidth = Dom.getViewportWidth(),
			scrollX = Dom.getDocumentScrollLeft(),

			bCanConstrain = (nOverlayOffsetWidth + nViewportOffset < viewPortWidth),

			aContext = this.cfg.getProperty("context"),
			oContextEl,
			nContextElX,
			nContextElWidth,

			bFlipped = false,

			nLeftRegionWidth,
			nRightRegionWidth,

			leftConstraint = scrollX + nViewportOffset,
			rightConstraint = scrollX + viewPortWidth - nOverlayOffsetWidth - nViewportOffset,

			xNew = x,

			oOverlapPositions = {

				"tltr": true,
				"blbr": true,
				"brbl": true,
				"trtl": true
			
			};


		var flipHorizontal = function () {
		
			var nNewX;
		
			if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
				nNewX = (nContextElX - nOverlayOffsetWidth);
			}
			else {
				nNewX = (nContextElX + nContextElWidth);
			}
			

			oOverlay.cfg.setProperty("x", (nNewX + scrollX), true);

			return nNewX;

		};



		/*
			 Uses the context element's position to calculate the availble width 
			 to the right and left of it to display its corresponding Overlay.
		*/

		var getDisplayRegionWidth = function () {

			// The Overlay is to the right of the context element

			if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
				return (nRightRegionWidth - nViewportOffset);
			}
			else {	// The Overlay is to the left of the context element
				return (nLeftRegionWidth - nViewportOffset);
			}
		
		};


		/*
			Positions the Overlay to the left or right of the context element so that it remains 
			inside the viewport.
		*/

		var setHorizontalPosition = function () {
		
			var nDisplayRegionWidth = getDisplayRegionWidth(),
				fnReturnVal;

			if (nOverlayOffsetWidth > nDisplayRegionWidth) {
	
				if (bFlipped) {
	
					/*
						 All possible positions and values have been 
						 tried, but none were successful, so fall back 
						 to the original size and position.
					*/

					flipHorizontal();
					
				}
				else {
	
					flipHorizontal();

					bFlipped = true;
	
					fnReturnVal = setHorizontalPosition();
	
				}
			
			}
	
			return fnReturnVal;
		
		};


		// Determine if the current value for the Overlay's "x" configuration property will
		// result in the Overlay being positioned outside the boundaries of the viewport
		
		if (x < leftConstraint || x > rightConstraint) {

			// The current value for the Overlay's "x" configuration property WILL
			// result in the Overlay being positioned outside the boundaries of the viewport

			if (bCanConstrain) {

				//	If the "preventcontextoverlap" configuration property is set to "true", 
				//	try to flip the Overlay to both keep it inside the boundaries of the 
				//	viewport AND from overlaping its context element.

				if (this.cfg.getProperty("preventcontextoverlap") && aContext && 
					oOverlapPositions[(aContext[1] + aContext[2])]) {
	
					oContextEl = aContext[0];
					nContextElX = Dom.getX(oContextEl) - scrollX;
					nContextElWidth = oContextEl.offsetWidth;
					nLeftRegionWidth = nContextElX;
					nRightRegionWidth = (viewPortWidth - (nContextElX + nContextElWidth));
	
					setHorizontalPosition();
					
					xNew = this.cfg.getProperty("x");
				
				}
				else {

					if (x < leftConstraint) {
						xNew = leftConstraint;
					} else if (x > rightConstraint) {
						xNew = rightConstraint;
					}

				}

			} else {
				//	The "x" configuration property cannot be set to a value that will keep
				//	entire Overlay inside the boundary of the viewport.  Therefore, set  
				//	the "x" configuration property to scrollY to keep as much of the 
				//	Overlay inside the viewport as possible.                
				xNew = nViewportOffset + scrollX;
			}

		}

		return xNew;
	
	};



	Prototype.getConstrainedY = function (y) {

		var oOverlay = this,
			oOverlayEl = oOverlay.element,
			nOverlayOffsetHeight = oOverlayEl.offsetHeight,
		
			nViewportOffset = Overlay.VIEWPORT_OFFSET,
			viewPortHeight = Dom.getViewportHeight(),
			scrollY = Dom.getDocumentScrollTop(),

			bCanConstrain = (nOverlayOffsetHeight + nViewportOffset < viewPortHeight),

			aContext = this.cfg.getProperty("context"),
			oContextEl,
			nContextElY,
			nContextElHeight,

			bFlipped = false,

			nTopRegionHeight,
			nBottomRegionHeight,

			topConstraint = scrollY + nViewportOffset,
			bottomConstraint = scrollY + viewPortHeight - nOverlayOffsetHeight - nViewportOffset,

			yNew = y,
			
			oOverlapPositions = {
				"trbr": true,
				"tlbl": true,
				"bltl": true,
				"brtr": true
			};


		var flipVertical = function () {

			var nNewY;
		
			// The Overlay is below the context element, flip it above
			if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) { 
				nNewY = (nContextElY - nOverlayOffsetHeight);
			}
			else {	// The Overlay is above the context element, flip it below
				nNewY = (nContextElY + nContextElHeight);
			}

			oOverlay.cfg.setProperty("y", (nNewY + scrollY), true);
			
			return nNewY;
		
		};


		/*
			 Uses the context element's position to calculate the availble height 
			 above and below it to display its corresponding Overlay.
		*/

		var getDisplayRegionHeight = function () {

			// The Overlay is below the context element
			if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
				return (nBottomRegionHeight - nViewportOffset);				
			}
			else {	// The Overlay is above the context element
				return (nTopRegionHeight - nViewportOffset);				
			}
	
		};


		/*
			Trys to place the Overlay in the best possible position (either above or 
			below its corresponding context element).
		*/
	
		var setVerticalPosition = function () {
	
			var nDisplayRegionHeight = getDisplayRegionHeight(),
				fnReturnVal;
				

			if (nOverlayOffsetHeight > nDisplayRegionHeight) {
			   
				if (bFlipped) {
	
					/*
						 All possible positions and values for the 
						 "maxheight" configuration property have been 
						 tried, but none were successful, so fall back 
						 to the original size and position.
					*/

					flipVertical();
					
				}
				else {
	
					flipVertical();

					bFlipped = true;
	
					fnReturnVal = setVerticalPosition();
	
				}
			
			}
	
			return fnReturnVal;
	
		};


		// Determine if the current value for the Overlay's "y" configuration property will
		// result in the Overlay being positioned outside the boundaries of the viewport

		if (y < topConstraint || y  > bottomConstraint) {
	
			// The current value for the Overlay's "y" configuration property WILL
			// result in the Overlay being positioned outside the boundaries of the viewport

			if (bCanConstrain) {	

				//	If the "preventcontextoverlap" configuration property is set to "true", 
				//	try to flip the Overlay to both keep it inside the boundaries of the 
				//	viewport AND from overlaping its context element.
	
				if (this.cfg.getProperty("preventcontextoverlap") && aContext && 
					oOverlapPositions[(aContext[1] + aContext[2])]) {
	
					oContextEl = aContext[0];
					nContextElHeight = oContextEl.offsetHeight;
					nContextElY = (Dom.getY(oContextEl) - scrollY);
	
					nTopRegionHeight = nContextElY;
					nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
	
					setVerticalPosition();
	
					yNew = oOverlay.cfg.getProperty("y");
	
				}
				else {

					if (y < topConstraint) {
						yNew  = topConstraint;
					} else if (y  > bottomConstraint) {
						yNew  = bottomConstraint;
					}
				
				}
			
			}
			else {
			
				//	The "y" configuration property cannot be set to a value that will keep
				//	entire Overlay inside the boundary of the viewport.  Therefore, set  
				//	the "y" configuration property to scrollY to keep as much of the 
				//	Overlay inside the viewport as possible.
			
				yNew = nViewportOffset + scrollY;
			}
	
		}

		return yNew;
	};

}());
