// 4/1/2010 *** General code for processing any of the pages.

// Global variables.
var clrClear = "#ffffff";       // white
var clrBlack = "#000000";       // black
var clrHighlight = "#eeeeaa";   // <--almost khaki (darker than cornsilk)
var clrMark = "#ffccaa";        // to mark changed fields
var clrGray = "#c0c0c0";        // to mark disabled fields
var clrGreen = "#005000";       // medium-dark green - eg radiobox title
var clrPale = "#fff8dc";        // cornsilk
var msgpw = "The password must be 6-30 alphanumeric characters, no spaces, case sensitive, with at least 1 digit and at least 1 letter.";
var emailmsg = "";
var TOGGLE_ON = "[+]";
var TOGGLE_OFF = "[-]";

// NOTE: The array siteWindows will be global but only 'per page'. Not known across pages.
// Used to collect the handles of pages this page opens.
var siteWindows = new Array();  

function showMessage(msg, louid) {
    // Write a message to a designated area on the page.
    // This is part of Greetings.
    var itm = document.getElementById("messagetarget"); // an h5 element
    if (itm) {
        // FF does not support innerText
        // IE does not support textContent
        // The cross-browser solution: set both.
        itm.innerText = msg;
        itm.textContent = msg;
    }
    
    // Also store away the logged-on-user's db personid.
    itm = document.getElementById("louid"); // hidden input element
    if (itm) {
        itm.value = louid;
    }
    return true;
}

function showmsgbox(msg) {
    // Show our msg in the pre-fab message box div.
    
    // Convert any \n strings to html line breaks.   
    msg = msg.replace(/\n/gi, "<br/>");
    
    var itm = document.getElementById("msgboxinfo");  // the <p> item
    itm.innerHTML = msg;
    
    itm = document.getElementById("msgbox"); // the <div> item
    if (itm) { 
        itm.className = "msgboxshow"; 
    }
}

function hidemsgbox(){
    var itm = document.getElementById("msgbox");
    if (itm) {
        itm.className = "msgboxhide";
    }
    return true;
}

function showworkbox() {
    // Show workbox to ask user for information.
    var box = document.getElementById("workbox"); 
    if (box){
        var cn = box.className;
        cn = cn.replace("workboxhide", "workboxshow");
        box.className = cn;
    }        
}

function hideworkbox(){
    // Hide the workbox. 
    var box = document.getElementById("workbox")
    if (box) { 
		var cn = box.className;
		cn = cn.replace("workboxshow", "workboxhide");
		box.className = cn;
    }
}

function validate_password (pstr) {
    // Check the format of the password for valid syntax.
    // See msgpw for description of rule.
    // example below from web, requires upper & lower case
    // var myregex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/;     
    // PROBLEMS re IE7: See REGEX NOTE in gatewaycode.js 
    
    // var myregex = /(?=.*\d)(?=.*[a-zA-Z]).{6,30}/;               // orig
    var myregex = /^(?=\S{6,30}$)(?=.*\d)(?=.*[a-zA-Z])\S{6,30}$/;  // new 
    
    return myregex.test(pstr);
}

function validate_email(estr){
    // Check the format of the email for valid syntax.
    var myregex = "";    
    var emsg1 = "The email must have no spaces and use the @ and . symbols in the format part1@part2.part3 \n";
    var emsg2 = "part1 has 1-30 alphanumeric characters or the + - . _ symbols.\n"
    var emsg3 = "part2 has 1-65 alphanumeric characters or the . - symbols.\n";
    var emsg4 = "part3 has 2-4 alphanumeric characters.\n";
    // emailmsg not used 1/20/2011 -- too wordy for err msg; maybe use for helper-mouseover text?
    //var emailmsg = emsg1 + emsg2 + emsg3 + emsg4; 
    
    /* ....... orig code
    // Original regex pattern did not work for IE7.
    var myregex = /^(?=\S{1,30}$)[A-z0-9+_-]{1,30}@[A-z0-9-]{1,65}[.][A-z]{2,4}/ ; 
    return myregex.test(estr); // orig
    .... end orig code */
    
    var pos_at = estr.indexOf("@");
    var pos_lastdot = estr.lastIndexOf(".");

    // Must minimally use the a@b.c format   === part1 @ part2 . part3 
    var p0fact = ( ( pos_at != -1 && pos_lastdot != -1 ) );

    var part1 = estr.substr(0,pos_at);                          // local part
    var part2 = estr.substr(pos_at+1, pos_lastdot-pos_at-1);    // domain 1
    var part3 = estr.substr(pos_lastdot+1);                     // domain 2
    
    // There are two kinds of lookahead assertions: positive and negative.
    // A postive assertion specifies that something does come next,
    // and a negative one specifies that something does not come next.
    // The syntax is (?=pattern) for positive assertions, and (?!pattern) for negative assertions.
    // For the following regex patterns, use 3 lookaheads:
    //    check length exclude spaces  ---  check good chars  ---  exclude bad chars
    
    myregex = /^(?=\S{1,30}$)(?=.*[\.A-z0-9+_-])(?!.*[^\.A-z0-9+_-])/;
    var p1fact = myregex.test(part1);
    
    myregex = /^(?=\S{1,65}$)(?=.*[A-z0-9-])(?!.*[^\.A-z0-9-])/;
    var p2fact = myregex.test(part2);
    
    myregex = /^(?=\S{2,4}$)(?=.*[A-z])(?!.*[^A-z])/;
    var p3fact = myregex.test(part3);
    
    var ans = p0fact && p1fact && p2fact && p3fact;
    return ans;
}

