function core_ajaxGetXML( request ) {
    if( navigator.appName == "Netscape" ) {
        // 2007-09-05 (JK): See https://bugzilla.mozilla.org/show_bug.cgi?id=326337
        return (new DOMParser()).parseFromString( request.responseText, "text/xml" );
    } else {
        return request.responseXML;
    }
}

function core_ajaxOnFailure( request, url ) {
    alert( url + ": " + request.status );
}

function core_ajaxOnException( request, error ) {
    alert( error.description + " for " + request.url );
}

function core_areCookiesEnabled() {
    var cookieEnabled = false;
    if (typeof document.cookie == "string") {
        if (document.cookie.length == 0) {
            document.cookie = "test";
            cookieEnabled = (document.cookie == "test");
            document.cookie = "";
        } else {
            cookieEnabled = true;
        }
    }
    return cookieEnabled;
}

function core_arrayContainsElement( a, e ) {
    for( var i = 0; i < a.length; i++ ) {
        if( a[i] == e ) {
            return true;
        }
    }
    return false;
}

function core_formatDate( year, month, day ) {
    if( typeof( year ) == "object" ) {
        // Assume it's a date, and pull out the year/month/day.
        return core_formatDate( year.getUTCFullYear(), year.getUTCMonth() + 1, year.getUTCDate() );
    }
    month = parseInt( month, 10 );
    day = parseInt( day, 10 );
    if( isNaN( month ) || isNaN( day ) ) {
        return null;
    }
    if( month < 10 ) {
        month = "0" + month;
    }
    if( day < 10 ) {
        day = "0" + day;
    }
    return year + "-" + month + "-" + day;
}

function core_formatTime( hour, minute ) {
    hour = parseInt( hour, 10 );
    minute = parseInt( minute, 10 );
    if( isNaN( hour ) || isNaN( minute ) ) {
        return null;
    }
    if( hour < 10 ) {
        hour = "0" + hour;
    }
    if( minute < 10 ) {
        minute = "0" + minute;
    }
    return hour + ":" + minute;
}

function core_getContextPath() {
    var path = document.location.pathname;
    var n = path.indexOf( "/", 1 );
    return path.substring( 0, n );
}

function core_getCookie( name ) {
    // See http://wiki.script.aculo.us/scriptaculous/show/Cookie
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return cookie ? unescape(cookie[2]) : null;
}

function core_getNumberOfUTF8Bytes( s ) {
	if( s == null ) {
		return 0;
	}
	var numBytes = 0;
	for( var i = 0; i < s.length; i++ ) {
		var c = s.charCodeAt( i );
		if( c <= 127 ) {
			numBytes++;
		} else if ( c <= 2047 ){
			numBytes += 2;
		} else if ( c <= 65535 ){
			numBytes += 3;
		} else {
			numBytes += 4;
		}
	}
	return numBytes;
}

function core_getQueryArg( key ) {
    var qs = document.location.search;
    if( qs.indexOf( "?" ) == 0 ) {
        qs = qs.substr( 1 );
    }
    if( qs == null ) {
        return "";
    }
    var a = qs.split( "&" );
    for( var i = 0, n = a.length; i < n; i++ ) {
        var kv = a[i].split( "=" );
        if( kv[0] == key ) {
            return kv[1];
        }
    }
    return null;
}

function core_getQueryStringWithoutPrefix( pfx, q ) {
    if( q == null )
        q = document.location.search;
    if( q.substring( 0, 1 ) == "?" )
        q = q.substring( 1 );
    var aIn = q.split( "&" );
    var aOut = new Array();
    for( var i = 0; i < aIn.length; i++ ) {
        if( aIn[i].substring( 0, pfx.length ) != pfx )
            aOut[aOut.length] = aIn[i];
    }
    return( aOut.join( "&" ) );
}

function core_getSelectedElementValues( element ) {

    // 2007-08-09 (JK): There are tests for this in test_core_getSelectedElementValues.html

    if( typeof( element ) == "string" ) {
        // Assume it's an id rather than an element
        element = document.getElementById( element );
    }

    function addValue( element ) {
        switch( element.type ) {
        case "checkbox":
        case "radio":
            if( element.checked ) {
                a.push( element.value );
            }
            break;
        case "hidden":
        case "text":
            if( ! core_isStringBlank( element.value ) ) {
                a.push( element.value );
            }
            break;
        case "select-one":
            if( ! core_isEmpty( element ) ) {
                a.push( core_getValue( element ) );
            }
            break;
        case "select-multiple":
            for ( var i = 0 ; i < element.options.length ; i++ ) {
                var option = element.options[i];
                if ( option.selected ) {
                    a.push( option.value );
                }
            }
            break;
        default:
            if( element.length ) {
                // Assume it's an array of elements with the same name, and add them all.
                for( var i = 0; i < element.length; i++ ) {
                    addValue( element[i] );
                }
            }
            break;
        }
    }

    if( element == null ) {
        return [];
    }
    var a = new Array();
    addValue( element );
    return a;
}

