// COPYRIGHT (c) 2006 Mixon/Hill, Inc., ALL RIGHTS RESERVED.
//-----------------------------------------------------------
// Utils.js 
//      Contains utility code that is used throughout the system.
//-----------------------------------------------------------

var nUserTypeId;

var sDefaultColor;


// The maximum length of a text message is 100 characters,
// which is based on 160-character maximum for SMS minus
// the 60-character header.
// The header looks like this:
//    TO: ##########@sprint.pcs.com
//    FROM: www.kcscout.net
//    BODY: 
// Note that I have counted 2 characters after each line for CR/LF.
// Also note that this may need to be lowered, since some providers
// may have a longer email address.
var nTxtMsgMaxLength = 100;
var nTxtMsgOtherDataLength = 0;


function GetInitialStyle(oElement)
{
    if (oElement.currentStyle)
    {
        // IE stuff
        sDefaultColor = oElement.currentStyle["color"];
    }
    else if (window.getComputedStyle)
    {
        // FF stuff
        sDefaultColor = document.defaultView.getComputedStyle(oElement, null).getPropertyValue("color");
    }
}



//-----------------------------------------------------------
// Debug()
//      Prints a debugging message.
//-----------------------------------------------------------
function Debug(sMsg)
{
    alert("-- DEBUG --\n" + sMsg);
}

//-----------------------------------------------------------
// CheckSecurity()
//      Checks the Credentials object stored on the web server
//      to see if the user is logged in during this session.
//      If the user is logged in, then allow them to continue.
//      If the user is not logged in, then redirect them back to the Login page.
//-----------------------------------------------------------
function CheckSecurity(nGetKey)
{
    // Create the XmlHttpRequest object and send the request to the database
    var oXmlRequest = new XmlRequest();

    // Passing in a 1 makes CheckSecurity.jsp pass back the password.
    // This minimizes the number of times we are passing a 64-bit hash key around.
    if (nGetKey == 1)
    {
        oXmlRequest.addParameter("getKey", "1");
    }

    oXmlRequest.getXml("CheckSecurity.jsp", cbInitPageCode);
}


//-----------------------------------------------------------
// VerifyCredentials()
//      Called from cbInitPageCode() to continue processing
//      when the XML call returns.
//      This checks the credentials to make sure the user
//      is supposed to be viewing this page.
//      Finally, this calls BuildMenu() to create the tabstrip
//      across the top of the page, and any sublinks that the
//      user might get.
//-----------------------------------------------------------
function VerifyCredentials(oXml, sCurrentTab, sRedirectPage)
{
    var oResult = oXml.documentElement;
    nUserTypeId = oResult.getAttribute("userTypeId");
    var sErrMsg = oResult.getAttribute("errMsg");
    var bCanContinue;

    if (nUserTypeId == null || nUserTypeId == 0)
    {
        alert(sErrMsg + "\nTo continue, please login again.");
        
        // If we are on a popup page (as denoted by the empty sCurrentTab)
        // then we need to close the popup window.
        if (sCurrentTab == "")
        {
            var sCall = "ClosePopup(\"" + sRedirectPage + "\")";
            setTimeout(sCall, 100);
        }
        else
        {
            document.location = sRedirectPage;
        }
        bCanContinue = false;
    }
    else
    {
        bCanContinue = true;
        // CheckSecurity() and VerifyCredentials() can be called from
        // top-level pages with the tabs, as well as Add/Edit pages
        // without the tabs.
        // Therefore, each page has to tell us whether or not to
        // build the tabs.  If no tabs are needed for the page, then
        // sCurrentTab should be empty.
        if (sCurrentTab != "")
        {
            BuildMenu(sCurrentTab);
        }
    }
    
    return(bCanContinue);
}


//-----------------------------------------------------------
// ClosePopup()
//      Close the popup window and go back to the Login page.
//-----------------------------------------------------------
function ClosePopup(sRedirectPage)
{
    if (opener != null)
        opener.window.location = sRedirectPage;
    else
        window.location = sRedirectPage;
    window.close();
}

