/////////////////////////////////////////////////////////////////
//	Copyright © 2004-2008 by Symmetrix Software, Inc.
//				Brookfield, Wisconsin
//				ALL RIGHTS RESERVED
  

/////////////////// UI Helper Functions //////////////////////
//	These functions provide various services for most kinds of UIs.
//	Specific UI behaviour should be implemented in UI.js....
//
//	Many of these functions implement dynamic behaviour of elements, i.e. elements
//	whose appearence can change based on whether they are enabled/disabled,
//	highlited or not, or selected or not. i.e. in reponse to model changes or 
//	UI events like mouse rollovers and clicks.
//	In these cases, the essence of what's done is to add/remove style class names 
//	to/from the className attribute for individual elements.
//	The base class name (i.e. the first listed) is the "base" style that specifies
//	the appearance of a disabled, un-highlighted, unselected element.
//	The functions uiEnable(), uiHilite(), and uiSelect() can be used to change the
//	appearance of the element dynamically.
//  NOTE: The current implementation restricts the enable, highlight, and selected
//				styles to be mutually exclusive.  

// Global references to the image viewing element and the associated
// image tag to use when popping up images...
var g_imageViewer;
var g_imageViewerImage;

var g_uiWndStatusStack;

// Very lenient (and slightly non-standard JS) conversion of various object types to boolean...
function uiCvt2Bool( value )
{
	var bool = value == null || 
						value == true || 
						value == "true" || 
						value == "y";
						
	if ( !bool )
		{
		valueAsNum = parseInt( value );
		bool = !isNaN( valueAsNum ) && valueAsNum != 0;
		}
		
	return bool;
}

// Return currently active classes in an array with leading and trailing empty
// class names removed.....
function uiGetActiveClasses( elem )
{
	var classes = elem.className.split( " " );
	while ( classes.length > 0 && classes[0] == "" )
		classes.shift();
		
	while ( classes.length > 0 && classes[ classes.length - 1 ] == "" )
		classes.pop();
		
	return classes;
}

// Replace the specified element's classes with the array of class names
function uiSetActiveClasses( elem, classes )
{
	if ( !classes )
		throw new Error( "null classes argument to asSetActive Classes" );
		
	elem.className = classes.join( " " );
}

// Find the specified class name in the optional array of classes.
// Return the zero-base position in classes of the found class name
// or -1 if not found.
function uiFindClass( elem, className, classes )
{
	if ( !classes )
		classes = uiGetActiveClasses( elem );
		
	for ( var idx = 0; idx < classes.length; idx++ )
		if ( classes[idx] == className )
			return idx;
			
	return -1;
}

// Returns true if specified element is enabled....
function uiIsEnabled( elem )
{
	return !uiIsFlagSet( elem, "disabled" );
}

// Sets/resets whether the specified element is enabled or not.
function uiEnable( elem, enableIt )
{
	var enableIt = uiCvt2Bool( enableIt );
	if ( !enableIt )
		uiHilite( elem, false );
		
	uiAddOrRemoveFlag( elem, "disabled", !enableIt );
}

// Sets/resets whether the specified element should be highlighted or not...
function uiHilite( elem, hiliteIt )
{
	var hiliteIt = uiCvt2Bool( hiliteIt );
	
	// We don't highlight a disabled element.....
	if ( hiliteIt && !uiIsEnabled( elem ) )
		return;

	uiAddOrRemoveFlag( elem, "hilited", hiliteIt );
}

// Sets/resets whether the specified element should appear "selected" or not...
function uiSelect( elem, selectIt )
{
	var selectIt = uiCvt2Bool( selectIt );
	
	// We don't select a disabled element.
	if ( selectIt && !uiIsEnabled( elem ) )
		return;

	uiAddOrRemoveFlag( elem, "selected", selectIt );
}

// Checks to see whether the specified flag is included in the 
// element's style classes.
function uiIsFlagSet( elem, flag )
{
	var classes = uiGetActiveClasses( elem );
 	var flagID = classes[0] + "_" + flag;
	return uiFindClass( elem, flagID, classes ) >= 0;
}

