// $Archive: /WorkshopProjects/UTexasDallas/CampusGuide/working/CustomWeb/custom.js $ [$Revision: 1 $] $Author: Ed $ $Modtime: 3/17/06 10:41a $
////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2005-2006 by NearSpace, Inc.  All rights reserved.
//
// The information contained herein is confidential, proprietary
// to NearSpace,  Inc.,  and considered a trade secret as defined
// in section 499C of the penal code of the State of California.
// Use of  this information  by  anyone  other  than  authorized
// employees of NearSpace, Inc.  is granted  only under a written
// non-disclosure agreement,  expressly  prescribing  the  scope
// and manner of such use.
//
////////////////////////////////////////////////////////////////////////////

// Custom scripts for this venue
/** The ID of the topic currently open for viewing */
var gCurrentTopicID;

/** The last thing the user selected */
var gLastSelection;

/** An array of objects holding the state of the html 
    for each topic */
var gTopicList = new Array(
    { id:"servicesTopic",       el:null, img:null, loaded:false, requester:null },
    { id:"roomsTopic",          el:null, img:null, loaded:true,  requester:null },
    { id:"floorsTopic",         el:null, img:null, loaded:true,  requester:null } );
    
/** Set to true to enable debug alert messages */
var gDebug = true; 

/**
 * Show the topic whose text id is passed in.
 * Close the other topics.
 * 
 * @param id of the html element to expand
 */
function showTopic( id )
{
    try {
        
        hideInfoWindows();
        expandTopic( gTopicList[ id ] );
        
    } catch( e ) {
        showDebugException( "showTopic() error", e );
    }
    
    return false;
}

/**
 * Toggle the visible state of the specified item.
 * Close the other topics.
 */
function toggleTopic( id )
{
    try {
        
        hideInfoWindows();
        var topic = gTopicList[ id ];
        
        if ( isItemDisplayed( topic.el ) )
            collapseTopic( topic );
        else 
            expandTopic( topic );
        
    } catch( e ) {
        showDebugException( "toggleTopic() error", e );
    }
    
    return false;
}

/**
 * Expand the previously expanded topic.
 * (All topics are probably collapsed for some reason.)
 */
function restoreLastTopic()
{
    showTopic( gCurrentTopicID ) 
}

/**
 * @param the item to expand
 */
function expandTopic( selectedTopic )
{

    for( var i=0; i<gTopicList.length; i++ ){
        
        var topic = gTopicList[i];

        if ( topic == selectedTopic ){
            if ( topic.el.style.display != "block" )
                topic.el.style.display = "block";
            gCurrentTopicID = topic.id;
            
            // Toggle the open image
            topic.img.src = "close.gif"
            
            // Get the file, if necessary
            if ( ! topic.loaded )
               loadTopicFromFile( topic );
           
        } else {
            collapseTopic( topic );
        }
    }
}

/**
 * Hide all topics
 */
function collapseAllTopics()
{
    for( var i=0; i<gTopicList.length; i++ ){
        collapseTopic( gTopicList[i] );
    }
}

/**
 * @param the topic to collpase
 */
function collapseTopic( topic )
{
    var style = topic.el.style;
    if ( style.display != "none" )
        style.display = "none";
    
    // Toggle the open image
    topic.img.src = "open.gif"
    
}
    
// Helper functions that should be in the Workshop
//

/**
 * Get the main tabular data frame or this window if
 * we're not using frames.
 */
function getTabularWindow()
{
    // Refer to the main document through the parent, if
    // there is one.
    if ( parent != null && parent.mainFrame != null )
        return parent.mainFrame;
    else
        return this;
}

/**
 * Just get an element and return it
 */
function getTabularElement( id )
{
    // Refer to the main document through the parent, if
    // there is one.
    var doc = getTabularWindow().document;
    
    if ( doc.all != null ){
        return doc.all( id );
    } else if ( doc.getElementById != null ){
        return doc.getElementById( id );
    }
}

/**
 * Show a memo as a result of a mouse click on a list
 */ 
