/**
 * BI Reporting Framework Library
 * */

var BIFrameworkLibrary = {
/**
     * Fires Custom named events
     * @param element       the element to fire the event
     * @param eventName     the event name to fire
     * @param memo          event meta data
     * @param bubble        boolean to bubble the event
     * */
    _fireEvent:function(element, eventName, memo, bubble) {
        if (this.isUndefined(bubble)) {
            bubble = true;
        }

        if (element == document && document.createEvent && !element.dispatchEvent) {
            element = document.documentElement;
        }
        var event;
        if (document.createEvent) {
            event = document.createEvent('HTMLEvents');
            event.initEvent('dataavailable', true, true);
        } else {
            event = document.createEventObject();
            event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
        }

        event.eventName = eventName;
        event.memo = memo || { };

        if (document.createEvent) {
            element.dispatchEvent(event);
        } else {
            element.fireEvent(event.eventType, event);
        }
    },

    /**
     * Determine if object is undefined
     * */
    isUndefined: function(object) {
        return typeof object == "undefined";
    },

    /**
     * Determines if object has no content
     * @param s     object to inspect
     * @return      boolean
     * */
    _isEmpty :function(s){
        return s == null || typeof s == null || s.length <= 0;
    },

    /**
     * Determines if object has content
     * @param s     object to inspect
     * @return      boolean
     * */
    _isNotEmpty: function(s) {
        return !this._isEmpty(s);
    },

    /**
     * Parses Key value pairs within an object into an encoded query string
     * @param collection the object to be parsed
     * */
    _objectToQueryString: function(collection) {
        var queryArray = [];
        for (var key in collection) {
            queryArray.push(key + '=' + encodeURIComponent(collection[key]));
        }
        return queryArray.join('&');
    },

    /**
     * Crossbrowser utility to obtain the links inner text
     * @param el HTML Element to have content discovered
     * @return content String
     * */
    _stringContent: function(el){
        var content = "";
        if(typeof document.body.innerText == 'undefined'){
            content = el.textContent;
        } else {
            content = el.innerText;
        }
        return content;
    },

    /**
     * Browser sniffer for IE
     * @return boolean
     * */
    _isIE: function() {
        return !!(window.attachEvent && !window.opera);
    },

    /**
     * Helper Method for Ajax request of log image
     * @param url   request string to send to the server
     **/
    _ajaxRequest: function (url) {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            // code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp=new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            // code for IE6, IE5
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }


        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    },

    /**
     * Sets browser Event observers
     * @param element       the element to observe for event
     * @param name          the event name to observe
     * @param observer      function to fire after event is observed
     **/
    _observe: function(element, name, observer) {

        if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent)) {
            name = 'keydown';
        }

        if(name.indexOf(":") != -1) {
            if (element.addEventListener) {
                element.addEventListener("dataavailable", observer, false);
            }
        } else {
            if (element.addEventListener) {
                element.addEventListener(name, observer, false);
                return true;
            } else if (element.attachEvent) {
                return element.attachEvent('on' + name, observer);
            } else {
                element['on' + name] = observer;
            }
        }
    },

    /**
     * Creates cross browser event object
     * @return event object
     * */
    _cleanseEvent: function(e) {
          return e || window.event;
    },

    /**
     * Creates cross browser event target
     * @return  event target
     * */
    _eventTarget: function(e) {
        var targ;
        if (!e) var e = window.event;
        if (e.target) targ = e.target;
        else if (e.srcElement) targ = e.srcElement;
        return targ;
    },

    /**
     * Matches the closest element (direct ancestor) to the event target that matches the tagname
     * @param e         event
     * @param tagname   tagname to match to event target
     * @return          closest matched element
     * */
    _findElement: function(e, tagname) {
        return this._matchElementByTagName(this._eventTarget(e), tagname);
    },

    /**
     * Reursive function to match tagname to current element or check parent
     * @param el        current element
     * @param tagname   tagname to match to current element
     * */
    _matchElementByTagName: function(el, tagname) {
        if(el.tagName.toLowerCase() == tagname) {
            return el;
        } else if (el.tagName.toLowerCase() == "html") {
            return false;
        } else {
            return this._matchElementByTagName(el.parentNode, tagname);
        }
    },

    /**
     * Cancels supplied event
     * @param e Event
     * */
    _stop: function(e) {
        if (!e) {
            e = window.event;
        }
        e.cancelBubble = true;
        if (e.stopPropagation) {
            e.stopPropagation();
        }
        if (e &&e.preventDefault) {
            e.preventDefault();
        } else if (window.event && window.event.returnValue) {
            window.eventReturnValue = false;
        }
    },

    /**
     * Collects Form elements
     * @param form  form to be iterated over
     * @return      collection of form elements
     * */
    _getFormElements: function(form) {
        var arr = [];
        var elements = form.getElementsByTagName('*');
        var elLen = elements.length;
        var tagnames = ["input", "select", "textarea"];
        var tagLen = tagnames.length;

        for (var i=0; i<elLen; i++) {
            for (var j=0; j<tagLen; j++) {
                if (elements[i].tagName.toLowerCase() == tagnames[j]) {
                    arr.push(elements[i]);
                }
            }
        }
        return arr;
    },

    getTag: function(tag, parent){
        var tags = (parent == null) ? document.getElementsByTagName(this.getTagName(tag)) : parent.getElementsByTagName(this.getTagName(tag));
        if (tags != null && tags.length > 0) {
            return tags[0];
        } else {
            var tagsx = document.getElementsByTagName("birf:"+tag);
            if (tagsx != null && tagsx.length > 0) {
                return tagsx[0];
            } else {
                return null;
            }
        }
    },

    getTags: function(tag, parent){
        var tags = (parent == null) ? document.getElementsByTagName(this.getTagName(tag)) : parent.getElementsByTagName(this.getTagName(tag));
        if (tags != null && tags.length > 0) {
            return tags;
        } else {
            var tagsx = document.getElementsByTagName("birf:"+tag);
            if (tagsx != null && tagsx.length > 0) {
                return tagsx;
            } else {
                return tags;
            }
        }
    },


    /**
     * Cross Browser cleansing of BI specific tag names
     * @param tag   the BI tagname
     * @return      the tagname as Browsers will be able to see it
     * */
    getTagName: function(tag){
        return this._isIE() ? tag : this.ns + ":" + tag;
    },

    /**
     * Causes Browser to ignore user input for specified time (ms)
     * @param ms the amount of milliseconds to ignore user input
     **/
    _pause: function(ms) {
        var now = new Date();
        var exitTime = now.getTime() + ms;
        while (true) {
            now = new Date();
            if (now.getTime() > exitTime)
                return;
        }
    },

    /**
     * Iterate over BIRF tag attributes and set their name/value pairs to collection object
     * @param tag           BIRF tag whose attributes are being parsed
     * @param collection    object to set name/value pairs in
     **/
    _parseBIRFAttributes: function(tag, collection) {
        var attrs = tag.attributes;
        var len = attrs.length;
        for (var i=0; i<len; i++) {
            if (attrs[i].specified) {
                collection[attrs[i].name] = attrs[i].textContent || attrs[i].value;
            }
        }
    },

    /**
     * Iterate over BIRF child tags and set their name/value pairs to collection object
     * @param childCollection   array of BIRF child elements
     * @param paramCollection   object to set name/value pairs in
     * @param n                 (optional) String that is used for name attribute in child tag
     * @param v                 (optional) String that is used for value attribute in child tag
     **/
    _parseBIRFChildTags: function(childCollection, paramCollection, n, v) {
        var name = (n) ? n : 'name';
        var value = (v) ? v : 'value';

        if(this._isNotEmpty(childCollection)) {
            var len = childCollection.length;
            for (var i=0; i<len; i++) {
                var val = childCollection[i].getAttribute(value);
                if (val == "null") val = "";
                paramCollection[childCollection[i].getAttribute(name)] = val;
            }
        };
    }
};