//-----------------------------------------------------------
// BuildMenu()
//      Builds the menu for the user.
//      Administrators get 4 tabs, Operators get 2 tabs.
//      All others get redirected to the Subscriber Login page.
//-----------------------------------------------------------
function BuildMenu(sCurrentTab)
{
    var sTargetURL;

    if (nUserTypeId == 1 || nUserTypeId == 2)
    {
        // build tabs
        var oTabMenu = document.createElement("ul");
        oTabMenu.appendChild(BuildMenuItem("EventsAlerts.html", "Events &", "Alerts", sCurrentTab));

        if (nUserTypeId == 1)
        {
            sTargetURL = "Orgs.html";
        }
        else
        {
            sTargetURL = "MyProfile.html";
        }

        oTabMenu.appendChild(BuildMenuItem(sTargetURL, "Application", "Configuration", sCurrentTab));

        if (nUserTypeId == 1)
        {
            oTabMenu.appendChild(BuildMenuItem("UserMgmt.html", "User/Security", "Management", sCurrentTab));
            oTabMenu.appendChild(BuildMenuItem("SubMgmt.html", "Subscriber", "Management", sCurrentTab));
            oTabMenu.appendChild(BuildMenuItem("PendingUsers.html", "Pending", "Users", sCurrentTab));
        }
      
        // create the logoff link
        var oLogOff = document.createElement("a");
        oLogOff.id = "logoff";
        oLogOff.href = "Logoff.html";
        oLogOff.appendChild(document.createTextNode("Log Off"));

        // create the log off container div
        var oDiv = document.createElement("div");
        oDiv.id = "logHeader";
        oDiv.appendChild(oLogOff);

        //putting the div for the log off in the main tab div
        oTabMenu.appendChild(oDiv);

        // put the whole menu into the div on the page
        var oTabContainer = document.getElementById("tabstrip")
        oTabContainer.appendChild(oTabMenu);

        // Build the sublinks area.
        // If a page doesn't have a sublink, create an empty spot so
        // the page headline is in the proper place.
        BuildSubLinks2(sCurrentTab);
    }
    else if (nUserTypeId == 4)
    {
        BuildSubLinks2(sCurrentTab);
    }
}


//-----------------------------------------------------------
// BuildMenuItem()
//      Creates the actual list item for the tab.
//-----------------------------------------------------------
function BuildMenuItem(url, labelTop, labelBottom, sCurrentTab)
{
    var oListItem = document.createElement("li");
    var oAnchor = document.createElement("a");
    oAnchor.href = url;
    oAnchor.appendChild(document.createTextNode(labelTop));

    if (labelBottom != null || labelBottom.length > 0)
    {
      oAnchor.appendChild(document.createElement("br"));
      oAnchor.appendChild(document.createTextNode(labelBottom));
    }

    // If the tab we are building matches the name of the tab passed in,
    // then set it as the current tab so it is highlighted.
    if (labelTop == sCurrentTab)
    {
        oListItem.id = "current";
    }

    oListItem.appendChild(oAnchor);
    return oListItem;
}