function hidePretty(theID) {
    // The field has been encrypted ('munged') before SUBMIT action.
    // This leaves dorky characters on display that confuse the user.
    // Answer: make the forecolor==backcolor to 'hide' the dorkiness.
    document.getElementById(theID).style.color = clrClear;
}

function fixHighlight(myid) {
    // Clear any highlight color indicating required-but-missing field.
    // But only clear if it has a real value entered.

    // the .Name field must be capitalized to work!
    //if (myid == "" || typeof myid.Name == "undefined") {
    if (myid == "" )    { return; }
    var myobj = document.getElementById(myid);
    if (!myobj)         { return; }

    switch(myobj.nodeName) {
        case "SELECT":      // a pull-down field.
            if (myobj.selectedIndex != 0) {   
                myobj.style.backgroundColor = clrClear;
            }
            break;
        case "INPUT":       // a user-entry textbox or file field.
            if ((myobj.type=='text' || myobj.type=='file') && myobj.value != ""){
                myobj.style.backgroundColor = clrClear;
            }
            break;
        case "TEXTAREA":    // a user-entry textarea field.
            if (myobj.value != ""){
                myobj.style.backgroundColor = clrClear;
            }
            break;
         default:
            break;
     }
}

function clearRadioErrorMark(ctlname, clr) {
    // Clear the error mark for the radio box group.
    // The arg ctlname is an ID
    if (typeof clr == "undefined") {
        clr = clrGreen;       // Set the default.
    }
    var docacc = document.getElementById(ctlname);
    docacc.style.color = clr;
}

function getRadioItem(ctlname) {
    // Get the value of the selected item from a group of radio buttons.
    // Return the string value, or null if nothing selected.
    var r;
    var chosen = "";
    var rdo = document.getElementsByName(ctlname);
    for (r = 0; r < rdo.length; r++) {
        if (rdo[r].checked) {
            chosen = rdo[r].value;
            break;
        }
    }
    return chosen;
}

function getCookieItems(theTask) {
    // Retrieve any cookies from a previous session and pre-fill those fields.
    var cookieArray = makeFieldArray(theTask);
    var myobj;
    var item;
    var c;
    
    for (c in cookieArray) {      // NOTE: Walks through the INDICES, not the items.
        item = getCookie(cookieArray[c]);
        if (item != null && item != "" ) {
            myobj = document.getElementById(cookieArray[c]); 
            if (myobj) { myobj.value = item; }
        }
    }
}

function getCookie(name){
    var cookievals = new Array();
    cookievals = document.cookie.split(";"); 
    var valUnmasked = "";       
    var c;
    
    for (c in cookievals) {
        var itmary = new Array();
        itmary = cookievals[c].split("=");
        var fixer = itmary[0].replace(" ", "");  // do 'trim' action
        if (fixer == name) {
            // The Cookie has been MASKED. Show normal form.
            valUnmasked = unconvertItem(itmary[1]);
            return valUnmasked;
        }
    }
    return null;
}

