<!------------------------------------------------------------------------
//
// FILE: 
//    VisualScience.js
//
// CREATED:
//    2003/02/10
//
// DESCRIPTION:
//   Usage Analysis Javascript Library
//  
// Copyright (C) 2005 Capital One Financial Corporation.  All Rights Reserved.
//
// All data and information contained in or disclosed by this document is 
// confidential and the proprietary information of Capital One Financial 
// Corporation and all rights therein are expressly reserved. By accepting this
// material the recipient agrees that this material and the information 
// contained therein is held in confidence and in trust and will not be used, 
// copied, reproduced in whole or in part, nor its contents revealed in any 
// manner to others without the express written permission of Capital One 
// Financial Corporation.
//
//----------------------------------------------------------------------->

    //  Set to true for testing, false otherwise,
    //  enables Analytics to be rendered in cleartext
    var TESTING = false;



/**
 * Writes the Cross Domain Analytic object request.
 *
 * Arguments: attributes, an array of attributes where each element of the
 *            array is of the form attributeName=attributeValue.
 *
 * Used by:   calling function.
 */
 
function writeCrossDomainAnalytic(attributes) {
     //  Constant URL value for the Cross Domain URL to included /path/to/null.js or
    //  /path/to/pixel.gif.
	if (host() == "applications.capitalone.com" || host() == "maps.capitalone.com") {
		CROSSDOMAINURL = "crossdomain.capitalone.com/common/scripts/null.js";
	} else {

		/*
			Modified so that Branch Locator can use this same file. If we try to make a
			call to qacrossdomain the page simply hangs. As soon as	we can get access to
			qacrossdomain.capitalone.com then we can uncomment this and remove the
			line below that says return true;
			
			CROSSDOMAINURL = "qacrossdomain.capitalone.com/common/scripts/null.js";

		*/

		/* REMOVE AFTER WE UNCOMMENT LINE ABOVE */
		return true;
	}
		
    if (typeof CROSSDOMAINURL == "undefined" || CROSSDOMAINURL == null || CROSSDOMAINURL == "") {
        return false;
    }

    // Remap file protocol for cross-domain Analytic when testing locally
    if (protocol() == "file:") {
        protocol = "http:";
    } else {
        protocol = protocol();
    }

    var crossDomainUrl = protocol + "//" + CROSSDOMAINURL;
    document.write(analyticObject(attributes, crossDomainUrl));

    return true;
}

/**
 * Builds and returns the analytic object tag.
 * Used by the writeAnalytic and writeCrossDomainAnalytic functions.
 */
function analyticObject(attributes, targetURL) {
    var openingTag  = "", closingTag = "";
    var objType = objectType(targetURL).toUpperCase();

    if (TESTING == true) {
        openingTag = "";
        closingTag = "<br>";
    }
    else if (objType == "JS") {
        openingTag = "<script language=\"JavaScript\" src=\"";
        closingTag = "\"></script>";
    }
    else if (objType == "IMG") {
        openingTag = "<image src=\"";
        closingTag = "\">";
    }
    else {
        return "";
    }

    var analyticObject = openingTag + targetURL + query(cleanAttributes(attributes)) +
                         closingTag;

    return analyticObject;
}

/**
 * Returns the value of the object being requested.
 *
 *     "JS"   for a JavaScript object,
 *     "IMG"  for a Image object,
 *     "NULL" neither a JavaScript or Image specified by the targetURL,
 *     "TEST" used for testing purposes.
 *
 * The targetURL argument is assumed to be the URL of either a 
 * JavaScript (.js) or an image (.gif).
 *
 * Used by the analyticObject function.
 */
function objectType(targetURL) {
    if (typeof targetURL == "undefined" || targetURL == null) return "NULL";

    if (targetURL.indexOf(".js") > 0) {
        return "JS";
    } else if (targetURL.indexOf(".gif") > 0 ||
             targetURL.indexOf(".jpg") > 0 ||
             targetURL.indexOf(".jpeg") > 0) {
        return "IMG";
    } else {
		return "SOMETHINGELSE";
	}
}