//-----------------------------------------------------------
// BuildSubLinks2()
//      Builds the sublinks for the user as an unordered list.
//-----------------------------------------------------------
function BuildSubLinks2(sCurrentTab)
{
    var oSubLinkList;
    var sCurrentPage;
    var sPageTitle = document.title;

    // Appending to the unordered list
    oSubLinkList = document.getElementById("sublinklist");

    // Build the sublinks for the pages under the Application Configuration tab.
    // When building the links, don't create the href tag for the page we are on.
    // For example, assume the "Foo" tab has 3 pages under it: Bar, Stuff, and Whatever.
    // If we are on the "Bar" page, then we would show all pages, but the "Bar" link
    // would not be underlined.
    if (sCurrentTab == "Application")
    {
        // If the user is an Administrator, then create the
        // Organizations and Datafeeds links.
        if (nUserTypeId == 1)
        {   
            //determines what page the user is on
            if (sPageTitle == "Intermodal System: Organizations")
                sCurrentPage = "Organizations";
            else if (sPageTitle == "Intermodal System: Datafeeds")
                sCurrentPage = "Datafeeds";
            else if (sPageTitle == "Intermodal System: My Profile")
                sCurrentPage = "My Profile";
        }
      
        // Builds the "My Profile" link
        oSubLinkList.appendChild(BuildSubLinkItem("MyProfile.html", "My Profile", sCurrentPage));
      
        // Builds the other links if they are administrators (userTypeId = 1)
        if (nUserTypeId == 1)
        {
            oSubLinkList.appendChild(BuildSubLinkItem("none", "|", sCurrentTab));
            oSubLinkList.appendChild(BuildSubLinkItem("Orgs.html", "Organizations", sCurrentPage));
            oSubLinkList.appendChild(BuildSubLinkItem("none", "|", sCurrentTab));
            oSubLinkList.appendChild(BuildSubLinkItem("Datafeeds.html", "Datafeeds", sCurrentPage));
        }
    }

    // Build the sublinks for the pages under the User/Security Management tab.
    else if (sCurrentTab == "User/Security")
    {
        if (sPageTitle == "Intermodal System: User Management")
            sCurrentPage = "User Management";
        else if (sPageTitle == "Intermodal System: Group Management")
            sCurrentPage = "Group Management";
        
        oSubLinkList.appendChild(BuildSubLinkItem("UserMgmt.html", "User Management", sCurrentPage));
        oSubLinkList.appendChild(BuildSubLinkItem("none", "|", sCurrentTab));
        oSubLinkList.appendChild(BuildSubLinkItem("GroupMgmt.html", "Group Management", sCurrentPage));
    }

    // Build the sublinks for the Subscriber Home Page.
    else if (sCurrentTab == "SubHome" || sCurrentTab == "SubProfile")
    {
        if (sPageTitle == "My KC Scout: Subscriber Home Page")
            sCurrentPage = "Subscriptions";
        else
            sCurrentPage = "My Profile";

        oSubLinkList.appendChild(BuildSubLinkItem("SubHome.html", "Subscriptions", sCurrentPage));
        oSubLinkList.appendChild(BuildSubLinkItem("none", "|", sCurrentTab));
        oSubLinkList.appendChild(BuildSubLinkItem("SubProfile.html", "My Profile", sCurrentPage));
        oSubLinkList.appendChild(BuildSubLinkItem("none", "|", sCurrentTab));
        oSubLinkList.appendChild(BuildSubLinkItem("Logoff.html", "Log Off", sCurrentPage));
    }

    var oSubLinks = document.getElementById("sublinks")
    oSubLinks.appendChild(document.createTextNode("   "));
    oSubLinks.appendChild(oSubLinkList);
}

//-----------------------------------------------------------
// BuildSubLinkItem()
//      Creates the actual list item for the sublinks.
//-----------------------------------------------------------
function BuildSubLinkItem(url, label, sPageTitle)
{
    var oListItem = document.createElement("li");
    var oAnchor;

    // If the link we are building does not match the current page,
    // then it becomes a true link.  Otherwise, don't add the href
    // attribute.
    oAnchor = document.createElement("a");
    if (label != sPageTitle && label != "|")
    {
      //make a link
      oAnchor.href = url;
    }
    oAnchor.appendChild(document.createTextNode(label));

    oListItem.appendChild(oAnchor);
    return oListItem;
}


//-----------------------------------------------------------
// addEvent()
//      Adds an event listener to the document.
//      The Internet Explorer (IE) and FireFox (FF) Document Object Models
//      have different ways of handling events.  This routine
//      codes around those differences so that our code can
//      use a common function for handling an event.
//-----------------------------------------------------------
function addEvent(oObject, sEventType, cbCallback, bUseCapture)
{
    // See if the user is running FF
    if (oObject.addEventListener)
    {
        // Found FF
        oObject.addEventListener(sEventType, cbCallback, bUseCapture);
        return true;
    }

    // The user wasn't running FF, so check for IE
    else if (oObject.attachEvent)
    {
        // Found IE
        return oObject.attachEvent("on" + sEventType, cbCallback);
    }
    
    // The user is running a DOM that does not follow the IE or FF DOMs.
    // There is nothing else we can do.
    else
    {
        alert("Handler could not be attached");
    }
} 


//-----------------------------------------------------------
// removeEvent()
//      Removes an event listener from the document.
//      The Internet Explorer (IE) and FireFox (FF) Document Object Models
//      have different ways of handling events.  This routine
//      codes around those differences so that our code can
//      use a common function for handling an event.
//-----------------------------------------------------------
function removeEvent(oObject, sEventType, cbCallback, bUseCapture)
{
    // Look for FF
    if (oObject.removeEventListener)
    {
        // Found FF
        oObject.removeEventListener(sEventType, cbCallback, bUseCapture);
        return true;
    }
    
    // The user wasn't running FF, so check for IE 
    else if (oObject.detachEvent)
    {
        // Found IE
        return oObject.detachEvent("on" + sEventType, cbCallback);
    }
    
    // The user is running a DOM that does not follow the IE or FF DOMs.
    // There is nothing else we can do.
    else
    {
        alert("Handler could not be removed");
    }
} 