/**
 * ATC BI Reporting Framework
 */
function BIFramework() {
    this.init = function(){
        this.processPageLoad();
        this.processAudit();
        this.processImpressions();
        this.processLinks();
       // this.processCustomClicks();
        this.processForms();
    };

    /**
     * Declaration of the BI namespace
     */
    this.ns = "birf";

    /**
     * Container for shared BIRF variables
     */
    this.shared = function() {
        var pageInstanceID;
        var pageID;
        var adID; // Container for ad Id from ad
        var fltID; // Container for flight Id from ad
        var adParams; // Container for ad params sent from ad
        var haveParsedPageLoad = false; // flags whether pageLoad tag has been parsed
    };

    /**
     * Array to hold impression BI calls until we are ready to process them
     */
    this.impressionQueue = [];

    /**
     * Returns an randon 18 digit integer that is based of the current time and a randomly generated integer
     * @return random 18 digit integer
     */
    this.randomID = function() {
        return  (new Date()).getTime()+""+Math.floor(Math.random()*1000+9999);
    };

    /**
     * Process for creating Cookie dependencies if they have not been done already
     */
    this.Audit = {
          _createAuditCookie: function(name,value) {
            document.cookie = name + "=" + value + "; path=/";
        },

        _readAuditCookie: function(name) {
            var nameEQ = name + "=";
            var ca = document.cookie.split(';');
            for(var i=0;i < ca.length;i++) {
                var c = ca[i];
                while (c.charAt(0)==' ') c = c.substring(1,c.length);
                if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
            }
            return null;
        }
    };

    /**
     * Logging of users "Audit Tag" to determine initial presence within the BI framework
     */
    this.processAudit = function() {
        // Assess if Audit "tag" has been fired into cookie
        if(!this.Audit._readAuditCookie("BIRF_Audit")) {
            this.log('', "Audit");
            this.Audit._createAuditCookie("BIRF_Audit", "true");
        }
    };

    /**
     * Function: Process of default and custom page load events
     *
     * The following params are set and logged by default using the custom JSP tag <birf:baseParams> that is generated
     * by a server side filter and appended to the end of the source: Page Instance, All Form Request Params,
     * myATC State.
     */
    this.processPageLoad = function(){
        var pageLoadParams = {};
        var baseBITag = this.getTag("baseParams");
        var baseBITagParams = this.getTags("baseParam", baseBITag);
        this._parseBIRFChildTags(baseBITagParams, pageLoadParams);

        this.shared.pageInstanceID = pageLoadParams['pg_inst'];
        delete pageLoadParams['pg_inst'];

        if (typeof cobrandLnx != "undefined") {
        if(this._isNotEmpty(cobrandLnx)){
            pageLoadParams['lnx'] = cobrandLnx;
            }
        };

        pageLoadParams['cur_url'] = document.location;
        pageLoadParams['ref_url'] = document.referrer;

        var pageLoadTag = this.getTag("pageLoad");
        var pageLoadTagParams = this.getTags("param", pageLoadTag);

        if(pageLoadTag != null){
            this.shared.pageID = pageLoadTag.getAttribute("pg");
            this._parseBIRFChildTags(pageLoadTagParams, pageLoadParams);
        };

        this.shared.haveParsedPageLoad = true;

        this.log(this._objectToQueryString(pageLoadParams), "page");

        this.processImpressionQueue();
    };

    /**
     * Accumulates, processes and logs Impression tags <birf:impression>.
     * Sets position and count of impressions
     */
    this.processImpressions = function() {
        // Obtain all the impression tags within the page
        var impressions = this.getTags("impression");
        var impressionString = "";
        var impLength = impressions.length;


        if(impLength > 0){
            for (var i=0; i<impLength; i++) {
                var impressionParams = {};

                // Process Base Param Child Tag Attributes
                this._parseBIRFAttributes(impressions[i], impressionParams);

                //
                var impressionsExtras = this.getTags("extra", impressions[i]);
                this._parseBIRFChildTags(impressionsExtras, impressionParams, "key", "value");

                impressionString += this._objectToQueryString(impressionParams) + '&';
            }
            // Push Object to a string and send to Logging Utility
            this.log(impressionString.substring(0, impressionString.length-1), "impression");
        }
    };

    /**
     * Accumulates, processes and logs Impression tags <birf:impression>.
     * Sets position and count of impressions
     */
    this.processImpressions2 = function() {
        // Create Object Container to store Component Id Types and their individual counts
        var componentTypes = {};

        // Obtain all the impression tags within the page
        var impressions = this.getTags("impression");
        var impressionString = "";

        var impLength = impressions.length;

        if(impLength > 0){
            for (var i=0; i<impLength; i++) {

                var impressionParams = {};

                // Log Components and Set Positions
                var cmpType = impressions[i].getAttribute("cmp");
                impressionParams["cmp_"+ i] =  cmpType;

                var componentIndex = componentTypes[cmpType];

                if (this._isEmpty(componentIndex)) {
                    componentTypes[cmpType] = 1;
                } else {
                    componentTypes[cmpType] = componentIndex + 1;
                }

                impressionParams["po_" + i] =  componentTypes[cmpType];

                // Process the rest of the impression attributes
                var attrs = impressions[i].attributes;
                var attrsLen = attrs.length;
                for (var j=0; j<attrsLen; j++) {
                    if (attrs[j].specified) {
                        impressionParams[attrs[j].name + '_' + i] = attrs[j].value;
                    }
                }

                // Obtain any extra parameters and add them to the log collection
                var impressionsExtras = this.getTags("extra", impressions[i]);
                for(var k=0; k<impressionsExtras.length; k++) {
                    var val = impressionsExtras[k].getAttribute("value");
                    if (val == "null") val = "";
                    impressionParams[impressionsExtras[k].getAttribute("key")+ '_'+ i] = val;
                };

                impressionString += this._objectToQueryString(impressionParams) + '&';
            };

            // Push Object to a string and send to Logging Utility
            this.log(impressionString.substring(0, impressionString.length-1), "impression");
        };
    };

    /**
     * Build an impression tag programmatically--for areas of the page that are rendered later, we can
     * generate an impression manually.  To avoid becoming overly chatty, we push these to a queue.  Impressions
     * created by this tag will not be logged until you call BIRF#processImpressionQueue
     * @param data object hash that contains the impressionAttributes (cmp, po, par, v, c, s, m, co)
     * @param fireImmediate Log this tag immediately bypassing the impression queue
     */
    this.buildImpression = function(data, fireImmediate){
        var impressionParams = {};
        // Temp removal of Impression functionality 
//        this.impressionAttributes.each(function(attribute){
//            impressionParams[attribute + '_' + this.impressionQueue.length] = data[attribute];
//        }.bind(this));
//        if(fireImmediate){
//            var iString = Object.toQueryString(impressionParams);
//            this.log(iString, "impression");
//        } else {
//            this.impressionQueue.push(impressionParams);
//        }
    };

    /**
     * Fires the impression tags generated by buildImpression and clears the queue.
     */
    this.processImpressionQueue = function(){
        if(this.impressionQueue.length > 0){
            var impressionString = "";
            this.impressionQueue.each(function(impression){
                impressionString += this._objectToQueryString(impression);
            });
            this.log(impressionString.substring(0, impressionString.length-1), "impression");
            this.impressionQueue = [];
        }
    };

    /**
     * Delegates Click Logging Capabilites to all applicable links
     */
    this.processLinks = function(){
        var obj = this;
        this._observe(document, "click",  function(e) {
            if (obj._findElement(e, "a")) {
                obj.logAnchorClick(e);
            }
        });
    };



    this.logAnchorClick = function(e) {
        var link = this._findElement(e, "a");

        var actionParams = {};
        actionParams['type'] = 'click';
        actionParams['t_url'] = link.getAttribute("href");

        if (this._isNotEmpty(this._stringContent(link))) {
            actionParams['co_txt_url'] = this._stringContent(link).replace(/[\r\n\s+]+/g, " ");
        }

        if (this._isNotEmpty(link.getAttribute("title"))) {
            actionParams['linktitle'] = link.getAttribute("title");
        }

        this.processLinkImageElements(link, actionParams);

        var clickTag = this.getTag("click",link);

        if (this._isNotEmpty(clickTag)) {
            this._parseBIRFAttributes(clickTag, actionParams);
        };

        this.log(this._objectToQueryString(actionParams), "click");
    };

    /**
     * Obtains image information for img emlements within links
     * */
    this.processLinkImageElements = function(link, collection) {
        // Process Images within clicked element if they exist
        var imgNodes = link.getElementsByTagName('img');
        if (this._isNotEmpty(imgNodes)) {
            var imageSrcs = [];
            var imageTitles = [];
            var imageAlts = [];

            for (var i = 0; i<imgNodes.length; i++) {
                imageSrcs.push(imgNodes[i].getAttribute("src"));
                imageTitles.push(imgNodes[i].getAttribute("title"));
                imageAlts.push(imgNodes[i].getAttribute("alt"));
            };

            collection['imagesrc'] =  imageSrcs;
            collection['imagetitle'] = imageTitles;
            collection['imagealt'] = imageAlts;
        }
    };

    /**
     * Intiates logging of submit form values and appends reference for use on subsequent page
     */
    this.processForms = function() {
       var obj = this;
        this._observe(document, "fake:Submit", function(e){
            obj.logFormValues(e);
        });
    };

    /**
     * Logs submitted form values
     */

    this.logFormValues = function(e) {
        // Stop Event Bubbling in nested forms
        this._stop(e);

        // Capture form that has been submitted
        var form = this._eventTarget(e);

        // Create object container to place all key value pairs to be logged and set base event params
        var formParams = {};
        formParams['type'] = "submit";
        formParams['f_nm'] = form.getAttribute('name');
        formParams['t_url'] = form.getAttribute('action');

        // Capture all form elements and their values at submission
        var formInputs = this._getFormElements(form);
        var formInputsLen = formInputs.length;
        for (var i=0; i<formInputsLen; i++ ) {
            formParams[formInputs[i].getAttribute("name")] =  formInputs[i].value;
        };

        // Obtain Submit Tag and any Children
        var formSubmitTag = this.getTag("submit", form);

        if (this._isNotEmpty(formSubmitTag)) {
            this._parseBIRFAttributes(formSubmitTag, formParams);
        }

        // Push object to a string and send to Logging Utility
        this.log(this._objectToQueryString(formParams), "event");
    };


    /**
     * Process and log custom click events
     */
    this.processCustomClicks = function() {
        this.customClickTags = this.getTags("customClick");
        this.customClickIds = [];

        for (var i=0; i<this.customClickTags.length; i++) {
            this.customClickIds.push(tag.getAttribute("domID"));
        }

        this._observe(document, "click", function(e){
            if(this.customClickIds.indexOf(e.element().getAttribute("id")) >= 0){
                this.logCustomClick(e);
            }
        });
    };

    /**
     * Logs custom click events
     * @param e click event
     */
    this.logCustomClick = function(e) {
        var el = _eventTarget(e);
        var actionParams = {};
        actionParams['type'] = 'click';
        actionParams['cmp_id'] = 'click';

        // Set Link Text in Param object
        if (this._isNotEmpty(this._stringContent(el))) {
            actionParams['co_txt_url'] =this._stringContent(el).replace(/[\r\n\s+]+/g, " ");
        }

        // Push object to a string and send to Logging Utility
        this.log(this._objectToQueryString(actionParams), "event");
    };



    /**
     * Sends Log Request to the server
     *@param rowId      the log request's row id
     *@param logString  the logString to be chunked
     *@param logtype    the type of log request
     **/
    this.log = function(logString, logtype, rowId){
        // Check to see if rowId has been supplied (from chunking method)- if not create a new one
        var rowIdValue;
        var chunking = false;

        if (this._isEmpty(rowId)) {
            rowIdValue = this.randomID();
        } else {
            rowIdValue = rowId;
            chunking = true;
        }

        // Set Base Log Params that will be attached to all Log Requests
        var baseLogParams = new Object;
        baseLogParams.row = rowIdValue;
        baseLogParams.Log = 0;
        baseLogParams.pg_inst = this.shared.pageInstanceID;
        baseLogParams.pg = this.shared.pageID;

        // Check log length - if less than 1400 then send to logs, if not then send to chunking utility
        if (logString.length <= 1400) {
            this.sendLogRequest(logtype, logString, baseLogParams);
        } else if (!chunking) {
            this.logMultipart(logString, logtype);
        }
    };

    this.sendLogRequest = function(logtype, logString, baseLogParams) {
        var url = this.constructLogRequest(logtype, logString, baseLogParams);

        this._ajaxRequest(url);
        if (logtype == "click" || logtype == "event") {
            this._pause(500);
        };
    };

/**
 * Constructs url structure to send to logs
 * @param logtype the type of log that is being processed
 * @param logString the string that will be appended to url to be processed by BI
 * @param baseLogParams the base log params that are sent with all log requests
 *
 * @return url log string to be sent out
 */
    this.constructLogRequest = function(logtype, logString, baseLogParams) {
        if (logtype == "click") logtype = "event";

        // Determine prefix ot send to logs
        var prefix;
        switch (logtype) {
            case "impression" :
                prefix = "/no_cache/bi_imp";
                break;

            case "event" :
                prefix = "/no_cache/bi_event";
                break;

            case "ad" :
                prefix = "/no_cache/bi_advr";
                break;

            case "page" :
                prefix = "/no_cache/bi_page";
                break;

            case "subPage" :
                prefix = "/no_cache/bi_subpage";
                break;

            case "Audit" :
                prefix = "/no_cache/bi_audit";
                break;
        }

        // Append base Params
        var url = prefix + '?' + this._objectToQueryString(baseLogParams);

        // Append log String if there is one
        if(logString.length != 0 ) {
            url += '&' + logString;
        }
        return url;
    };

    /**
     * Establishes shared Row Id for chunked Log Requests and sends Log String to chunking method
     * @param logString the log request string
     * @param logtype   the type of log request
     * */
    this.logMultipart = function(logString, logtype) {
        var rowId = this.randomID();
        this.splitMultipartStringAndLog(rowId, logString, logtype);
    };

    /**
     * Chunks Log Strings into 1300 character sections and sends to BI as seperate Log Requests
     *@param rowId      the log request's row id
     *@param logString  the logString to be chunked
     *@param logtype    the type of log request
     **/
    this.splitMultipartStringAndLog  = function(rowId, logString, logtype) {
        if (logString.length > 0) {
            var logIndex = logString.length;

            if (logString.length > 1300) {
                logIndex = logString.substring(0, 1300).lastIndexOf("&");
            }

            if (logIndex < 0) {
                logIndex = logString.length;
            }

            this.log(logString.substring(0, logIndex), logtype, rowId);
            this.splitMultipartStringAndLog(rowId, logString.substring(logIndex + 1, logString.length), logtype);
        }
    };

    /**
     * Stores Ad Parametes for reuse in logging
     *@param adid           the Ad's Id
     *@param flightid       the Ad's flight Id
     *@param segVarString   query string containing the segvar parameters passed to the ad
     * */

    this.setAdParams = function(adid, flightid, segVarString) {
        this.shared.adID = adid;
        this.shared.fltID = flightid;
        this.shared.adParams = segVarString;
        this.logAdParams();
    };

    /**
     * Checks to see if dependent logging variables have been established
     * If such variable have been created then the ad logging function is fired.
     * else we check until they are established
     * */
    this.logAdParams = function() {
        if (this.shared.haveParsedPageLoad) {
            this.log('ad=' + this.shared.adID + '&flt=' + this.shared.fltID + '&' + this.shared.adParams, "ad");
        } else {
            setTimeout(function(){BIRF.logAdParams();}, 500);
        }
    };
}