function setCookieItem(item, cookiename) {
    // Capture the arg entered in a cookie so it can be pre-filled at next session.
    // Arg 'item' is the htmlID and cookiename is the name to store the cookie as.
    var myobj = document.getElementById(item);
    var val = myobj.value;
    var valMasked = "";
    if (item == "callsign") {
        val = val.toUpperCase();
    }
    
    var expdate = new Date ();
    /*
    // "delete" a cookie by setting the expiry date to one second in the past.
    expdate.setTime ( expdate.getTime() - 1 );
    */
    
    expdate.setTime (expdate.getTime() + (24 * 60 * 60 * 1000 * 365));
    var expfact = ((expdate != null) ? "; expires=" + expdate.toGMTString() : "") + "; path=/";
    
    // doTask MASKS --ALL-- fields --> don't repeat.
    valMasked = val; // convertItem(val); 
    var dc = cookiename + "=" + valMasked + expfact;
    document.cookie = dc;
}

function upcase(theID) {
    // Upcase an input text field. The arg is an id attribute.
    // Used for callsign entry.
    var myobj = document.getElementById(theID);
    myobj.value = myobj.value.trim().toUpperCase();
}

function trimStr(theID) {
    // Trim an input text field. The arg is an id attribute.
    // Used (at least) for pw entry.
    var myobj = document.getElementById(theID);
    myobj.value = myobj.value.trim();
}

function maskValue(theID, which) {
    // For the form element given by the id, get the value
    // and do 'crypt' work before POST action.
    // Don't 'crypt' SELECT, Radio, checkbox, file, image...
    var itm = "";
    var ans = "";
    var status = false; // No action take on this item.
    itm = document.getElementById(theID);
    
    if (itm) {
        if ((itm.nodeName == "INPUT" && (itm.type == "text" || itm.type == "password"))  
                 || (itm.nodeName == "TEXTAREA")) {
            if (which == "mask") {
                ans = convertItem(itm.value);
            }
            else { // "unmask"
                ans = unconvertItem(itm.value);
            }
            
            itm.value = ans;
            status = true;
        }
    }
    return status;
}

function convertItem(item) {
	// Simple "encryption" masking. Both companion functions taken from web 4/28/2010.
	// Item is any string.
	
	var a = item; //escape(item); 
	var x = "`~!|\;'<>,?/"; //  symbols not used. Are some trouble: "  \ < > 
	var b = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]'{}@.%#$^&* ()-_=+:";  // letters to compare to
	var c = "zyx987wvutsr@(*&^$#:qpon}{mlk654jihg[]fedcb'aZYXW. +=_%-)VU321TSRQPONMLKJ0IHGFEDCBA";  // letter to change string to
	var d;
	var h;
	var i;
	var j = "";

	var f = a.length; 
	var e = 0; 
	var g = 1;

	while (e != f) { 			// loop through length of string
		d = a.substring(e,g);  	// get each letter
		h = b.indexOf(d); 		// find that letter in var b 
		i = c.charAt(h); 		// change it to the letter in var c 
		e++; 					// add one to var e 
		g++; 					// add one to var g 
		j += i; 				// write out each letter
	}
	
	//alert("converting: in=[" + item + "] out=[" + j + "]");  // debug
	return j; 
}

function unconvertItem(item) {
	// Simple "de-cryption" unmasking.
	// This must match the unconvertItem() in utility.php file.
	
	var aa = item;
	var bb = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]'{}@.%#$^&* ()-_=+:"; 
	var cc = "zyx987wvutsr@(*&^$#:qpon}{mlk654jihg[]fedcb'aZYXW. +=_%-)VU321TSRQPONMLKJ0IHGFEDCBA";
	var dd;
	var hh;
	var ii;
	var jj = "";

	var ff = aa.length;
	var ee = 0; 
	var gg = 1;

	while (ee != ff) { 
		dd = aa.substring(ee,gg);
		hh = cc.indexOf(dd); // just switch var b with c to unencode ex(h = b.indexOf(d); now  ='s hh = cc.indexOf(dd);)
		ii = bb.charAt(hh);  // just switch var c with b to unencode
		ee++;
		gg++;
		jj += ii;
	}
	//alert("un-converting: in=[" + item + "] out=[" + jj + "]");  // debug
	return jj;
}