//-----------------------------------------------------------
// getEventSource()
//      Returns a reference to the object that received an event.
//      The Internet Explorer (IE) and FireFox (FF) Document Object Models
//      have different ways of handling events.  This routine
//      codes around those differences so that our code can
//      use a common function for handling an event.
//-----------------------------------------------------------
function getEventSource(oEvent)
{
    // Look for IE
    if (oEvent.srcElement)
    {
        // Found IE
        return oEvent.srcElement;
    }
    
    // Look for FF
    else
    {
        // Found FF
        return oEvent.target;
    }
}


//-----------------------------------------------------------
// NumbersOnly()
//      Ensures the user can only enter numbers.
//      Used for the onKeyPress callback function in an HTML file.
//-----------------------------------------------------------
function NumbersOnly(myfield, e)
{
    var key;
    var keychar;

    if (window.event)
        key = window.event.keyCode;
    else if (e)
        key = e.which;
    else
        return true;

    // Calls the appropriate function if the user hits Enter
    keychar = String.fromCharCode(key);

    // Control keys
    if ((key==null) || (key==0) || (key==8) || (key==9) || (key==27) )
        return true;

    // Allowable characters
    else if ((("0123456789-.").indexOf(keychar) > -1))
        return true;

    else
        return false;
}


//-----------------------------------------------------------
// DigitsOnly()
//      Ensures the user can only enter numbers.
//      Used for the onKeyPress callback function in an HTML file.
//      NOTE: This is the same as NumbersOnly(), except it doesn't allow
//      a decimal or a minus sign.
//-----------------------------------------------------------
function DigitsOnly(myfield, e)
{
    var key;
    var keychar;

    if (window.event)
        key = window.event.keyCode;
    else if (e)
        key = e.which;
    else
        return true;

    // Calls the appropriate function if the user hits Enter
    keychar = String.fromCharCode(key);

    // Control keys
    if ((key==null) || (key==0) || (key==8) || (key==9) || (key==27) )
        return true;

    // Allowable characters
    else if ((("0123456789").indexOf(keychar) > -1))
        return true;

    else
        return false;
}

//-----------------------------------------------------------
// DateCharsOnly()
//      Ensures the user can only enter numbers and the "/".
//      Used for the onKeyPress callback function in an HTML file.
//-----------------------------------------------------------
function DateCharsOnly(myfield, e)
{
    var key;
    var keychar;

    if (window.event)
        key = window.event.keyCode;
    else if (e)
        key = e.which;
    else
        return true;

    // Calls the appropriate function if the user hits Enter
    keychar = String.fromCharCode(key);

    // Control keys
    if ((key==null) || (key==0) || (key==8) || (key==9) || (key==27) )
        return true;

    // Allowable characters
    else if ((("0123456789/").indexOf(keychar) > -1))
        return true;

    else
        return false;
}


//-----------------------------------------------------------
// fillDataField()
//      Fills the data field on the HTML page with the data passed in.
//-----------------------------------------------------------
function fillDataField(sElement, sData)
{
    var oField = document.getElementById(sElement);
    if (sData == null || sData == "")
    {
        oField.value = "";
    }
    else
    {
        oField.value = sData;
    }
}


//-----------------------------------------------------------
// FindInList()
//      Given a list of data items returned via XML, this
//      function will walk the list and return the ID for that item.
//      Parameters:
//          oList           The list of items
//          sFind           The item we want found
//          sFindAttr       The attribute in which to look
//          sGetAttr        The attribute to return
//-----------------------------------------------------------
function FindInList(oList, sFind, sFindAttr, sGetAttr)
{
    var oItem;
    for (var i = 0; i < oList.length; i++)
    {
        oItem = oList[i];
        if (oItem.getAttribute(sFindAttr) == sFind)
        {
            return(oItem.getAttribute(sGetAttr));
        }
    }
    
    // Couldn't find the target in the list.
    return("");
}