/**
 * Returns the protocol of the page request.
 *
 *     "http:"  for an http page request,
 *     "https:" for an https page request,
 *     "file:"  if testing on local machine.
 *
 * Used by the writeAnalytic and writeCrossDomainAnalytic functions.
 */
function protocol() {
    return location.protocol;
}

/**
 * Returns the host of the page request.
 * Used by the writeAnalytic function.
 */
function host() {
    return location.host;
}

/**
 * Builds and returns the query string, which will be "?Log=1" followed by
 * name-value pairs for each attribute to be captured in the analytic object
 * request.
 * Used by the analyticObject function.
 */
function query(attributes) {
    var queryString = "";
    
    if (attributes) {
        queryString = "?Log=1";
        for (var i=0; i < attributes.length; i++) {
            queryString += "&" + attributes[i];
        }
    }
    return queryString;
}

/**
 * Returns a clean attributes array, where each element of the array is of
 * the format "attributeName=numericvalue" or "attributeName='textvalue'".
 * Used by the analyticObject function.
 */
function cleanAttributes(attributes) {
    var cleanAttribs = new Array();
    var cleanAttribsIndex = 0;

    var splitAttributes = new Array();

    if (attributes) {
        // Iterate through each attribute
        for (var i=0; i < attributes.length; i++) {

            // Process only attributes containing an element            
            if(attributes[i]) {
                // Process only where elements contains "=value" or "value" (no attribute= specified)
                if(attributes[i].search(/=[ '\=A-Za-z0-9]/) != -1 ||
                   attributes[i].search(/=/) == -1) {

                    // Split attributes on equal symbol, separator of name=value
                    splitAttributes = attributes[i].split("=");
                    // Iterate through each element of the split array
                    for(var j=0; j < splitAttributes.length; j++) {
                        // remove single and double quotes, trim before and after
                        splitAttributes[j] = ltrim(rtrim(removeQuotes(splitAttributes[j])));
                    }

                    switch(splitAttributes.length) {
                        case 1:
                            // Only attribute value specified
                            attributes[i] = "Attribute" + i + "=" + encode(splitAttributes[0]);
                            break;
                        default:
                            // Attribute name=value specified, any extra values ignored
                            var attributeName = clean(splitAttributes[0]);
                            if (attributeName == "") {
                                attributes[i] = "Attribute" + i + "=" + encode(splitAttributes[1]);
                            }
                            else {
                                attributes[i] = attributeName + "=" + encode(splitAttributes[1]);
                            }
                            break;
                    }
                    // Add cleaned attribute to new array
                    cleanAttribs[cleanAttribsIndex] = attributes[i];
                    cleanAttribsIndex++;
                }
            }
        }
    }
    else {
        return false;
    }

    return cleanAttribs;
}

/**
 * Returns encoded string for use within a URL.
 * Used by cleanAttributes function to encode the attribute value.
 */
function encode(str) {
    if (typeof str == "undefined"  || str == null || str == "") {
        return "";
    }

    var OKCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +    // Alphabetic
                  "abcdefghijklmnopqrstuvwxyz" +
                  "0123456789" +                    // Numeric
                  "-_.!~*'()";                      // RFC2396
    var HEX =     "0123456789ABCDEF";

    var unEncodedString = str;
    var encodedString = "";
    for (var i = 0; i < unEncodedString.length; i++ ) {
        var ch = unEncodedString.charAt(i);
        if (ch == " ") {
            // Encode space with a "+", rather than %20
            encodedString += "+";
        } else if (OKCHARS.indexOf(ch) != -1) {
            encodedString += ch;
        } else {
            var charCode = ch.charCodeAt(0);
            if (charCode > 255) {
                // Unicode character cannot be encoded as URL encoding only supports 
                // 8-bit characters.  Substituting a space (+) for the character.
                encodedString += "+";
            } else {
                encodedString += "%";
                encodedString += HEX.charAt((charCode >> 4) & 0xF);
                encodedString += HEX.charAt(charCode & 0xF);
            }
        }
    }

    return encodedString;
}

/**
 * Returns a cleaned string of only alphabetic or number symbols, minus the URL
 * special characters or other characters that would require URL encoding.
 * Used by the cleanAttributes function to clean the attribute name in the
 * attribute name-value pair.
 */
function clean(str) {
    if (typeof str == "undefined"  || str == null || str == "") {
        return "";
    }

    var CLEANCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + // Alphabetic
                     "abcdefghijklmnopqrstuvwxyz" +
                     "0123456789";                  // Numeric;

    var patientString = str;
    var cleanedString = "";
    for (var i = 0; i < patientString.length; i++ ) {
        var ch = patientString.charAt(i);
        if (CLEANCHARS.indexOf(ch) != -1) {
            cleanedString += ch;
        }
        // else omit character from cleaned string
    }
    
    return cleanedString;
}

/**
 * Returns string quoted with single quotes "'" unless the string is a
 * numerical value.
 * Used by cleanAttributes function to quote the attribute value of the 
 * attribute name-value pair.
 */
function singleQuote(str) {
    if (typeof str == "undefined" || str == null) {
		return str;
	}

    str = "" + str;
    
    if (isNumeric(str)) {
        return str;
    }
    return "'" + str + "'";
}

/**
 * Returns string with all single and double quotes removed.
 * Used by the cleanAttributes function to remove quotes from the 
 * attribute value.
 */
function removeQuotes(str) {
    if (typeof str == "undefined" || str == null) {
		return str;
	}

    str = "" + str;
    
    allQuotes = /['\"]/ig; 

    return str.replace(allQuotes, "");
}


/**
 * Returns string with inital spaces removed up to the first character not in
 * the set.  Set defaults to " ".
 * Used by the cleanAttributes function to trim the operands of the 
 * attribute name-value pair.
 */
function ltrim(str, set) {
    if (typeof str == "undefined" || str == null) {
		return str;
	}

    if (typeof set == "undefined"  || set == null || set == "") {
        set = " ";  // Default
    }
    str = "" + str;
    set = "" + set;

    while (str.length > 0 && set.indexOf(str.charAt(0)) != -1) {
        str = str.substring(1, str.length);
    }
    return str;
}

/**
 * Returns string with final characters removed up the last character not in
 * the set.  Set defaults to " ".
 * Used by the cleanAttributes function to trim the operands of the 
 * attribute name-value pair.
 */
function rtrim(str, set) {
    if (typeof str == "undefined" || str == null) {
		return str;
	}

    if (typeof set == "undefined"  || set == null || set == "") {
        set = " ";  // Default
    }
    str = "" + str;
    set = "" + set;

    while(str.length > 0 && set.indexOf(str.charAt(str.length-1)) != -1) {
        str = str.substring(0, str.length-1);
    }
    return str;
}

/**
 * Returns true if the string contains only numberic characters, and false if
 * string contains at least one non-numeric character.
 * Used by singeQuote function to appropriately quote only non-numeric strings.
 */
function isNumeric(value) {
    if (typeof value == "undefined" || value == null) {
		return false;
	}
    
    var v = 1.0 * value;

    if (isNaN(v)) {
        return false;
    } else {
        return true;
    }
}

/*
 * Copyright 2004 Capital One Financial Corporation
 * All Rights Reserved.
 *
 * This software contains valuable trade secrets and proprietary
 * information of Capital One and is protected by law. It may not
 * be copied or distributed in any form or medium, disclosed to third
 * parties, reverse engineered or used in any manner without prior
 * written authorization from Capital One.
 */