function onLocate( atomHandle, rowHandle, bScrollIntoView )
{
    if ( arguments.length < 2 )
        rowHandle = atomHandle;
    if ( arguments.length < 3 )
        bScrollIntoView = false;
    selectRow( rowHandle, bScrollIntoView );  
    locateAtomByHandle( atomHandle );
    justShowMemo( atomHandle, false );
	return false;
}


/**
 * Get the html of a memo from an html document and set
 * it into the memo region of the document.
 */
function justShowMemo( atomHandle )
{
    //not used axv043000
    return;
	if ( ! gEnableMemos )
        return;

    var fileText = readExternalFile( "./memos/" + atomHandle + ".html" );
    var memoRegion = getTabularElement( "memoRegion" );
    memoRegion.innerHTML = (fileText == null) 
        ? "No information is available for the selected item." 
        : fileText;
}

/**
 * Show or hide the help window
 * 
 * @param show is true to show help, false to hide it
 */
function showHelp( show )
{
    hideInfoWindows();
    
    // Show or hide the about window as appropriate
    var elem = getTabularElement( "help_window" );
	if ( elem && elem.style ){
        if ( show ){
            var text_elem = getTabularElement( "helpText" );
            text_elem.innerHTML = readExternalFile( "HelpText.html" );
            elem.style.visibility = "visible";
            collapseAllTopics();
        } else {
            restoreLastTopic();
        }
    }
    
    return false;
}

/**
 * Show or hide the about window
 * 
 * @param show is true to show help, false to hide it
 */
function showAbout( show )
{
    hideInfoWindows();
    
    // Show or hide the about window as appropriate
    var elem = getTabularElement( "about_window" );
	if ( elem && elem.style ){
        if ( show ){
            var text_elem = getTabularElement( "aboutText" );
            text_elem.innerHTML = readExternalFile( "AboutText.html" );
            elem.style.visibility = "visible";
            
            collapseAllTopics();
        } else {
            restoreLastTopic();
        }
    }
    
    return false;
}
 
/**
 * Hide an information window such as help or about.
 */
function hideInfoWindows()
{
    var elem = getTabularElement( "about_window" );
	if ( elem && elem.style )
        elem.style.visibility = "hidden"
    elem = getTabularElement( "help_window" );
	if ( elem && elem.style )
        elem.style.visibility = "hidden"
}

/**
 * Read an external document return it as text.
 * 
 * @parm fileURL
 * @return the text contents of the file
 */
function readExternalFile( fileURL )
{
    var requester = getFileLoader();
    if ( ! requester )
        return null;
    
    try {
        
        requester.open("GET", fileURL, false); 
        requester.send(null);
        
        if ( requester.status <= 200 )
            return requester.responseText;
        
    } catch( e3 ) {
        // Ignore these errors
        // showDebugException( "Error loading document: " + fileURL, e );
    }
    
    return null;
}

/**
 * Make an item selected in the Locator visible in an HTML 
 * list.
 * Note: this function overrides the function of the same name
 *       in venueFuncs.js.  That function assumes a scrolling div,
 *       this one a selection list box.
 *
 * @param key, the handle of the item to find.
 * @param bScrollIntoView, a flag telling whether to make sure it's visible
 */
function selectRow( key, bScrollIntoView )
{
    // Unselect the current selection
    if ( gLastSelection != null ){
        gLastSelection.className = "categoryItem";
    }

    var targetElement = getTabularElement( "h" + key );
    if ( targetElement != null ){
        
        // Walk up the DOM tree until we find the 'topic'
        // container so we can make the section visible        
        var node = targetElement.parentNode;
        while( node ){
            if ( node.className == "topic" ){
                showTopic( node.id );
                break;
            }
            node = node.parentNode;
        }
        
        // Highlight the item
        targetElement.className = "selectedCategoryItem";
        gLastSelection = targetElement;

        if ( bScrollIntoView && (typeof targetElement.scrollIntoView != "undefined")){
            targetElement.scrollIntoView();
        }

    } else {
        gLastSelection = null;
    }

}

/**
 * Make a row move visible by changing it's style or restore
 * it's default style
 */