// Adds/removes the specified flag from the element's style classes.
function uiAddOrRemoveFlag( elem, flag, addIt )
{
	if ( !flag )
		throw new Error( "null flag argument to uiAddOrRemoveFlag" );
		
 	var classes = uiGetActiveClasses( elem );
 	if ( classes.length == 0 )
 		return;
 		
 	var flagID = classes[0] + "_" + flag;
 		
	if ( addIt )
		{
		if ( uiFindClass( elem, flagID, classes ) <= -1 )
			classes.push( flagID );
		}
		
	else
		{
		var pos = uiFindClass( elem, flagID, classes );
		if ( pos >= 0 )
			classes.splice( pos, 1 );
		}
		
	uiSetActiveClasses( elem, classes );
}


function uiPopupImage( imgSrc, event )
{
	// Initialize global image viewer....
	if ( g_imageViewer == undefined )
		g_imageViewer = g_myModel.getElementById( "plx_imageViewer" );

	// Bail if none...
	if ( !g_imageViewer )
		return;

	// Initialize the global image tag (assumed to be contained in the
	// image viewer).
	if ( g_imageViewerImage == undefined )
		g_imageViewerImage = g_myModel.getElementById( "plx_imageViewerImage" );

	// More bailing....
	if ( !g_imageViewerImage )
		return;

	// If asked to display an image, then....
	if ( imgSrc )
		{
		// Load the image.....
		g_imageViewerImage.src = imgSrc;
		
		// Adjust it to document window dimensions....
		uiSizeForDocWindow( g_imageViewerImage );

		// Show it...		
		uiShowElem( g_imageViewer );
		}
		
	// No image to show, hide everything...
	else
		{
		uiHideElem( g_imageViewer );
		g_imageViewerImage.src = null;
		}
}

function uiSizeForDocWindow( imgTag )
{
		var docHeight, docWidth;
		if ( document.body.clientHeight )	// IE
			{
			docHeight = document.body.clientHeight;
			docWidth = document.body.clientWidth;
			}
		else if ( window.innerHeight )	// FF
			{
			docHeight = window.innerHeight;
			docWidth = window.innerWidth;
			}
		else
			throw Error( "Cannot get document window dimensions.  Not a supported browser." ); 

		var maxHeight = 0.9 * docHeight;
		var maxWidth = 0.9 * docWidth;
		
		var rawImg = new Image();
		rawImg.src = imgTag.src;
		
		var zoomedWidth, zoomedHeight;

		// If the image is here, then zoom it and position it to fit in the 
		//	max height/width....
		if ( rawImg.width > 0 && rawImg.height > 0 )
			{		
    	var zoomWidth = maxWidth / rawImg.width;
    	var zoomHeight = maxHeight / rawImg.height;
    	var zoom = zoomWidth < zoomHeight ? zoomWidth : zoomHeight;
   	
			if ( zoom > 1 )
				zoom = 1;
				
      zoomedWidth = zoom * rawImg.width;
      zoomedHeight = zoom * rawImg.height;
			}
			
		// Image is not yet here.  Set up to display the "alt" text...
		else
			{
			zoomedWidth = maxWidth;
			zoomedHeight = maxHeight;
			imgTag.alt = "Image not yet available...";
			imgTag.src = null;
			}
			
  	imgTag.width = zoomedWidth;
  	imgTag.height = zoomedHeight;
  	imgTag.style.top = ( docHeight - zoomedHeight ) / 2 + "px";
  	imgTag.style.left = ( docWidth - zoomedWidth ) / 2 + "px";

}

function uiShowElem( elem, atPoint )
{
	// If positioning is requested, then try it.....
	// Note will only work for relative and absolute position styles....
	if ( 	atPoint && 
				atPoint.x != undefined &&
				atPoint.y != undefined )
		{
		elem.style.left = atPoint.x;
		elem.style.top = atPoint.y;
		}

	// Show it!
	elem.style.display = "";
}

function uiHideElem( elem )
{
	// Hide it...
	elem.style.display = "none";
}

function uiSetThumbnail( theModel, imgElem, popupURL )
{
	if ( !theModel || !imgElem )
		return;
		
	if ( popupURL )
		{
		uiStartImageLoad( theModel, popupURL );
		imgElem.title = "Click to view...";
		imgElem.src = theModel.getParam( "IconTipPicAvailable" );
		imgElem.style.cursor = "pointer";
		}
	else
		{
		imgElem.title = "";
		imgElem.src = theModel.getParam( "IconTransparent" );
		imgElem.onClick = null;
		imgElem.style.cursor = "default";
		}
	
}