//-----------------------------------------------------------
// UpdateTxtMsgCount()
//      Counts the characters in the TxtMsg description TEXTAREA
//      and updates the display.
//-----------------------------------------------------------
function UpdateTxtMsgCount()
{
    var oTxtMsgDesc = document.getElementById("txtmsgdesc");
    var oCharCount = document.getElementById("chars");
    var nCharsLeft = (nTxtMsgMaxLength - oTxtMsgDesc.value.length - nTxtMsgOtherDataLength);
    oCharCount.firstChild.data = "Characters Left: " + nCharsLeft;

    // If the length of the text message is greater than the maximum length
    // allowed, change the color of the font to some sort of red.
    if (nCharsLeft < 0)
    {
        oCharCount.style.color = "#E03030";
        oCharCount.style.fontWeight = "bolder";
    }
    else
    {
        oCharCount.style.fontWeight = "normal";
        oCharCount.style.color = sDefaultColor;
    }
}


//-----------------------------------------------------------
// GetTxtMsgMax()
//      Returns the maximum length of a Text Message.
//-----------------------------------------------------------
function GetTxtMsgMax()
{
    return(nTxtMsgMaxLength);
}


//-----------------------------------------------------------
// SetTxtMsgOtherDataLength()
//      Sets the length of any other data that will be part of the
//      Text Message, but which isn't in the Text Message Description box.
//-----------------------------------------------------------
function SetTxtMsgOtherDataLength(nLength)
{
    nTxtMsgOtherDataLength = nLength;
}


//-----------------------------------------------------------
// StartClock()
//      Formats the timestamp for the clock in the KC Scout roadway.
//      Note: The clock is displayed both for the Intermodal System
//            consoles as well as the Subscriber pages.  On the Subscriber
//            pages, the drive time ("Morning", "Afternoon", etc.) is
//            displayed under the timestamp.
//-----------------------------------------------------------
function StartClock()
{
    var oDate = new Date();
    var nHour = oDate.getHours()
    var nMins = oDate.getMinutes()
    var nSecs = oDate.getSeconds()
    var aDay = new Array("Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, ");
    var aMonth = new Array("Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec ");
    var sAMPM;

    // Establish the drive time message
    var oBold = document.getElementById("drivetime");
    if (oBold != null)
    {
        var sDriveTime;
        if ((nHour >= 1) && (nHour <=5))
          sDriveTime = "The Early Morning Update";

        else if ((nHour >= 6) && (nHour <=11))
          sDriveTime = "Your Morning Commute";

        else if ((nHour >= 12) && (nHour <=16))
          sDriveTime = "Afternoon Drive Time";

        else if ((nHour >= 17) && (nHour <=19))
          sDriveTime = "The Evening Rush";

        else if ((nHour >= 20) && (nHour <=23))
          sDriveTime = "Late Night Drive";

        else if (nHour == 0)
          sDriveTime = "The Late Shift";
        
        var oBold = document.getElementById("drivetime");
        oBold.firstChild.data = sDriveTime;
    }

    
    // Add a zero in front of numbers < 10
    if (nMins < 10)
        nMins = "0" + nMins;
    
    var oClockTxt = document.getElementById("timestamp");

    if (nHour < 12)
        sAMPM = " AM, ";
    else
    {
        if (nHour != 12)
            nHour -= 12;
        sAMPM = " PM, ";
    }

    var sClock = nHour + ":" + nMins + sAMPM + aDay[oDate.getDay()] + 
                 aMonth[oDate.getMonth()] + GetOrdinal(oDate.getDate()) + ", " +
                 oDate.getFullYear() + ", CST";

    oClockTxt.firstChild.data = sClock;

    // Wake up at the next minute.
    setTimeout(StartClock, (1000 * (60 - nSecs)));

    if (document.tableRefresher)
        document.tableRefresher();
}


//-----------------------------------------------------------
// GetOrdinal()
//      Given a date, return its ordinal.
//-----------------------------------------------------------
function GetOrdinal(nDate)
{
    var sOrdinal;
    switch (nDate)
    {
        case 1:
        case 21:
        case 31:
            sOrdinal = nDate + "st";
            break;

        case 2:
        case 22:
            sOrdinal = nDate + "nd";
            break;

        case 3:
        case 23:
            sOrdinal = nDate + "rd";
            break;

        default:
            sOrdinal = nDate + "th";
            break;
    }
    
    return(sOrdinal);
}