function wordwrap (str, int_width, str_break, cut) {
    // Grabbed from web 1/11/2010
    // Wraps buffer to selected number of characters using string break char  
    // 
    // version: 909.322
    // discuss at: http://phpjs.org/functions/wordwrap    
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Nick Callen
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Sakimori    // +   bugfixed by: Michael Grier
    // *     example 1: wordwrap('Kevin van Zonneveld', 6, '|', true);
    // *     returns 1: 'Kevin |van |Zonnev|eld'
    // *     example 2: wordwrap('The quick brown fox jumped over the lazy dog.', 20, '\n');
    // *     returns 2: 'The quick brown fox \njumped over the lazy\n dog.'    
    // *     example 3: wordwrap('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.');
    // *     returns 3: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod \ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim \nveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea \ncommodo consequat.'
    // PHP Defaults
    var m = ((arguments.length >= 2) ? arguments[1] : 75   ); 
    var b = ((arguments.length >= 3) ? arguments[2] : "\n" ); 
    var c = ((arguments.length >= 4) ? arguments[3] : false);
 
    var i, j, l, s, r;
 
    str += ''; 
    if (m < 1) {
        return str;
    }
     for (i = -1, l = (r = str.split(/\r\n|\n|\r/)).length; ++i < l; r[i] += s) {
        for (s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : "")){
            j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
        }
    }    
    return r.join("\n");
}

function tellPWhelp(item, clickfact) {
    // Inform user of the password format rules in a tooltip or message box.
    if (clickfact == true) {
        showmsgbox(msgpw);
    }
    else {
        document.getElementById(item).title = msgpw;
    }
    return true;
}

function getXYPosition(e){
    // Cursor coordinate functions.
    // clientX and clientY are integers for pixel values.
    var myMouseX, myMouseY;
    myMouseX=(e||event).clientX;
    myMouseY=(e||event).clientY;
    if (document.documentElement.scrollTop > 0) {
        myMouseY = document.documentElement.scrollTop + myMouseY ;
    }
    
    // Put our info into a hidden field for retrieval.
    document.getElementById("apptaskxy").value = myMouseX + ":" + myMouseY ;
}

String.prototype.trim = function () {
    // Create trim function for javascript strings.
    // Copied from web.
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}

function disableEnterKey(e){
    // Example of use:
    // <input type="text" name="mytext" onKeyPress="return disableEnterKey(event)">
     var key;

     if (window.event) {
          key = window.event.keyCode;   //IE
     }
     else {
          key = e.which;                //firefox
     }

     if (key == 13) {
         return false;
     }
     else {
        return true;
     }
}

function makeEnterActLikeTab(e) {
    // Make Enter key tab to next field.
    // USE: <body onkeydown="makeEnterActLikeTab(event)" >
    // NOTE: IE makes a ding-sound when using Enter to advance to next field. Cannot find.
    var code = "";
        
    if (window.event) {         // Internet Explorer
        code = event.keyCode;
    }
    else {                      // Firefox
        code = e.which;
    }
    
    try {
        if (code == 9) { 
            return code;
        }
        
        var activeid = document.activeElement.id;
        if (code == 13 && activeid) {
        
            // Let user use ENTER to put line breaks in text areas (multiline).
            if (document.getElementById(activeid).type == "textarea") { return code; }
        
            // Find in our field array, and return the next element.
            // NOTE: The function findNextField is form-specific as it references field names.
            var nxt = findNextField(activeid);
            // Focus on this element, i.e., "TAB" forward.
            if (nxt != -1) {
                document.getElementById(nxt).focus();
            }
        }
    }
    catch (err) {
        // If a browser does not support activeElement, ignore.
        //alert("Trap: Probably due to no activeElement.");
    }
    
    var orig = code;
    if (code == 13) {
        code = 9;
    }
    //alert("orig=" + orig + "  new=" + code);  // debug
    return code;
}

function findNextField(oname) {
    // Arg oname is the id of a field, find its desired successor.
    var theForm = "";
    
    // Create array of ids of fields we want ENTER to "tab" through (with wrapping).
    if (document.URL.search("gateway.php") != -1) {
        // This document has more than one form.
        theForm = "personForm";
    }
    else if (document.URL.search("eqtracker.php") != -1) {
        theForm = "eqtracker"; // a fake: page has no form object
    }
    else {
        // Use the first/only form of the document.
        theForm = document.forms[0].id;
    }
    var fields = buildFieldArray(theForm);
                  
    var i = -1;
    var ans = -1;
    var len = fields.length;
    
    if (oname == fields[len - 1]) {
        // Revision 9/1/2010 to this "if" section.
        // NOTE: None of these Alts are used for Monthly Reports
        //       due to multiline/textarea treatment in makeEnterActLikeTab().
        
        // Alt-1: Last element so wrap: return the first element.
        //ans = fields[0];
        
        // Alt-2: Stay put in last field; do not "rotate".
        ans = oname;
        
        // Alt-3: Do nothing in code here.
        //  --> For Monthly Reports, Comments is last data-entry field.
        //          Be sure using ENTER inside comments field DOES NOT 
        //          immediately SUBMIT report!

    }
    else {
        for (f in fields) {
            i++;        // Tally the current array index.
            if (fields[f] == oname) {
                ans = fields[i + 1];
                break;
            }
        }
    }        
        
    return ans;
}