function uiStartImageLoad( theModel, imgURL, onLoadTarget, action )
{
	if ( !imgURL || imgURL == "" )
		return false;

	imgURL = imgURL.toLowerCase();
	
	// Do we have an image object for this url?  If not create one.
	var imgObj = theModel.getAppOb( "img", imgURL, true );

	// Has the actual image been requested?  If not request it.
	var rawImage = imgObj._rawImage;
	if ( !rawImage )
		{
		rawImage = new Image();
	  rawImage.src = imgURL;
		imgObj._rawImage = rawImage;
		}
	
	// If we have dimensions for the raw image, then the image is loaded
	// already.  
	if ( rawImage.height > 0 && rawImage.width > 0 )
		imgObj._isHere = true;
		
	else
		{
		// Load is not complete....  :(
		imgObj._isHere = false;

		if ( onLoadTarget && action )
			{
  		// Schedule an event notification to adjust the image tag when it is available.
  		theModel.onPC( imgURL + ".loadComplete", "n", onLoadTarget, action, true );
		
  		// Ask the idler to check for image load completion (unless it is already running).
  		if ( !PLXIdler.hasProcess( "uiCheck4ImageLoadComplete" ) )
  			PLXIdler.addProcess( "uiCheck4ImageLoadComplete", uiCheck4ImageLoadComplete, theModel );
			}
		}
		
		return imgObj;
}

function uiSwitchImage( theModel, imgTag, imgURL, defImgURL, dynamicSize )
{
	// Say what?!?!
	if ( !imgTag )
		return;
	
	// if first time being asked to switch an image for this tag, then remember
	// whether we are supposed to dynamically size it to its content or what....	
	if ( imgTag._dynamicSize == undefined )
		imgTag._dynamicSize = dynamicSize ? true : false;

	// Default image URL if needed and specified....
	if ( !imgURL && defImgURL )
		imgURL = defImgURL;
		
	if ( imgURL == "" )
		{
		imgTag.src = null;
		return;
		}
	
	// Start the load of the image....
	var imgObj = uiStartImageLoad( theModel, imgURL, imgTag.getAttribute( "id" ), "if ( _v == 'y' ) uiAdjustImageTag( _e );" );

	// If already here, then adjust the displayable image tag (specified) 
	//	to fit within its borders....
	if ( imgObj._isHere )
		uiAdjustImageTag( imgTag, imgObj._rawImage );

	// Image is not here yet......   		
	else
		{
		// attach the raw image we are loading to the image element that we're trying to
		// display (via an expando).  We'll use this later when the image finally arrives...
		imgTag._rawImage = imgObj._rawImage;

		// Display the default for now......
		imgTag.src = null;
		}
}
		
// Called in idle loop to check to see whether incomming images have arrived and
// notify the model if they do.
function uiCheck4ImageLoadComplete()
{
	// Sanity?
	if ( arguments.length <= 0 )
		throw Error( "No arguments to uiCheck4ImageLoadComplete." );

	var needMoreTime = false;	// Do we need more idle time?

	// Walk the image objects stored as custom objects in the model.....
	var theModel = arguments[0];
	var imgObjects = theModel.getAppObIndex( "img" );
	if ( imgObjects )
		{
		// For each image......
		for ( var imgID in imgObjects )
			{
			// if there is an object, it has a raw image element defined and loading
			// was not complete, then...   Is it now?
			var currImgObj = imgObjects[ imgID ];
			if ( currImgObj && currImgObj._rawImage && !currImgObj._isHere )
				{
				// If both dimensions are not zero, then we conclude that the image has arrived....
				if ( currImgObj._rawImage.width > 0 && currImgObj._rawImage.height > 0 )
					{
					// The image has arrived...  
					currImgObj._isHere = true;
					
					// Set the "loadComplete" property to "y"...
					// This will notify any active elements waiting for this image....
					theModel.setPV( imgID + ".loadComplete", "y" );
					}

				// We still have an incomming image... We will need more idle time....
				else
					needMoreTime = true;
				}
			}
		}

	return needMoreTime;
}