function core_getValue( element ) {
    if( element == null ) {
        return null;
    }
    if( typeof( element ) == "string" ) {
        // Assume it's an id rather than an element
        element = document.getElementById( element );
    }
    switch( element.type ) {
    case "select-one":
        if( element.selectedIndex < 0 ) {
            return null;
        }
        // 2007-08-09 (JK): Use .getAttribute rather than .value; FireFox returns the content for .value if there is
        //  no attribute.
        return element.options[element.selectedIndex].getAttribute( "value" );
    case "file":
    case "hidden":
    case "password":
    case "text":
    case "textarea":
        return element.value;
    case "radio":
        return element.checked ? element.value : null;
    default:
        // See if it's an array of radio buttons.
        if( element.length && element.length > 0 && element[0].type == "radio" ) {
            var a = core_getSelectedElementValues( element );
            return a.length == 1 ? a[0] : null;
        }
        break;
    }
    return null;
}

function core_isDateValid( s ) {

    if( typeof( s ) != "string" ) {
        return false;
    }

    var dateComponents = s.split( "-" );
    var year = dateComponents[0];
    var month = dateComponents[1];
    var day = dateComponents[2];

    if ( (isNaN(dateComponents[0])) || (isNaN(dateComponents[1])) || (isNaN(dateComponents[2])) ) {
        return false;
    }

    month = parseInt( month, 10 );

    if ( dateComponents.length > 3 ) {
        return false;
    }

    if ( (month < 1) || (month > 12) ) {
        return false;
    }

    // year must be a 4 digit value
    if ( year < 1000 ) {
        return false;
    }

    if( day < 1 ) {
        return false;
    }

    switch( month ) {
    case 2:
        var lastDay;
        if ( ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))) {
            lastDay = 29;
        } else {
            lastDay = 28;
        }

        if ( day > lastDay ) {
            return false;
        }
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        if ( day > 30 ) {
            return false;
        }
        break;
    default:
        if ( day > 31 ) {
            return false;
        }
        break;
    }

    return true;
}

function core_isEmailAddressValid( email ) {

    function domainIsValid( domain ) {
        if( domain.length < 3 ) {
            return false;
        }
        var lastDot = -1;
        var n =domain.length;
        for( var i = 0; i < n; i++ ) {
            var c = domain.charAt( i );
            switch( c ) {
            case '.':
                if( i == 0 || i == n - 1 || lastDot == i - 1 ) {
                    return false;
                }
                lastDot = i;
                break;
            default:
                if( ! isValidAtomChar( c ) ) {
                    return false;
                }
                break;
            }
        }
        return lastDot != -1;
    }

    function isValidAtomChar( c ) {
        switch( c ) {
        case '(':
        case ')':
        case '<':
        case '>':
        case ',':
        case ';':
        case ':':
        case '\\':
        case '"':
        case '[':
        case ']':
        case ' ':
        case '\t':
        case '\n':
            return false;
        default:
            return c.charCodeAt(0) >= 32 && c.charCodeAt(0) <= 127;
        }
    }

    function localAddressIsValid( address ) {
        var n = address.length;
        if( n == 0 ) {
            return false;
        }
        for( var i = 0; i < n; i++ ) {
            var c = address.charAt( i );
            switch( c ) {
            case '.':
                if( i == 0 ) {
                    return false; // first character can't be a .
                }
                break;
            default:
                if( ! isValidAtomChar( c ) ) {
                    return false;
                }
                break;
            }
        }
        return true
    }

    if( email == null ) {
        return false;
    }
    var parts = email.split( "@" );
    if( parts.length != 2 ) {
        return false;
    }
    if( ! localAddressIsValid( parts[0] ) ) {
        return false;
    }
    return domainIsValid( parts[1] );
}

function core_isEmpty( element ) {
    // 2007-08-10 (JK): There are tests for this in test_core_isEmpty.html
    // 2007-08-27 (JK): If element is null, return true. The scenario for this is dynamically created hidden elements
    //  (e.g., for company accreditations).
    if( element == null ) {
        return true;
    }
    switch( element.type ) {
    case "file":
    case "hidden":
    case "password":
    case "select-one":
    case "text":
    case "textarea":
        return core_isStringBlank( core_getValue( element ) );
        break;
    case "select-multiple":
        return core_isMultiSelectEmpty( element );
        break;
    case "radio":
        return core_isStringBlank( core_getValue( element ) );
        break;
    case "checkbox":
        return core_getSelectedElementValues( element ).length == 0;
        break;
    default:
        // Assume it's an array of elements, and see if any are selected.
        return core_getSelectedElementValues( element ).length == 0;
        break;
    }
    return false;
}