function buildFieldArray(whichform) {
    // whichform is an ID of a form
    // Array of ids of fields we want ENTER to "tab" through (with wrapping).
    // THESE SHOULD BE * ORDERED * FOR TABBING.
    // See utility.js: makeEnterActLikeTab() and findNextField()
    var fields = new Array();
    
    switch (whichform) {
        case "mailForm":
            fields[0] = "totalmembers";
            fields[1] = "change";
            fields[2] = "NetSessions";
            fields[3] = "NetLiaison";
            fields[4] = "Drills";
            fields[5] = "Drill_Mhrs";
            fields[6] = "PSEvents";
            fields[7] = "PS_Mhrs";
            fields[8] = "EmOps";
            fields[9] = "Em_Mhrs";
            fields[10] = "AresOps";
            fields[11] = "Ares_Mhrs";
            fields[12] = "Comments";
            //fields[13] = "submittask"; // omit 9/1/2010
            break;
        case "equipmentForm":
            fields = getEqFormFields();
            break;
        case "personForm":
            fields = getRegFormFields();
            break;
        case "eqtracker":
            // There are 2 different areas (not FORMS) on this page.
            fields = makeFieldArray('add','contact','all');
            fields = fields.concat(makeFieldArray('add','inventory','all'));
            break;            
    }
    
    return fields;
}

function reselectPulldown(boxid, theVal, theText) {
    // (Re)select the arg value "theVal" in the pulldown box "boxid"
    // Arg theVal is required. Arg theText is optional.
    var box = document.getElementById(boxid);
    var i;
    
    // Set the optional argument if needed.
    if (!theText) { theText = ""; }
    box.selectedIndex = 0;
    for (i = 0; i < box.options.length; i++){
        if ( (box.options[i].value == theVal) || (box.options[i].text == theText) ) {
            box.selectedIndex = i;
            box.disabled = "";  // enable since it has a value
            break;
        }
    } 
}

function pausecomp(millis) {
    // Do a wait-loop for given milliseconds of time.
    var date = new Date();
    var curDate = null;

    do { 
        curDate = new Date(); }
    while (curDate - date < millis);

    // Alternate code.
    //ms += new Date().getTime();
    //while (new Date() < ms) { }
} 

function playSound(soundObj) {
    // Play a sound that has been embedded in the page.
    // Example:
    //    <embed src="../support/ding.wav" autostart="false" width="0" height="0" id="errsound" type="audio/wav" enablejavascript="true">
    var sound = document.getElementById(soundObj);
    if (sound) {
        sound.Play();
    }
    else {
        // nothing.
    }
}

function clearForm(formid) {
    // Clear all the user-entry fields on the specified form.
    var frm = document.getElementById(formid);
    var x;
    var itm;
    var flds;
    
    if (frm) {
        //...............................
        flds = frm.getElementsByTagName("input");
        for (x in flds) {
            itm = document.getElementById(flds[x].id);
            if (itm) {
                itm.style.backgroundColor = clrClear;
                switch(itm.type) {
                    case "text":
                        itm.value = "";
                        break;
                    case "radio": 
                    case "checkbox":
                        itm.checked = false;
                        break;
                    default:
                        // Avoid making buttons look weird.
                        itm.style.backgroundColor = "";
                        break;    
                }
            }
        }
        //...............................
        flds = frm.getElementsByTagName("select");
        for (x in flds) {
            itm = document.getElementById(flds[x].id);
            if (itm) {
                itm.style.backgroundColor = clrClear;
                itm.selectedIndex = 0;
            }
        }
        //...............................
        flds = frm.getElementsByTagName("textarea");
        for (x in flds) {
            itm = document.getElementById(flds[x].id);
            if (itm) {
                itm.style.backgroundColor = clrClear;
                itm.value = "";
            }
        }
        //...............................
        // Close up any 2nd county and title.
        document.getElementById("secondcounty").className="hideme";
        
    }
}