function highlightRow( elem, highlight )
{
    if ( elem ) {
        if ( highlight )
            elem.className = "categoryItemHover"; 
        else if (elem == gLastSelection) 
            elem.className = "selectedCategoryItem";
        else
            elem.className = "categoryItem";
    }
    return false;
}

/**
 * Show an alert if the debug flag is true
 */
function showDebugAlert( o )
{
    if ( gDebug )
        alert( o );
}

/**
 * Display an exception in an alert box

function showDebugException( msg, e )
{
    showDebugAlert( msg + "\n" + e.name + "\n" + e.message );
}

/**
 * Determine whether the display field of an object's style
 * is *not* set to 'none'.  If display is set to 'none' the object
 * is not displayed.
 */
function isItemDisplayed( item )
{
    return (item.style.display != "none") &&
           (item.style.display != "");
}

/**
 * Check to see if the category has been loaded.  If not,
 * go get it.
 * This function makes an asynchronous request for the object.
 * The callback function is responsible for stuffing the text
 * returned from the file into the html element.
 *
 * @parm topic to be loaded from a file.
 */
function loadTopicFromFile( topic )
{
    try {
        if ( topic.loaded )
            return;
        
        topic.el.innerHTML = "Please wait while the list loads ...";
        
        // Create the request object and event handler
        topic.requester = getFileLoader();
        topic.requester.onreadystatechange = function()
        {
            onTopicLoadCallback( eval( "\"" + topic.id + "\"" ) );
        };

        // Send the request
        topic.requester.open("GET", topic.id + ".html", true); 
        topic.requester.send(null);
        
    } catch( e ) {
        /* showDebugException(null); */
	   }
}

/**
 * Initialize what can only be done after the HTML document
 * has loaded fully.  We are called by the body's onLoad()
 * function.
 */
function customInit()
{
    // Set the element object that holds each topic into
    // out object array for easy retrieval later.
    //
    for( var i=0; i<gTopicList.length; i++ ){
        var topic = gTopicList[i];

        topic.el = getTabularElement( topic.id );
        topic.img = getTabularElement( topic.id + "HeadImage" );
        
        // Store the object by id as well for easy lookup
        gTopicList[ topic.id ] = topic;
        
        // Now, start the topic loading, if necessary
        setTimeout( "loadTopicFromFile( gTopicList[" + i + "] )", 3000 );
    }
    
    // Do the global init()
    //
    init();
}

/**
 * Create an XMLHttpRequestObject based on the 
 * file url passed into the constructor.
 */
function getFileLoader()
{
    var req = null;
    
    if (window.XMLHttpRequest){
        // Mozilla version...
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject){
        // Microsoft version...
        try{ 
            req = new ActiveXObject("Microsoft.XMLHTTP");
        } catch( e ) {
            return null;
        }
    }
    
    return req;
}

/**
 * Respond to a state change by a topic loader.
 * XMLHttpRequest readyState values:
 * 0 = uninitialized
 * 1 = loading
 * 2 = loaded
 * 3 = interactive
 * 4 = complete
 */
function onTopicLoadCallback( id )
{
    try {
        // Look up the topic
        var topic = gTopicList[ id ];
        if ( ! topic )
            return; // not found
        
        if ( topic.requester.readyState != 4 )
            return; // not finished
        
        // We only get here if the job is complete, whether
        // it succeeded of failed.
        // Status code should be 200 if the file is on an HTTP
        // server and 0 if it's on the local file system.
        //
        topic.el.innerHTML = ( topic.requester.status <= 200 ) ?
             topic.requester.responseText :
             "Load failed.";

        // Release the requester
        topic.requester = null;
        topic.loaded = true;
   } catch( e ) {
        showDebugException( "onTopicLoadCallback error: ", e );   
    }
}

/**
 * Generic click processor that must process the event only if
 * the click took place on a list item with a handle.  In that
 * case, the click is processed by the onLocate() function.
 */