/**
 * Inherit BI Library into Class and Instantiate BIRF
 * */
BIFramework.prototype = BIFrameworkLibrary;
BIFramework.prototype.parent = BIFrameworkLibrary;
var BIRF = new BIFramework();



function birfStartup() {
    /**
     * Startup BI Engine
     * */
    BIRF.init();


     /**
     * Captures form submissions, fires custom event to set off form logs, refires submit event
     */
    if(window.HTMLElement){
        var cached_submit = HTMLFormElement.prototype.submit;  //reference the original function
        var new_submit = function(args) {
                BIRF._fireEvent(this, "fake:submit");
            return cached_submit.apply(this, args);
        };
        HTMLFormElement.prototype.submit = new_submit;
    } else {
        // IE6 Specific
        for(var i=0; i<document.forms.length; i++){
            var form = document.forms[i];
            form._submit = form.submit;
            form.submit = function() {
                var fakeEventObj = {};
                fakeEventObj.srcElement = this;
                BIRF.logFormValues(fakeEventObj);
                this._submit();
            };
        };
    }
};





// for Internet Explorer (using conditional comments)
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
  if (this.readyState == "complete") {
    birfStartup(); // call the onload handler
  }
};
/*@end @*/

if (document.addEventListener) {
  document.addEventListener("DOMContentLoaded", birfStartup, false);
}