//-----------------------------------------------------------
// ListboxInsertItem()
//      Inserts an item into a listbox (SELECT object).
//      Returns the OPTION object to the caller so extra data can
//      be added to it, if necessary.
//-----------------------------------------------------------
function ListboxInsertItem(oList, sText, sValue)
{
    var oEntry = document.createElement("option");
    oEntry.appendChild(document.createTextNode(sText));
    oEntry.value = sValue;
    oList.appendChild(oEntry);
    return(oEntry);
}


//-----------------------------------------------------------
// ListboxRemoveSelected()
//      Remove selected items from a listbox.
//-----------------------------------------------------------
function ListboxRemoveSelected(oList)
{
    for (var i = oList.childNodes.length; i > 0; i--)
    {
        oEntry = oList.childNodes.item(i - 1);
        if (oEntry.selected)
        {
            oList.removeChild(oEntry);
        }
    }
}


//-----------------------------------------------------------
// ListboxRemoveAll()
//      Removes all items in a list box.
//-----------------------------------------------------------
function ListboxRemoveAll(oList)
{
    while (oList.childNodes.length > 0)
    {
        oList.removeChild(oList.lastChild);
    }
}


//-----------------------------------------------------------
// ListboxRemoveItem()
//      Removes a given item in a list box.
//-----------------------------------------------------------
function ListboxRemoveItem(oList, nIndex)
{
    oList.remove(nIndex);
}


//-----------------------------------------------------------
// ListboxSelectItem()
//      Walks the items in a listbox and selects the entry that matches sTarget.
//      If bCheckValue is true, then it checks the value.
//      If bCheckValue is false, then it checks the text entry.
//-----------------------------------------------------------
function ListboxSelectItem(oList, sTarget, bCheckValue)
{
    for (var i = 0; i < oList.childNodes.length; i++)
    {
        // Debug("Checking " + sTarget + " against " + oList.childNodes.item(i).value + " / " + oList.childNodes.item(i).text);
        if (bCheckValue)
        {
            // Internet Explorer seems to choke sometimes
            // when selecting the item.  It appears to be a timing issue,
            // so putting it in a try block seems to resolve it.
            if (oList.childNodes.item(i).value == sTarget)
            {
                try
                {
                    oList.childNodes.item(i).selected = true;
                    break;
                }
                catch(oErr)
                {
                    // Debug("Could not set item #" + i + " in listbox " + oList.name);
                    // break;
                }
            }
        }
        else
        {
            if (oList.childNodes.item(i).text == sTarget)
            {
                try
                {
                    oList.childNodes.item(i).selected = true;
                    break;
                }
                catch(oErr)
                {
                    // Debug("Could not set item #" + i + " in listbox " + oList.name);
                    // break;
                }
            }
        }
    }
}

//-----------------------------------------------------------
// ListboxTossSelected()
//      Toss selected items from one list to another.
//-----------------------------------------------------------
function ListboxTossSelected(oListFrom, oListTo)
{
    // Copy selected items from the ListFrom to the ListTo.
    var bFound;
    var oEntryFrom;
    for (var iFrom = 0; iFrom < oListFrom.childNodes.length; iFrom++)
    {
        oEntryFrom = oListFrom.childNodes.item(iFrom);
        if (oEntryFrom.selected)
        {
            // Search the To list to see if the item is already in there.
            bFound = false;
            for (var iTo = 0; iTo < oListTo.childNodes.length; iTo++)
            {
                if (oListTo.childNodes.item(iTo).value == oEntryFrom.value)
                {
                    bFound = true;
                    break;
                }
            }
            
            // Add the item to the To list if it isn't in there.
            if (!bFound)
            {
                ListboxInsertItem(oListTo, oEntryFrom.firstChild.data, oEntryFrom.value);
            }
        }
    }
}


//-----------------------------------------------------------
// ListboxSelectedText()
//      Get the string associated with the selected item in a listbox.
//      NOTE: Only works with a single-select listbox.
//-----------------------------------------------------------
function ListboxSelectedText(oList)
{
    if (oList.item(oList.selectedIndex).childNodes.length != 0)
        return(oList.item(oList.selectedIndex).firstChild.data);
    else
        return("");
}