function onRowClick(evt)
{
    var el = getElementFromEvent(evt);
    if (!el)
        return;
    
    // Get the atom handle stored in the id
    var id = el.id;
    while (id == null || id.length == 0){
        el = el.parentNode;
        id = el.id ? el.id : null;
    }
    if ( id == null )
        return;

    // Is there an h indicating it's a handle?
    if ( id.charAt(0) == 'h' )
        id = id.substring(1);
    
    // If it's not a number, ignore it
    if ( isNaN( parseInt(id) ) ) 
        return;
    
    // OK, now do something useful with it
    onLocate(id);
}

/**
 * Generic mouse out processor that must process the event only if
 * the event took place on a list item with a handle.  In that
 * case, the event is processed by the appropriate function.
 */
function onRowEnter(evt)
{
    var elem = getCategoryItemFromEvent(evt);
    if (!elem)
        return;
    
    // Set the item's style to "hover"
    elem.className = "categoryItemHover";
}

/**
 * Generic mouse out processor that must process the event only if
 * the event took place on a list item with a handle.  In that
 * case, the event is processed by the appropriate function.
 */
function onRowExit(evt)
{
    var elem = getCategoryItemFromEvent(evt);
    if (!elem)
        return;
    
    // Set the item's style to a normal item, or the selected item
    // if this is the chosen one.
    elem.className = (elem == gLastSelection) ? 
        "selectedCategoryItem" :
        "categoryItem";
}

/**
 * Find the category item for the current event.
 */
function getCategoryItemFromEvent(evt)
{
    var elem = getElementFromEvent(evt);
    
    // Find the category item in the item's lineage
    while ( elem && 
            elem.className != "selectedCategoryItem" && 
            elem.className != "categoryItem" && 
            elem.className != "categoryItemHover" ){
        elem = elem.parentNode;
    }
    return elem;
}

/**
 * Get the event in a cross-browser way
 */
function getEvent(evt)
{
    return evt ? evt : (event ? event : null);
}

/**
 * Get the target element from an event
 */
function getElementFromEvent(evt)
{
    // Get the event object in a cross browser way
    evt = getEvent(evt);
    if (evt){
        // Get the object clicked on
        return evt.target ? evt.target : 
                    (evt.srcElement ? evt.srcElement : null );
    }
    
    return null;
}

/**
 * Process a keystroke anywhere in the document.
 * If the keystroke is a scroll command (up, dn, pg up, pg dn)
 * scroll the active window.
 */
function processKeyPress(evt)
{
    // Get the row element
    var elem = gLastSelection;

    while (elem && elem.nodeName != "p"){  //used to be TR
        elem = elem.parentNode;
    }
    if (!elem)
        return;
    
    // Get the next TR in line
    elem = elem.nextSibling;
    while (elem && elem.nodeName != "p"){ //used to be TR
        elem = elem.nextSibling;
    }
    if (!elem)
        return;

    // Descend to the cell
    elem = elem.firstChild;
    
    outer:
    while ( elem && 
            elem.className != "selectedCategoryItem" && 
            elem.className != "categoryItem" && 
            elem.className != "categoryItemHover" ){
        while ( elem && elem.nodeType != 1 ){ // html elements only!
            elem = elem.nextSibling;
            continue outer;
        }
            
        elem = elem.firstChild;
    }
    if (!elem)
        return;

    var id = elem.id;
    
    // Is there an h indicating it's a handle?
    if ( id.charAt(0) == 'h' )
        id = id.substring(1);
    
    // If it's not a number, ignore it
    if ( isNaN( parseInt(id) ) ) 
        return;
    
    // OK, now do something useful with it
    onLocate(id);
    //elem.scrollIntoView();  
    
    // Stop further processing
    evt = getEvent(evt);
    if (evt){
        evt.cancelBubble = true;
        /***
        showDebugAlert( "keyCode: " + evt.keyCode +
               "\ncharCode: " + evt.charCode );
        ***/
    }
   
}

/**
 * A "null" function that does nothing.  It provides a place-
 * holder for the action in a form when the "action" is invoked
 * by the key handler
 */
function doNothing()
{
    /** Do nothing **/
}