function getBrowserInfo(x) {
    // Determine the identifying info for the client brower.
    // Return a string.
    // Would also like to know: iphone, mac, windows, linux ...
    // This js code gathers browser info, then at page-submit, php logs this info to file.
    var ans = "Unknown";
    var info, extra = "";      
    var lparen, semi = "";
    var pos = -1;       // start index into info
    var b = -1;         // index into array
    var ender = -1;     // end index into info
    var candidate = "";
    
    var browser = new Array("MSIE", "Firefox", "Chrome", "Opera", "Safari", "Mosaic");

    // We also want to know the version number.
    // Get what char bounds our desired info in the string.
    var limiter = new Array(";", " ", " ", " ", " ", " ");         
        
    // optional arg to allow for testing
    if (!x) {
        info = navigator.userAgent;
    }
    else {
        info = x;
    }
    
    ans = "{}"; // we are not in the list
    for (b in browser) {
        pos = info.indexOf(browser[b]) ;
        if (pos >= 0) {
            ender = info.indexOf(limiter[b], pos);      // start this search from our initial find
            if (ender == -1) { ender = info.length; }   // ... can be end-of-string
             // Extract from 'pos' up to 'limiter' in string info.
            candidate = info.substr(pos, ender - pos);  // substr(start,len)
           
			if (candidate != "") {
			    // Detail work. Don't want:   browser x.y.z.t    Want only:  browser x.y  
                var parts = candidate.split(".");
			    var bestans = parts[0] ; //  + "." + parts[1];  // even this is too variable 10/22/11
			    //alert("info="+info+"\ncand="+candidate+"\nbest="+bestans);
				ans = bestans;
			}
			
			// extra info
			lparen = info.indexOf("(") ;
			semi = info.indexOf(";") ;
			extra = info.substring(lparen+1, semi); // substring(from, to)
			
            break;
        }
    }
    
    return ans + ' [' + extra + ']' ;
}

function testBrowserInfo() {
    // jkw tester for browser info
    var t = "";
    var ans = "";
    
    t='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; yie8)';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; SPH-D700 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A306 Safari/6531.22.7';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.04 (lucid) Firefox/3.6.14';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Firefox/3.6.15';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.14) Gecko/20110218 BTRS28059 Firefox/3.6.14';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15';
    ans += t + '\n' + getBrowserInfo(t) + '\n\n';
    t='Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7';
    ans +=  t + '\n' +getBrowserInfo(t) + '\n\n';

    alert(ans);
    return;
}

function WinClose() {
    // If user clicks CLOSE button and we are doing COC work, 
    // then close whole window/tab.
    // window.top.location.search is the url arg string, including the ? symbol
    // Using substring(1) does the substr from position 1 to end; i.e., skips the ? symbol
    var querystring = window.top.location.search.substring(1);
    // works for both coc update and coc view
    if (querystring.search("coc") != -1 ) {
        window.close();
    }
}

function showMeritLegend() {
    // Show the legend for the certification flags.
    // Uses hardwired knowledge of DB content course data.
    var msg = "<div id='legend'>";
    msg +="<h4>";
    msg += "Flags for groups of courses mark 'merit' or 'certification' status. ";
    msg += "These flags also show on roster reports.";
    msg +="</h4><h4>";
    msg += "There are 2 groups of flags: Regular and Winlink.";
    msg += "</h4>";
    msg += "<ul>";
    msg += "<li>Regular:";
    msg += "<ul>";
    msg += "<li>Lowercase flags mark a group of courses that have all been taken (marking candidate certification).</li>";
    msg += "<li>Uppercase flags mark a group of courses that have been taken and verified (marking true certification).</li>";
    msg += "</ul>";
    msg += "<ul>";
    msg += "<li>n, N - NIMS</li>";    
    msg += "<li>e, E - EC16</li>";    
    msg += "<li>c, C - COML</li>";  
    msg += "</ul>";  
    msg += "</li>"; // close regular
    msg += "<li>Winlink:";
    msg += "<ul>";    
    msg += "<li>Only entries that have been verified are marked.</li>";
    msg += "<li>For more information, contact the ASEC Training.</li>";
    msg += "</ul>";    
    msg += "<ul>";    
    msg += "<li>One or two 'w' characters.</li><li>Lowercase means VHF/UHF.</li><li>Uppercase means HF.</li>";
    msg += "<li>Underscore means 'capable'.</li><li>Green means 'active'.</li><li>Overscore means 'sysop'.</li>";
    msg += "<li>Simple letter with no extra markers means 'registered'. Only shows if nothing else does.</li>";
    msg += "</ul>";
    msg += "</li>"; // close winlink
    msg += "</ul>";
    msg += "</div>";
   
    showmsgbox(msg);
}