//-----------------------------------------------------------
// FillTimeListbox()
//      Fills a listbox that holds time values.
//-----------------------------------------------------------
function FillTimeListbox(oList, bSelectTime)
{
    var sTime;
    var sMin;
    var sHour;
    var sMilTime;
    var iTempHour;
    var sAMPM;
    
    var oDate = new Date();
    var nHourNow = oDate.getHours()
    var nMinsNow = oDate.getMinutes()
    
    ListboxInsertItem(oList, "(Not specified)", "");

    for (var iHour = 0; iHour < 24; iHour++)
    {
        for (var iMin = 0; iMin < 60; iMin += 5)
        {
            // Specify morning or afternoon
            if (iHour < 12)
                sAMPM = " AM";
            else
                sAMPM = " PM";
            
            // Convert from "military" time to "civilian" time.
            iTempHour = iHour;
            if (iHour > 12)
                iTempHour = iHour - 12;

            sHour = iTempHour;

            // Pad out the minutes with a 0.
            if (iMin < 10)
                sMin = "0" + iMin;
            else
                sMin = iMin;
            
            sTime = sHour + ":" + sMin + sAMPM;
            
            // Store the military time as the value so it can be used to generate
            // a DATETIME field for the database.
            sMilTime = iHour + ":" + sMin

            ListboxInsertItem(oList, sTime, sMilTime);
            
            // Select the current time, if directed.
            // Find the closest previous 5-minute interval.
            if (bSelectTime)
            {
                if (iHour == nHourNow)
                {
                    if (iMin <= nMinsNow)
                    {
                        oList.childNodes.item(oList.length - 1).selected = true;
                    }
                }
            }
        }
    }
}


//-----------------------------------------------------------
// GetDate()
//      Returns a date in MM/DD/YYYY format.  Specifying an
//      offset from "today" will give you that date.  For example,
//      specifying an offset of 1 will give tomorrow's date.
//-----------------------------------------------------------
function GetDate(nOffsetFromToday)
{
    var cDate = new Date();
    
    // Apply the offset
    cDate.setDate(cDate.getDate() + nOffsetFromToday);

    // Add 1 to the month because it is 0-based.
    var nMonth = cDate.getMonth() + 1;
    
    var sDate = nMonth + "/" + cDate.getDate() + "/" + cDate.getFullYear();
    return (sDate);
}


//-----------------------------------------------------------
// GetTime()
//      Returns a time in HH:MM:SS format.  Specifying any
//      offsets from "now" will give you that time.  For example,
//      specifying a MinutesOffset of 5 will give you the time in 5 minutes.
//-----------------------------------------------------------
function GetTime(nHoursOffset, nMinutesOffset, nSecondsOffset)
{
    var cDate = new Date();
    
    // Apply the offsets by converting them to milliseconds and adding
    // them to the time.
    var timeOffset = cDate.getTime() +
                     (nHoursOffset * 3600 * 1000) +
                     (nMinutesOffset * 60 * 1000) +
                     (nSecondsOffset * 1000);
    
    cDate.setTime(timeOffset);

    var sHours = cDate.getHours();
    var sMinutes = cDate.getMinutes();
    var sSeconds = cDate.getSeconds();

    if (sMinutes < 10)
        sMinutes = "0" + sMinutes;
    
    if (sSeconds < 10)
        sSeconds = "0" + sSeconds;
    
    var sTime = sHours + ":" + sMinutes + ":" + sSeconds;
    
    return (sTime);
}


//-----------------------------------------------------------
// TrimString()
//      Removes spaces from the beginning and end of a string.
//-----------------------------------------------------------
function TrimString (sInput)
{
    while (sInput.charAt(0) == ' ')
        sInput = sInput.substring(1);
  
    while (sInput.charAt(sInput.length - 1) == ' ')
        sInput = sInput.substring(0, sInput.length - 1);
    
  return sInput;
}


//-----------------------------------------------------------
// RemoveInnerSpaces()
//      Replaces 2 spaces with 1.
//-----------------------------------------------------------
function RemoveInnerSpaces(sInput)
{
    while (sInput.indexOf("  ") != -1)
        sInput = sInput.replace(/  /g, " ");
    return(sInput);
}


//-----------------------------------------------------------
// RemoveCRLF()
//      Removes CRLFs from a string.
//-----------------------------------------------------------
function RemoveCRLF(sInput)
{
    var sTemp;

    // Remove all Carriage Returns (0xD).
    // Note: IE puts the CRLF sequence in its text boxes.
    //       FF only puts the LF.
    if (sInput.indexOf("\r") != -1)
    {
        sTemp = sInput.split("\r");
        sInput = "";
        for (var i = 0; i < sTemp.length; i++)
            sInput += sTemp[i];
    }

    // Replace all Line Feeds (0xA) with a space.
    if (sInput.indexOf("\n") != -1)
    {
        sTemp = sInput.split("\n");
        sInput = "";
        for (var i = 0; i < sTemp.length; i++)
        {
            sInput += sTemp[i];
            
            // Add a space if this is not the last word in the array.
            if (i < (sTemp.length - 1))
                sInput += " ";
        }
    }
    
    return(sInput);
}