/**
 * Possibly deprecated functions that need to be revisited
 * */

BIRF.executeFunctionByName = function(functionName, context /*, args */) {
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    if ((func != null) && context[func]) return context[func].apply(this, arguments);
};

BIRF.executeFunctionByNameArgs = function(functionName, context, args) {
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }

    for (var j=0;j<args.length;j++) {
        args[j] = args[j] + '';
        args[j] = args[j].replace(new RegExp("'","g"),"").replace("%20"," ").replace(/^\s+|\s+$/g,"");;
    }
    args = Array.prototype.slice.call(args);
    if ((func != null) && context[func]) return context[func].apply(this, args);
};

// Tag events on 3rd party non-anchor elements that will not be available until after page load
BIRF.tagEvents = function(tagList) {
    var keepWaiting = false;
    for (var i=0; i<tagList.length; i++) {
        var parms = tagList[i];
        if (parms != null) {
            var tagId = parms["id"];
            if (tagId != "") {
                var el = document.getElementById(tagId);
                if (el != null) {
                    Event.observe(el, 'click', this.tag_click.bindAsEventListener(this, el));

                    // attach bi attributes to 3rd party elements for events
                    for (var name in parms) {
                        if (name !== "id") {
                            el[name]=parms[name];
                        }
                    }
                    tagList[i]=null;
                } else {
                    keepWaiting = true;
                }
            }
        }
    }
    if (keepWaiting) setTimeout(function(){ BIRF.tagEvents(tagList); },50);
};