function logout() {
    // Log out the current user; end session; close all Depot windows.
    // Method: 
    //      Close any pages this page opened.
    //      If this page is vault_top, do logout action. 
    //      Else: invoke the logout action-click from the page that opened me. 
    // NOTE: window.parent is NOT the same as window.opener. USE window.opener for this work.
    // jkw fixme: Problem: 'cousin' windows are not closed at logout time.
    //            I.e., windows not opened directly from gateway are not closed
    //            in the case where the logout is initiated from a page not its child/parent path.
    
    // Close any windows this page opened.
    closeWindowSet(siteWindows);
    
    if (window.location.href.search('vault_gateway.php') != -1) {
        // Invocation from/for the main gateway window.
        // Perform the primary logout action. This will end the session.
        viewArea('photo','hideme');
        ajxDoUtilityJob('logout') ;
    }
    else { 
        // Invoke the logout action from the page that opened me.
        
        // Works for FF and IE. Fails for Chrome, Safari.
        //window.opener.document.getElementById('logout').click();
        
        // Solution for all browsers: Chrome, Safari, FF, IE.
        window.opener.logout();
    }        
}

function closeWindowSet(winArray) {
    // Given an array of window handles, close all windows on that list.
    // Can be called recursively.
    var i;
    for (i=0; i < winArray.length; i++) {
        if (!winArray[i]) { continue; } // skip nulls
        if (!winArray[i].closed) {
            closeWindowSet(winArray[i]);
            winArray[i].close();
        }
    }
}

function saveWindowHandle(winHandle) {
    // Collect handles of windows opened by current page this depot session.
    // All pages include 'utility.js' and so have an instance of array siteWindows() declared.
    siteWindows.push(winHandle);
}

function toggleView(theID, target) {
    // Toggle the +/- show/hide symbol and then show or hide the area.
    var obj = document.getElementById(theID);
    var tgt = document.getElementById(target);
    if (obj.innerHTML == TOGGLE_ON) {
        tgt.className = 'showme';
        obj.innerHTML = TOGGLE_OFF;
    }
    else {
        tgt.className = 'hideme';
        obj.innerHTML = TOGGLE_ON;
    }
}

function viewArea(theID, clsname) {
    // Show or hide the area given, as specified by clsname.
    // clsname is typically 'showme' or 'hideme'
    var obj = document.getElementById(theID);
    if (obj) {
        obj.className = clsname;
    }
}

function checkValidFile(fnID, pix) {
    // Check for valid file extension. The arg is the ID of the input field.
    // Arg 'pix' is optional; if pix=true, verify extensions for member pictures only.
    
    // This work previously done in php (kit_utility2.php). 
    // This extension array exists there also even though that code is now skipped.
    // See: http://en.wikipedia.org/wiki/List_of_file_formats
    var allowedExtensions =[
        "txt","csv","rtf","pdf","readme",   // textual
        "doc","docx",                       // word
        "htm","html","xml","css",           // web/browser
	    "xls","xlsx",                       // excel
	    "ppt","pptx","pps","ppsx",          // powerpoint
	    "swf","flv",                        // shockwave flash multimedia; flash video (adobe)
	    "mp4","mp3","mp2","mpg",            // mp2,mp3=mpeg audio; mpg,mp4=mpeg video
	    "avi","wav","wmv","mov",            // video
	    "jpg","jpeg","gif","png","ico"      // graphic/image
	    ];
	    
    var allowedPixExtensions = ["jpg","jpeg"];
    var testList = [];
    
    if (typeof(pix) == 'undefined') { testList = allowedExtensions; }	    
    else                            { testList = allowedPixExtensions;}
	    
    var fn = document.getElementById(fnID);
    var pos = fn.value.lastIndexOf(".");
    var fext = fn.value.substr(pos + 1);  // skip the dot     
           
    var msg = "";
    var valid = false;
    var len = testList.length;
    
    for (var i=0; i < len; i++) {
        if (testList[i] == fext.toLowerCase()){ 
            valid = true;
            break;
        }
    }
    return valid;
}