function uiAdjustImageTag( imgTag, rawImage )
{
	if ( !imgTag )
		return;

	if ( !rawImage )
		rawImage = imgTag._rawImage;
		
	if ( !rawImage )
		return;
		
	// If we are statically sizing to a max, then....
	if ( !imgTag._dynamicSize )
		{
  	    // Figure the maximum height & width that this image tag has to live in by asking
  	    // the image tag itself for some proprietary properties.  Any not specified 
  	    // or erroneous default to the full size image measurement.
  	    var maxHeight = parseInt( imgTag.getAttribute( "plx_MaxHeight" ) );
  	    if ( isNaN( maxHeight ) || maxHeight <= 0 )
  		    maxHeight = rawImage.height;
      
  	    var maxWidth = parseInt( imgTag.getAttribute( "plx_MaxWidth" ) );
  	    if ( isNaN( maxWidth ) || maxWidth <= 0 )
  		    maxWidth = rawImage.width;
      		
  	    // Figure the zoom amount for width & height needed to fit and choose the
  	    // most zoom (i.e. the smallest zoom factor).
        var zoomWidth = maxWidth / rawImage.width;
        var zoomHeight = maxHeight / rawImage.height;
        var zoom = zoomWidth < zoomHeight ? zoomWidth : zoomHeight;
      	
  	    // We don't make images bigger then they are, so....
        if ( zoom > 1 )
    	    zoom = 1;
      	
  	    // Set up the image tag with the new data....
        imgTag.src = rawImage.src;
        imgTag.width = zoom * rawImage.width;
		}
		
	// We are dynamically sizing the image to its container.
	else
		{
        imgTag.src = rawImage.src;
		if ( rawImage.width > rawImage.height )
			{
			imgTag.style.width = "100%";
			imgTag.style.height = null;
			}
		else	
			{		
			imgTag.style.width = null;
			imgTag.style.height = "100%";
			}
		} 	
}

function uiShowAlert( title, subTitle, text ) 
    {
    var alertOverlayElem = g_myModel.getElementById("plx_alert_overlay");
    if ( !alertOverlayElem )
        throw Error("plx_alert_overlay not found.");
        
    // if we have everything we need to display, then.....
    if ( title && subTitle && text )
        {
        // Get references to the specfic elements we need to assign......
        var alertTitleElem = g_myModel.getElementById( "plx_alert_title" );
        if ( !alertTitleElem )
            throw Error( "plx_alert_title not found." );
        
        var alertSubtitleElem = g_myModel.getElementById( "plx_alert_subtitle" );
        if ( !alertSubtitleElem )
            throw Error( "plx_alert_subtitle not found." );
        
        var alertTextElem = g_myModel.getElementById( "plx_alert_text" );
        if ( !alertTextElem )
            throw Error( "plx_alert_text not found." );
            
        // Assign the text dynamically....
        alertTitleElem.innerHTML = title;
        alertSubtitleElem.innerHTML = subTitle;
        alertTextElem.innerHTML = text;
        
        // Make the alert visible.
        alertOverlayElem.style.visibility = "visible";
        }
        
    // Otherwise we interpret this as a request to hide the alert window.
    else
        alertOverlayElem.style.visibility = "hidden";
    }

function uiDisplayError( msg )
    {
    if ( msg )
        {
		// Get the full text of the message by substituting any arguments.....
		var fullText = formatArgs( msg, arguments );
		
        uiShowAlert( "Error", "The last operation resulted in an error....", 
                                "<pre>" + fullText + "</pre>" );
        }
     else
        uiShowAlert( null );
    }
    

function uiShowBusy( msg )
{
	if ( !g_uiWndStatusStack )
		g_uiWndStatusStack = new Array;
		
	if ( msg && msg != "" )
		{
		g_uiWndStatusStack.push( window.status );
		window.status = formatArgs( msg, arguments );
		}
		
	else
		{
		var prevMsg = g_uiWndStatusStack.pop();
		window.status = prevMsg ? prevMsg : "";
		}
}

function uiGetKeyCode( event )
{
		if ( event.keyCode )				// IE way...
			return event.keyCode;
			
		if ( event.which )					// NS way....
			return event.which;
			
		return 0;										// No way....
}

function uiKeyDown( objID, elem, event, validator )
{
	event.returnValue = true;
	
 	var keyCode = uiGetKeyCode( event );
	
	// Validate the value if user hit enter...
  if ( keyCode == 13 )
  	event.returnValue = validator( objID, elem, event );

	// If user hit escape, then restore the current value...
	// NOTE: We are abusing the defaultValue property for this....
	else if ( keyCode == 27 )
		{
		elem.value = elem.defaultValue;
		event.returnValue = false;
		}

	return event.returnValue;
	
}

function uiSetBackImg( element, setIt, imgUrl )
{
	if ( setIt )
		element.style.backgroundImage = "url(" + imgUrl + ")";
	else
		element.style.backgroundImage = "none";
}