function core_isInteger( value ) {
    if( value == null || value == "" )
        return( false );

    var re = new RegExp( "^-?\\d+$" );
    return( re.test( value ) );
}

function core_isMultiSelectEmpty( element ) {
    for ( var i = 0 ; i < element.options.length ; i++ ) {
        if ( element.options[i].selected ) {
            return false;
        }
    }
    return true;
}

function core_isStringBlank( s ) {
    if( s == null ) {
        return true;
    }
    for(var i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if ( (c != ' ') && (c != '\n')  && (c != '\r') && (c != '\t') ) {
            return false;
        }
    }
    return true;
}

function core_isTimeValid( s ) {
    if( typeof( s ) != "string" ) {
        return false;
    }
    if( ! s.match( /^\d\d\:\d\d$/ ) ) {
        return false;
    }
    var a = s.split( ":" );
    var h = parseInt( a[0] );
    var m = parseInt( a[1] );
    return h >= 0 && h <= 23 && m >= 0 && m <= 59;
}

function core_isURLValid( url, validProtocols ) {

    function protocolIsValid( protocol ) {
        for( var i = 0; i < validProtocols.length; i++ ) {
            if( validProtocols[i] == protocol ) {
                return true;
            }
        }
        return false;
    }

    // 2006-07-25 (JK): There are tests for this in test_core_isURLValid.html
    if( url == null ) {
        return false;
    }

    if( validProtocols == null ) {
        validProtocols = [ "ftp", "http", "https", "javascript", "mailto" ];
    }

    if( url.indexOf( "#" ) == 0 ) {
        return true; // allow fragment links
    }
    var n = url.indexOf( ":" );
    if( n < 1 ) {
        return false;
    }
    var protocol = url.substring( 0, n ).toLowerCase();
    if( ! protocolIsValid( protocol ) ) {
        return false;
    }

    // Issue 4472, 2006-06-22 (DW): Disallow spaces only if not javascript
    // Issue 5503, 2009-07-20 (JK): ... or mailto - not sure if they are technically allowed here or not, but they seem harmless and legacy content has them
    if ( protocol != "javascript" && protocol != "mailto" ) {
        if( url.indexOf( " " ) != -1 ) {
            return false;
        }
    }

    var s = url.substring( n + 1 );

    if( protocol == "mailto" ) {
        var address = s;
        if( address.indexOf( '?' ) != -1 ) {
            address = address.split( '?' )[0];
        }
        return core_isEmailAddressValid( address );
    } else if( protocol == "javascript" ) {
        return s != "";
    } else {
        if( s.indexOf( "//" ) != 0 ) {
            return false;
        }
        s = s.substring( 2 );
        var a = s.split( "/" );
        var host = a[0];
        var d = host.split( "." );
        return d.length > 1 && d[1] != "";
    }
}

function core_setElementText( id, value ) {
    var elem = document.getElementById( id );
    if( ! elem ) {
        return;
    }
    // Remove any children
    while( elem.firstChild ) {
        elem.removeChild( elem.firstChild );
    }
    if( value == null ) {
        return;
    }
    var node = document.createTextNode( value );
    elem.appendChild( node );
}

function core_selectOption( e, value, isSelected ) {
    switch( e.type ) {
    case "select-multiple":
        for ( var i = 0 ; i < e.options.length ; i++ ) {
            var option = e.options[i];
            if ( option.value == value ) {
                option.selected = isSelected;
                return;
            }
        }
        break;
    default:
        break;
    }
}

function core_setClass( e, name ) {
    e.setAttribute( "className", name );
    e.setAttribute( "class", name );
}

function core_setSelectedOptionValue( e, value ) {
    // There are unit tests for this function in test_core_setSelectedOptionValue.html
    if( typeof( e ) == "string" ) {
        // Assume it's an element ID rather than an element.
        core_setSelectedOptionValue( document.getElementById( e ), value );
    }
    if( e.type == "select-one" ) {
        var options = e.options;
        for( var i = 0; i < options.length; i++ ) {
            if( options[i].value == value ) {
                e.selectedIndex = i;
                return;
            }
            e.selectedIndex = -1;
        }
    } else if( e.type == "hidden" ) {
        e.value = value;
    } else if( e.type == "radio" ) {
        e.checked = ( e.value == value );
    } else if ( ( typeof( e ) == "object" && e[0] && e[0].type == "radio" ) ) {
        for( i = 0; i < e.length; i++ ) {
            var r = e[i];
            r.checked = ( r.value == value );
        }
    }
}

function core_trimString( s ) {
    // Strip any leading or trailing white space
    s = s.replace( /^(\s)+/, "" );
    s = s.replace( /(\s)+$/, "" );
    return s;
}



