/**
 * Allows BI framework to capture and process all form submissions
 * @param event the submit event
 */
//function newsubmit(event) {
//    var target = event ? event.target : this;
//    $(target).fire("fake:submit");
//    // call real submit function - we may need to come up a better idea
//    // delayed to allow log to fire
//    // setTimeout(function(){ this._submit(); }.bind(this), 500);
//    this._submit();
//}
//
//
//
//
//document.observe("dom:loaded", function() {
//    if(window.HTMLElement){
//        HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit;
//        HTMLFormElement.prototype.submit = newsubmit;
//    } else {
//        for(var i=0; i<document.forms.length; i++){
//            document.forms[i]._submit = document.forms[i].submit;
//            document.forms[i].submit = function(event) {
//                var target = event ? event.target : this;
//                $(target).fire("fake:submit");
//                // call real submit function
//                this._submit();
//            };
//        };
//    }
//});




/**
 * Prototype Extension that cleans up crossbrowser processing of link text
 * @return string the link text
 */
Element.addMethods({
    stringContent :function(el){
        var content = "";
        if(typeof document.body.innerText == 'undefined'){
            content = el.textContent;
        } else {
            content = el.innerText;
        }
        return content;
    }
});





/**
 * ATC BI Reporting Framework
 */
var BIRF = {
    /**
     * Declaration of the BI namespace
     */
    ns:"birf",

    /**
     * Arrays of common BI custom tag keys
     */
    impressionAttributes: ["cmp","po","par","v","c","s","m","co","gs","bph","dlg","re","pt"],
    clickTagAttributes: ["cmp","par","c","v"],

    /**
     * Container for shared BIRF variables
     */
    shared:{
        pageInstanceID:"",
        pageID:"",
        adID:"", // Container for ad Id from ad
        fltID:"", // Container for flight Id from ad
        adParams:"", // Container for ad params sent from ad
        haveParsedPageLoad:false, // flags whether pageLoad tag has been parsed
        cachedOnClick:'', // container for onclick functions of interacted with links
        anchorRedirectsPage:true, // determines whether page is redirected via anchor href or onlcick functionality
        onClickRedirectors:["openPopWin", "BILogUtil.Redirector", "popCreditApp"] // array of functions known to redirect page via onclick
    },

    /**
     * Array to hold impression BI calls until we are ready to process them
     */
    impressionQueue: [],

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





    /**
     * BIRF Initilaization Fucntion
     */
    init:function(){
        this.initBIRFCookieJar();
        this.processPageLoad();
        this.processAudit();
        this.processImpressions();
        this.processLinks();
       // this.processCustomClicks();
//        this.processForms();
    },





    /**
     * Process for creating Cookie dependencies if they have not been done already
     */
    initBIRFCookieJar: function() {
        // Create BIRF specific Cookie Collection
        this.birfSession = new CookieJar({
            expires:'',
            path: '/'
        });
    },





    /**
     * 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.
     */
    processPageLoad:function(){

        // Create Object container to place all key value pairs to be logged
        var pageLoadParams = {};

        var baseBITag = this.getTag("baseParams");
        var baseBITagParams = this.getTags("baseParam", baseBITag);

        // Process Base Param Child Tag Attributes
        this.processChildBITags(baseBITagParams, pageLoadParams);

        // Set Shared Page Instance and remove from pageLoadParams so it is not logged twice
        this.shared.pageInstanceID = pageLoadParams['pg_inst'];
        delete pageLoadParams['pg_inst'];

        // Process LNX Code
        if (typeof cobrandLnx != "undefined") {
        if(!this.isEmpty(cobrandLnx)){
            pageLoadParams['lnx'] = cobrandLnx;
            }
        };

        // Set Current Location and Referring URL
        pageLoadParams['cur_url'] = document.location;
        pageLoadParams['ref_url'] = document.referrer;

        // Process Page Load Tag
        var pageLoadTag = this.getTag("pageLoad");
        var pageLoadTagParams = this.getTags("param", pageLoadTag);

        if(pageLoadTag != null){
            // Set the page attribute as a shared param to be appended to all log requests
            this.shared.pageID = pageLoadTag.getAttribute("pg");
            // Process Base Param Child Tag Attributes
            this.processChildBITags(pageLoadTagParams, pageLoadParams);
        };

        // Set flag that pageLoad has been parsed dependent methods may fire
        this.shared.haveParsedPageLoad = true;

        // Log the Page Load Event
        this.log(Object.toQueryString(pageLoadParams), "page");

        // Clear out the impression queue of any generated impressions
        this.processImpressionQueue();
    },





    /**
     * Logging of users "Audit Tag" to determine initial presence within the BI framework
     */
    processAudit: function() {
        // Assess if Audit "tag" has been fired into cookie
        // If not log audit tag and set tag to fired
        if(this.birfSession.get('birfAudit') ==  null) {
            this.log('', "audit");
            this.birfSession.put('birfAudit', {auditValue: true});
        };
    },





    /**
     * Accumulates, processes and logs the Impression tags <birf:impression> that have been place within the source code.
     */
    processImpressions: 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 = "";

        if(impressions.length != 0){
            $A(impressions).each(function(impression, i){
                var impressionParams = {};

                // Log Components and Set Positions
                var cmpType = impression.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
                $A(this.impressionAttributes).each(function(attribute) {
                    var val = impression.getAttribute(attribute);
                    if (val == "null") val = "";
                    impressionParams[attribute + '_' + i] = val;
                }.bind(this));

                var impressionsExtras = this.getTags("extra", impression);

                // Obtain any extra parameters and add them to the log collection
                $A(impressionsExtras).each(function(extra){
                    var val = extra.getAttribute("value");
                    if (val == "null") val = "";
                    impressionParams[extra.getAttribute("key")+ '_'+ i] = val;
                });
                impressionString += Object.toQueryString(impressionParams) + '&';
            }.bind(this));

            // 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
     */
    buildImpression: function(data, fireImmediate){
        var impressionParams = {};
        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.
     */
    processImpressionQueue: function(){
        if(this.impressionQueue.length > 0){
            var impressionString = "";
            this.impressionQueue.each(function(impression){
                impressionString += Object.toQueryString(impression);
            });
            this.log(impressionString.substring(0, impressionString.length-1), "impression");
            this.impressionQueue = [];
        }
    },




    /**
     * Delegates Click Logging Capabilites to all applicable links
     */
    processLinks:function(){
        document.observe("click",  this.clickEventIntercept.bindAsEventListener(this));
    },





    /**
     * Intercepts the user initiated click event and then initiates the logging method
     * @param e click event
     */
    clickEventIntercept: function(e) {
        // Evaluate whether user is clicking to invoke action
         if (e.isRightClick() || !Event.findElement(e, "a")) return false;

        // Initiate Data collection of Click Event
        this.logAnchorClick(e);
    },

    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);
    },

    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 i=0;i<args.length;i++) {
            args[i] = args[i] + '';
            args[i] = args[i].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);
    },

    logAnchorClick: function(e) {
        // Obtain parent anchor tag of click event if click event is on children
        var link = (e.element().tagName.toLowerCase() == 'a') ? e.element() : e.element().up('a');

        // Create and set Base Click Event Logging Params
        var actionParams = {};
        actionParams['type'] = 'click';
        actionParams['t_url'] = link.getAttribute("href");

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

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

        // Set Link Title in Param object
        if (!this.isEmpty(link.getAttribute("title"))) {
            actionParams['linktitle'] = link.getAttribute("title");
        }

        // Process Images within clicked element if they exist
        var imgNodes = link.select('img');

        if (!this.isEmpty(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"));
            });

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

        var clickTag = this.getTag("click",link);
        if (!this.isEmpty(clickTag)) {
            //             var clickTagAttributes = ["cmp", "par", "c"];
            $A(this.clickTagAttributes).each(function(attribute) {
                actionParams[attribute] = clickTag.getAttribute(attribute);
            }.bind(this));
        };

        this.log(Object.toQueryString(actionParams), "click")
    },




    /**
     * Process and log custom click events
     */
    processCustomClicks: function() {
        this.customClickTags = this.getTags("customClick");
        this.customClickIds = $A();
        $A(this.customClickTags).each(function(tag) {
            this.customClickIds.push(tag.getAttribute("domID"));
        }.bind(this))

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




    /**
     * Intiates logging of submit form values and appends reference for use on subsequent page
     */
    processForms: function() {
        document.observe("fake:submit", function(e){
            if(e.element().tagName.toLowerCase() == "form"){
                this.logFormValues(e);
            }
        }.bindAsEventListener(this));
    },



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

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

        // Push object to a string and send to Logging Utility
        setTimeout(function(){BIRF.log(Object.toQueryString(actionParams), "event");},50);
    },





    /**
     * Logs submitted form values
     */

    logFormValues: function(e) {
        // Stop Event Bubbling in nested forms
        e.stop();

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

        // 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 baseFormInputs = form.getElements();
        baseFormInputs.each(function(formInput) {
            formParams[formInput.getAttribute("name")] =  formInput.getValue();
        });

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

        // Obtain and override attribute if they exist on the Submit Tag
        if (!this.isEmpty(formSubmit)) {
            var formSubmitAttributes = ["cmp"];
            $A(formSubmitAttributes).each(function(attribute) {
                formParams[attribute] =  formSubmit.getAttribute(attribute);
            }.bind(this));
        }

        // Push object to a string and send to Logging Utility
        // short timeout so FF and IE have to to log the event and get a 200 back in the request
        this.log(Object.toQueryString(formParams), "event");
    },





    // Tag events on 3rd party non-anchor elements that will not be available until after page load
    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 (name in parms) {
                            if (name !== "id") {
                                el[name]=parms[name];
                            }
                        }
                        tagList[i]=null;
                    } else {
                        keepWaiting = true;
                    }
                }
            }
        }
        if (keepWaiting) setTimeout(function(){ BIRF.tagEvents(tagList); },50);
    },

    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
    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.isEmpty(link.stringContent())) {
                actionParams['co_txt_url'] = link.stringContent().replace(/[\r\n\s+]+/g, " ");
            }

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

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

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

            var imgNodes = link.select('img')

            if (!this.isEmpty(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);
        }
    },

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

    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 Utility that is called to process all necessary BI logging during Ajax page interactions
     *
     */
    subpage:function(){
        this.processSubPage();
        this.processImpressions();
    },





    /**
     * Process of <birf:subPage> tag that is placed within Ajax portions of the sit
     *
     */
    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) {
                    var attributeValue = subPageTag.getAttribute(attribute);
                    subPageParams[attribute + '_' + i] = attributeValue;
                }.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");

        }
    },


    isEmpty:function(s){
        return s == null || typeof s == null || s.length <= 0;
    },

    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;
            }
        }
    },

    getTagName:function(tag){
        return Prototype.Browser.IE ? tag : this.ns + ":" + tag;
    },

    pause: function(ms) {
        var now = new Date();
        var exitTime = now.getTime() + ms;
        while (true) {
            now = new Date();
            if (now.getTime() > exitTime)
                return;
        }
    },

    processChildBITags: function(childCollection, paramCollection, n, v) {
        var name = (n) ? n : 'name';
        var value = (v) ? v : 'value';

        if(!this.isEmpty(childCollection)) {
            $A(childCollection).each(function(child) {
                var val = child.getAttribute(value);
                if (val == "null") val = "";
                paramCollection[child.getAttribute(name)] = val;
            }.bind(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 = this.isEmpty(rowId) ? this.randomID() : rowId;

        // 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 {
            this.logMultipart(logString, logtype);
        }
    },

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

        new Ajax.Request(url, {method:"Get", requestHeaders:{"cache-control":"no-cache"}});
        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
 */
    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;
        }

        // Determine url structure to send to logs
        var url;
        if (logString.length == 0) {
            url = prefix + '?' + Object.toQueryString(baseLogParams);
        } else {
            url = prefix + '?' + Object.toQueryString(baseLogParams) + '&' + logString;
        }

        return url;
    },





    /*
     * Establishes shared Row Id for chunked Log Requests and sends Log String to chunking method
     *
     * */
    logMultipart: function(logString, logtype) {
        var rowId = this.randomID();
        this.splitMultipartStringAndLog(rowId, logString, logtype);
    },






    /*
     * Recursively Chunks Log Strings into 1300 character sections and sends to BI as seperate Log Requests
     *
     * */
    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);
        }
    },

    /*
     * Called from ad.html.base
     * Stores Ad Parametes for reuse in logging and IE6 required peroidic checking for dependent variables
     *
     * */

    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.
     *
     * */
    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);
        }
    }
}


/**
 * Instantiate ATC BI Framework
 * */
//Event.observe(window, "load", function() {
//    BIRF.init();
//});