BIRF.tagEventsRange = function(tagName,first,last) {
    var tagList = "";
    for (var i=first; i<=last; i++) {
        if (tagList.length>0) tagList += ",";
        tagList += tagName.replace("#",i);
    }
    if (tagList.length>0) this.tagEvents(tagList);
};

// This is the event processor for 3rd party non-anchor elements
// It is assumed that the page will not be reloaded so event bubbling will not be stopped
BIRF.tag_click = function(e) {
    //        document.title="tag click:"+e.element().tagName+"-"+this.randomID();
    if (Event.isLeftClick(e)) {

        var parentEl = (e.element().id) ? e.element() : e.element().up();
        var parentId = parentEl.id;

        var link = e.element();

        var actionParams = {};

        if (this._isNotEmpty(this._stringContent(link))) {
            actionParams['co_txt_url'] = this._stringContent(link).replace(/[\r\n\s+]+/g, " ");
        }

        if (this._isNotEmpty(link.getAttribute("title"))) {
            actionParams['linktitle'] = link.getAttribute("title");
        }

        var biCallBack = link.getAttribute("bicallback");
        if (biCallBack) {
            this.executeFunctionByName(biCallBack, window, actionParams, link);
        }

        for (var name in parentEl) {
            if (name.indexOf("bi_") == 0) {
                actionParams[name.substring(3)]=parentEl[name];
            }
        }

        var imgNodes = link.select('img');

        if (this._isNotEmpty(imgNodes)) {
            var imageSrcs = $A();
            var imageTitles = $A();
            var imageAlts = $A();
            imgNodes.each(function(img) {
                imageSrcs.push(img.getAttribute("src"));
                imageTitles.push(img.getAttribute("title"));
                imageAlts.push(img.getAttribute("alt"));
            });

            if ((imageSrcs.length>0) || (imageTitles.length>0) || (imageAlts.length>0)) {
                actionParams['imagesrc'] =  imageSrcs;
                actionParams['imagetitle'] = imageTitles;
                actionParams['imagealt'] = imageAlts;
            }
        }
        //short timeout so FF and IE have to to log the event and get a 200 back in the request
        setTimeout(function(){BIRF.log(Object.toQueryString(actionParams), "event");},50);
    }
};