//-----------------------------------------------------------
// FormatStreetEntry()
//      Formats a street name with the directional prefix and suffix.
//-----------------------------------------------------------
function FormatStreetEntry(sPrefix, sStreet, sSuffix)
{
    var sRoute;

    if (sPrefix  == "")
        sRoute = "   ";
    else
    {
        sRoute = sPrefix;
        if (sRoute == "E")
            sRoute += " ";
    }

    sRoute += " " + sStreet;
    
    if (sSuffix != "")
        sRoute += " " + sSuffix;
    
    return sRoute;
}


//-----------------------------------------------------------
// XlatCRLF_BinToStr()
//      Translates CRLF characters to "0x0A" so that different
//      browsers and databases won't do anything funky with them.
//-----------------------------------------------------------
function XlatCRLF_BinToStr(sInput)
{
    var sOutput = "";
    
    // Remove all Carriage Returns (0xD) before converting the Line Feeds (0xA)
    if (sInput.indexOf("\r") != -1)
    {
        var sTemp = sInput.split("\r");
        sInput = "";
        for (var i = 0; i < sTemp.length; i++)
            sInput += sTemp[i];
    }

    if (sInput.indexOf("\n") != -1)
    {
        var sTemp = sInput.split("\n");
        for (var i = 0; i < sTemp.length; i++)
        {
            sOutput += sTemp[i];
            if (i < (sTemp.length - 1))
                sOutput += "0x0A";
        }
    }
    else
    {
        sOutput = sInput;
    }
    
    return(sOutput);
}


//-----------------------------------------------------------
// XlatCRLF_StrToBin()
//      Translates the "0x0A" sequence stored in the database
//      to "\n" for the textareas.
//-----------------------------------------------------------
function XlatCRLF_StrToBin(sInput)
{
    var sOutput = "";
    if (sInput.indexOf("0x0A") != -1)
    {
        var sTemp = sInput.split("0x0A");
        for (var i = 0; i < sTemp.length; i++)
        {
            sOutput += sTemp[i];
            if (i < (sTemp.length - 1))
                sOutput += "\n";
        }
    }
    else
    {
        sOutput = sInput;
    }
    
    return(sOutput);
}


function FillDirectionList(oDirList, sDirection, bPickSelected, sFirstEntryText)
{
    // Save the direction, if one is already selected.
    var sSelected = "";
    if (oDirList.selectedIndex != -1)
    {
        sSelected = oDirList.childNodes.item(oDirList.selectedIndex).text;
    }

    ListboxRemoveAll(oDirList);
    

    ListboxInsertItem(oDirList, sFirstEntryText, "-1");

    for (var i = 0; i < sDirection.length; i++)
    {
        if (sDirection.charAt(i) == "N")
            ListboxInsertItem(oDirList, "NB", 0);
        else if (sDirection.charAt(i) == "E")
            ListboxInsertItem(oDirList, "EB", 2);
        else if (sDirection.charAt(i) == "S")
            ListboxInsertItem(oDirList, "SB", 1);
        else if (sDirection.charAt(i) == "W")
            ListboxInsertItem(oDirList, "WB", 3);
    }
    
    // If the user already had a direction selected and the direction is to be selected,
    // then search the list to see if the selected direction
    // matches one of the direction.  If it does, then reselect it.
    if (bPickSelected)
        ListboxSelectItem(oDirList, sSelected, false);
}


function ComputeDataState()
{
    var sDataState = "";
    var oElement;
    var sValue;
    for (var i = 0; i < document.all.length; i++)
    {
        if (document.all(i).id != "")
        {
            oElement = document.all(i);
            
            if (oElement.type == "checkbox" || oElement.type == "radio")
                sValue = oElement.checked;
            else 
                sValue = oElement.value;
            
            if (document.all(i).value)
                sDataState += oElement.id + ":" + sValue + ",";
        }
    }
    return(sDataState);
}