BIRF.logEventParams = function(eventType, eventParams) {
    if (eventType == "click") { eventType = "event"; }
    this.log(Object.toQueryString(eventParams), eventType);
};

BIRF.logEventMakeParams = function(eventType, params) {
    if (eventType == "click") { eventType = "event"; }
    var eventParams = $H();
    var parts = params.split(",");
    for (var i=0;i<parts.length;i++) {
        var pairs = parts[i].split("=");
        if (pairs.length==2) {
            eventParams.set(pairs[0],pairs[1]);
        }
    }
    this.log(Object.toQueryString(eventParams), eventType);
};

BIRF.subpage = function(){
//    this.processSubPage();
//    this.processImpressions();
};

BIRF.processSubPage = function(){
    var subPages = this.getTags("subPage");
    var subPageString = "";

    if(subPages != null){
        $A(subPages).each(function(subPageTag, i){
            var subPageParams = {};
            subPageParams['type'] = 'click';

            // Process the rest of the subPage attributes
            var subPageAttributes = ["spg"];
            $A(subPageAttributes).each(function(attribute) {
                subPageParams[attribute + '_' + i] = subPageTag.getAttribute(attribute);
            }.bind(this));

            var subPageExtras = this.getTags("extra", subPageTag);

            $A(subPageExtras).each(function(extra){
                subPageParams[extra.getAttribute("key")+ '_'+ i] = extra.getAttribute("value");
            });

            subPageString += subPageParams.toQueryString();
        }.bind(this));
        this.log(subPageString, "subPage");
    }
};