/**
 * Everything that's specific to the product matching forms product-fit, find-credit-card, and gateway
 * There are page specific method overrides in each product-fit.js, find-credit-card.js, and gateway.js
 * for functionallity that differs.
 */
var productMatcher = {
    config:{
        fitOverridesCookie     : 'ca_product_match_fit_overrides',
        stateCookie            : 'ca_product_match',
        progressCookie         : 'ca_product_match_progress',
    
        pageCodeLookup         : 'fac',             // the key to lookup questions pagecodes in the form
        pageCodes              : {start:'',end:''}, // set in the form view, from the action defaults.
        completeSelector       : '#complete',       // the form complete text container
        questionSelector       : '#question-spot',  // the active question position
        compareLink            : '.compare-link',
        
        firstButton            : '.get-started',    // the first click function trigger
        clickElement           : '.click-spot a',   // the element to attach the "next" click function to
        
		
        // PROGRESS BAR RELATED
        
        progressBarSel         : '#progressbar',    // the div to attach the progress bar component to
        progressIncrement      : (100/6),           // the amount to increment the progress bar each question completed
        
        // SUGGESTED CARDS RELATED

        resetSel               : '.reset a',        // the anchor to click for form reset

        
		
        // the div containing the suggested cards
        suggestedCardsSel      : 'div.recommendations', 
        suggestedCardsUrl      : '', // set in the form view

        // the anchor to click to compare the suggested cards
        compareCardsSel        : 'div.recommendations div div.title a',
        compareCardsUrl        : '', // set in the form view
        
        // the message position to the right of the recommended cards
        recommendedMessageSel  : '#recommendedMessage',
        
        // when the form is complete, 
        completeRecommendedSel : '#completeRecommended',
        
        suggestedTitleSel        : '#suggestion-title',
        suggestedTitleInitialSel : '#suggestion-title-initial',
        suggestedTitleInterimSel : '#suggestion-title-interim',
        
        // the method to wrap the tracking functionallity around
        // this is necessary because product-fit and find-a-card
        // form make tracker.gif hits when the suggestedCardsCallback completes,
        // but the gateway doesn't have a suggestedCardsCallback and
        // so tracking happens after the processCallback completes.
        decorateForTracking    : ['suggestedCardsCallback','attachFirstClick','firstClick','reset']
    },
    
    progress:10,
    lastPageCode:LinkId.params.source,
    lastQuestionName:'',
    lpChatPageName:'',                   // a method set this to override tracking()
    lpChatSectionName:'',                // a method set this to override tracking()
    pageCode:'',                         // a method set this to override tracking()
    cg5:'',                              // a method set this to override tracking()
    cg4:'',                              // a method set this to override tracking()
    trackingLock:false,                  // a lock so the user may not proceed until tracking is complete
    skipTracking:false,                  // the gateway form needs to be able to skip tracking at some points
    waitedAmount:0,
    initialize:function(form) {
	    if((window.top && typeof(window.top.lpMTag)!='undefined' && typeof(window.top.lpMTag.lpSendData)!='undefined') || (typeof(lpMTag)!='undefined' && typeof(lpMTag.lpSendData)!='undefined') || this.waitedAmount >= 3000) 
	    {
		    this.formSetup(form);
	    }
	    else
	    {
			this.waitedAmount += 50;
		    setTimeout(function(){productMatcher.initialize(form)},50);
	    }
    },
formSetup:function(form){

        // we want to replace the source page code in the LinkId object
        // because we want the first transition to look as though it was between
        // the page referrer and the cookie determined state of the form
        // rather than the un-processed page.
        this.locSrcPC = LinkId.getFrom(window.document.location,'source');
        this.locSrcA = LinkId.getFrom(window.document.location,'area');
        this.locSrcSA = LinkId.getFrom(window.document.location,'subarea');
        if( this.locSrcPC ) // they may have hit the page directly, so no linkid would be in url
        {
            LinkId.set('source',this.locSrcPC);
            LinkId.set('area',this.locSrcA);
            LinkId.set('subarea',this.locSrcSA);
        }
        
        this.form = form;
        var here = this;

        // wrap some methods with a post-method-execution call to this.track() 
        this.decorateWithTracking();
        
        // determine what capabilities and in what environment the form is in
        this.establishContext();
        
        // the Ca_Form uses the stateCookie configuration value
        // for the cookie name to store state in
        form.config.stateCookie = this.config.stateCookie;
        form.reset();
        // attempt to restore state prior to associating the callback
        this.initProgressBar();
        this.restoreState();
        this.setupClicks();
        
        // the reset and compare cards links are in the suggested cards section
        if( this.hasSuggestedCards ) {
            $(here.config.resetSel).click(function(){
                if( here.trackingLock )
                    return;
                here.trackingLock = true;
                
                // setup the LiveChat click action
                here.setLiveChatClickAction();
                here.reset()
            });    
            this.compareCardsEnabled(false);
        }
    },
    
    setLiveChatClickAction:function() {},


    /**
     * Sets up the click events on the
     * initial Start and Next buttons of product-match
     */
    setupClicks:function() {
    
        // if the restore state put us on an input other than the first,
        // then attache the next click function instead of the first click
        if( this.form.processor.currentInput != this.form.inputsArray[0].name ) {
            this.attachNextClick();
        } else {
            this.pageCode = this.config.terminalPageCodes.start;
            this.cg4 = this.config.terminalCg4Values.start;
			this.lpChatPageName = this.config.terminalLpChatPageNames.start;
            this.attachFirstClick();
        }
    
    },

    /**
     * Determines whether we are running in an IFrame,
     * have a suggested cards section, and a progress bar
     */
    establishContext:function() {
        // on the product-fit popup, we need to have awareness that
        // links must open in the parent window.
        if( window.parent.parent && window.parent.parent!=window )
            this.inIFrame = true;
        else this.inIFrame = false;
        
        // the gateway page does not have a suggested cards section
        if( $(this.config.suggestedCardsSel).length == 0 )
            this.hasSuggestedCards = false;
        else this.hasSuggestedCards = true;
        
        if( $(this.config.progressBarSel).length == 0 )
            this.hasProgressBar = false;
        else this.hasProgressBar = true;
    },
///////////////////////////////   
    /**
     * Enable or disable the compare cards link
     */
    compareCardsEnabled:function(on) {
        if( this.hasSuggestedCards == false )
            return;

        var here = this;
        var disabled = function(){here.disabledCompareSuggestedCards();}
        var enabled = function(){here.compareSuggestedCards();}
        if( on == false )
        {
            $(this.config.compareCardsSel)
                .unbind( 'click' )
                .bind( 'click', disabled )
                .addClass('disabled' );
        } else {
            $(this.config.compareCardsSel)
                .unbind( 'click' )
                .bind( 'click', enabled )
                .removeClass('disabled' );
        }
    },

    /**
     * Show or Hide the Start Over 
     */
    resetShow:function(on) {
    	if(on == true){
    	    $(this.config.resetSel).show();
		}
    	else {
			$(this.config.resetSel).hide();
			
		}
    },


    /**
     * Triggered by clicking on the "Compare Cards" link in the card suggestion section.
     */
    compareSuggestedCards:function() {
        
        var form = $('<form id="compareCardsForm" target="_top" action="'+LinkId.replace(this.config.compareCardsUrl,'source',this.getPageCode())+'" method="post"><input type="hidden" name="compareType" value="Add"/></form>');
        for( var cardNumber = 1; cardNumber<=4; cardNumber++ )
        {
            var cardName = $('#card'+cardNumber).attr('card-name');
            if( typeof cardName !== undefined && cardName!=null )
                $(form).append('<input type="hidden" name="compareCards[]" value="'+cardName+'"/>');
        }
        $(document.body).append(form);
        setTimeout( function(){
            $('#compareCardsForm').submit();
        }, 500 );
    },
    disabledCompareSuggestedCards:function() {
        return false;
    },
///////////////////////////////   
    /**
     * Method is overridden by the specific page js using the form
     */
    attachFirstClick:function() {},
///////////////////////////////    
    attachNextClick:function() {
        var here = this;
        this.form.processor.processCallback = ['productMatcher','processCallback'];
        this.nextClickFunc = function(){ here.nextClick(); }
        $(this.config.clickElement).click(here.nextClickFunc);
    },
    /**
     * Clears out question related class variables
     * and calls process() for the current question
     */
    nextClick:function() {
        var proc = this.form.processor;
        var inp = this.form.inputs[proc.currentInput];
        this.clearFitOverrides();
        this.passback = null;
        if( inp )
        {
            var val = inp.domElement.getValue();
            var actualVal = inp.domElement.getActualValue();
            WebTracker.send({eventName:proc.currentInput + ':' + val,userInput:actualVal},'click','button');
        }
        if(proc.process()){
			this.resetShow(true);
		}
    },
    /**
     * Called by the Ca_Form_Processor_LogicalOperator each call to process()
     */
    processCallback:function(processor, input, value, passback) {
    
        this.passback = passback;
        if( ! this.passback ) {
            return;
        }
        
        // tracking depends on various member properties
        // and that state will be corrupted if we allow the
        // user to proceed prior to completion of tracking
        // this lock is set back to false in the function
        // wrapping methods named in this.config.decorateForTracking
        if( this.trackingLock && !this.skipTracking )
            return;
        this.trackingLock = true;
        
        // store the form state each question answered
        this.storeState();        
        
        // if the passback goes to another question
        // then advance the progress bar
        // and swap out the current question with the question indicated
        // by the passback object
        if( this.passback.type != 'result' ) {
	    this.lpChatPageName = null;
            this.swapOut( processor.form.inputs[this.passback.value].domElement );
            this.progress = this.progress + this.config.progressIncrement;
        } else {
            this.completeForm();
            
            //compare cards click - blue button on final screen
            var here = this;
            $(this.config.compareLink).click(function(){here.compareSuggestedCards();});
        }

        // get the suggested cards
        this.getSuggestedCards();  
        
        this.updateProgress(this.progress);
    },
    /**
     * Used to swap out the question section content with another element
     *
     * @param DomElement newOne The dom element to replace the current active question position with
     */
    swapOut:function(newOne) {
        var ele = $(this.config.questionSelector);
        ele.each(function(){
            while( this.firstChild )
                this.removeChild( this.firstChild );
            this.appendChild( newOne );
        });
    },
///////////////////////////////
    /**
     * Makes a call to the credit-card/product-match action
     * to determine what cards will populate in the suggested cards section.
     * Called by processCallback and restoreState
     */
    getSuggestedCards:function() {
    
        if( ! this.hasSuggestedCards)
            return;
		
		if( ! this.passback )
			this.clearCardSpots();
            
        // we pass in the page code from the current input,
        // so that the linkid's on details urls returned by
        // the productMatchAction will be correct.
        var url = LinkId.replace(this.config.suggestedCardsUrl,'source',this.getPageCode()) + '&pageCode=' + this.getPageCode() + '&' + Math.random();
        // The testcell may update via XP1, so we want to account for this.
		url = LinkId.replace(url,'testcell',linkIdParams.testcell);
		var here = this;
        var proc = this.form.processor;
        var inp = this.form.inputs[proc.currentInput];
        $.get(
            url,{},
            function(response) {
                here.suggestedCardsCallback(response);
            }
        );
    },
    /**
     * Triggered by the return of the post in getSuggestedCards
     */
    suggestedCardsCallback:function(response)
    {
        if( response.match(/SUCCESS/) )
        {
            // var 'result' is defined in the response
            eval(response);
            
            // clear out the old suggested cards
            this.clearCardSpots();
            
            // if card char codes are returned,
            // then put them in cg5 for the next track() call
            if( !this.cg5 && result.cardCharCodes )
            this.cg5 = 'LKP1-'+result.cardCharCodes;
            
            var cardNumber = 1;                
            for( var i in result.cards )
            {
                var current = result.cards[i];
                var detailsText = 'Click for details on the '+current.altAndTitle;
                
                var cardSpot = $('#card'+cardNumber).get(0);
                $(cardSpot).attr('card-name',i);
                
                var img = $('img',cardSpot);
                img.attr('src',current.thumbnail)
                img.attr('alt',detailsText);
                img.get(0).style.cursor='pointer';
                
                var anch = $('div.description a',cardSpot);
                anch.attr('title',detailsText);
                anch.html(current.name);
                anch.get(0).style.cursor='pointer';
                
                /*var add_name = $('div.description-ext', cardSpot);
                if ($.trim(current.name_ext))
                {
                    add_name.html(current.name_ext);
                    add_name.show();
                } else {
                    add_name.hide();
                }*/
                
                var here = this;
                var subarea = LinkId.getFrom(current.details,'subarea');
                var anch = $('a',cardSpot).each(function() {
                    if( $(this).hasClass('card-image') )
                        $(this).attr('href',
                            LinkId.replace(LinkId.replace(
                                current.details,
                            'subarea',((100+(new Number(subarea)+1))+'').substr(1)),'type','G')
                        );    
                    else $(this).attr('href',current.details);
                    $(this).attr('title',detailsText);
                    $(this).get(0).style.cursor='pointer';
                    if( here.inIFrame )
                        $(this).attr('target','_top');
                });
                    
                cardNumber ++;
            }
            
            // if there were no cards returned, 
            // then disable the compare cards link
            if( cardNumber == 1 ) {
                this.setSuggestedTitle( this.config.suggestedTitleInitialSel );                
                this.compareCardsEnabled(false);
            } else {
                this.setSuggestedTitle( this.config.suggestedTitleInterimSel );
                this.compareCardsEnabled(true);
            }
                      
            return result;
        }
    },
    setSuggestedTitle:function(sel) {
        if( this.lastSuggestedTitleSel != sel ) {
            $(this.config.suggestedTitleSel).html($(sel).html());
            this.lastSuggestedTitleSel = sel;
        }
    },
    clearCardSpots:function()
    {
        if( $(this.config.suggestedCardsSel).length == 0 )
            return;
        // now clear out spots we didn't update this call
        for( var i=1; i<=4; i++ )
            this.clearCardSpot(i);
    },
    /**
     * Clears out one of the suggested cards image spots
     */
    clearCardSpot:function(i)
    {
        var cardSpot = $('#card'+i).get(0);
        $(cardSpot).attr('card-name',null);
        
        var img = $('img',cardSpot);
        img.attr('src','/img/ca/cardfinder/module-card-shell.png');
        img.attr('alt','Blank spot');
        img.get(0).style.cursor='arrow';
        
        var anch = $('div.description a',cardSpot);
        anch.html('');
        anch.attr('href','javascript:void(0);');
        anch.attr('title','Blank spot');
        anch.get(0).style.cursor='arrow';
        
        /*var add_name = $('div.description-ext', cardSpot);
        add_name.html('');
        add_name.hide();*/
        
        var anch = $('a',cardSpot);
        anch.attr('href','javascript:void(0);');
        anch.attr('title','Blank spot');
        anch.get(0).style.cursor='arrow';
    },
///////////////////////////////
    /**
     * Appends a call to ::track() to methods in the this.config.decorateForTracking array
     */
    decorateWithTracking:function() {
        for( var i = 0; i < this.config.decorateForTracking.length; i++ )
        {
            var oldFuncName = this.config.decorateForTracking[i]+'_old';
            this[oldFuncName] = this[this.config.decorateForTracking[i]];
            eval(' \
                this[this.config.decorateForTracking[i]] = function(a,b,c,d,e,f) { \
                    var ret = this.'+oldFuncName+'(a,b,c,d,e,f); \
                    if( ! this.skipTracking ) \
                        this.track(); \
                    this.trackingLock = false; \
                    this.cg5 = null; \
                    this.cg4 = null; \
                    this.pageCode = null; \
                    return ret;\
                } \
            ');
        }
    },
    /**
     * There are three types of calls to tracking:
     * - on transition from the initial page to the 1st question
     * - from q1 to the next question
     * - from the last question to the completion
     * - from anywhere to q1
     */
    track:function() {

        var proc = this.form.processor;
        var inp = this.form.inputs[proc.currentInput];
        var pageCode = this.getPageCode();
        var lpChatPageName = this.getLpChatPageName();
        var lpSendDataVar = this.getLpSendDataVar();

        if(proc.currentInput)
        {
            var linkid = (pageCode != LinkId.get('source')) ? LinkId.outputId('G',pageCode) : null;
            
            if( this.cg4 ) 
	    {
                var cg4 = this.cg4;
	    }
            else {
                if( this.passback )
		{
                    var cg4 = this.passback.value;
		}
                else
		{	
			var cg4 = proc.currentInput;
		}
            } 
                
            if( this.cg5 )
                var cg5 = this.cg5;
            else var cg5 = '';
            
            window.cg4 = cg4 + ((cg4=='Intro') ? ((typeof xp_experience != 'undefined') ? '-' + xp_experience : '') : '');
            window.cg5 = cg5 + '-'+ linkIdParams.testcell;
            
            var parms = {
                cg1    : window.cg1,
                cg2    : window.cg2,
                cg3    : window.cg3,
                cg4    : window.cg4,
                cg5    : window.cg5,
                pn     : window.cg1 + '_' + window.cg2 + '_' + window.cg3 + '_' + window.cg4 + '_' + window.cg5
            };
            
            if( linkid )
                parms['linkid'] = linkid;
            $.vstrack(parms);
            
            // we are now on the page indicated by the last call to page code
            // so update the linkid's across the page to reflect that transition
            LinkId.set('source',pageCode);
            LinkId.replaceAll('source',pageCode);
			
	    if(lpChatPageName != null && lpChatPageName.indexOf('question')>=0)
	    { 
		    var lpStage=lpChatPageName;
	    }
	    else
	    {
		    var lpStage = cg4.replace(/q/,'question ');
	    }
	    if( (!this.inIFrame && typeof lpSendData == 'function')||(this.inIFrame && typeof window.top.lpSendData == 'function'))
	    {
		    if(this.inIFrame)
		    {
			window.top.lpSendData('page', lpSendDataVar, lpStage);
		    }
		    else
		    {
			lpSendData('page', lpSendDataVar, lpStage);
		    }
	    }
        }
		
        LinkId.set('area','C1');
        LinkId.set('subarea','01');
    },
    /**
     * Method pulls the page code of the current question
     * from the input configuration of the current input
     * being evaluated to be evaluated by the form processor
     * @return string The page code component of a link id associated to the current question
     */
    getPageCode:function() {
        if( this.pageCode )
            var pageCode = this.pageCode;
        else {
            var proc = this.form.processor;
            var inp = this.form.inputs[proc.currentInput];
			if(typeof inp  != 'undefined')var pageCode = inp.config.javascript.pagecode[this.config.pageCodeLookup];
			else var pageCode = proc.currentInput;
        }
        return pageCode;
    },
    /**
     * Method pulls the chat page name of the current question
     * from the input configuration of the current input
     * being evaluated to be evaluated by the form processor
     * @return string The chat page name associated to the current question
     */
    getLpChatPageName:function() {
        if( this.lpChatPageName )
            var lpChatPageName = this.lpChatPageName;
        else {
			var proc = this.form.processor;
			var inp = this.form.inputs[proc.currentInput];
			var lpChatPageName = inp.config.javascript.lpChatPageName;
		}
        return lpChatPageName;
    },
    /**
     * Method pulls the chat section name of the current question
     * from the input configuration of the current input
     * being evaluated to be evaluated by the form processor
     * @return string The chat section name associated to the current question
     */
    getLpSendDataVar:function() {
        if( this.lpSendDataVar )
            var lpSendDataVar = this.lpSendDataVar;
        else {
			var lpSendDataVar = this.config.lpSendDataVar;
		}
        return lpSendDataVar;
    },
///////////////////////////////
    initProgressBar:function() {
        if( this.hasProgressBar )
            $(this.config.progressBarSel).progressbar({value: this.progress});
    },
    /**
     * Updates the progress bar and stores the value in the progress session cookie
     */
    updateProgress:function(value) {
        if( ! this.hasProgressBar )
            return;
        $.cookie( this.config.progressCookie, value, {path:'/',domain:'.capitalone.ca'} );
        $(this.config.progressBarSel).progressbar( 'value', value );
        this.progress = value;
    },
////////////////////////////////
    /**
     * Called when the form is complete.
     * Shared functionallity between product-fit and find-credit-card.
     * Each page overwrites in it's own javascript file.
     */
    completeForm:function() {
        this.updateProgress(100);
        
        $(this.config.clickElement).css('display','none');
        
        // if the form has a suggested cards section,
        // replace the "recommended cards" text with the completion text.
        if( this.hasSuggestedCards )
        {
            var e = $(this.config.recommendedMessageSel).get(0);
            e.oldHtml = $(e).html();
            $(e).html($(this.config.completeRecommendedSel).html());
        }
        
        if( this.config.terminalPageCodes.end )
            this.pageCode = this.config.terminalPageCodes.end;
        if( this.config.terminalCg4Values.end )
            this.cg4 = this.config.terminalCg4Values.end;
        if( this.config.terminalLpChatPageNames.end )
            this.lpChatPageName = this.config.terminalLpChatPageNames.end;
    },
    /**
     * Reset the form to the beginning question.  Note that
     * all values are retained.
     */
    reset:function(){
        this.form.reset();
        this.form.resetState();
        
        this.passback = null;
        this.cg5 = null;
        this.lpChatPageName = null;
        this.swapOut( this.form.inputsArray[0].domElement );
        
        $(this.config.clickElement).show();
        
        this.updateProgress(10);
        
        if( this.hasSuggestedCards ) {
            var e = $(this.config.recommendedMessageSel).get(0);
            if( e.oldHtml )
                $(e).html(e.oldHtml);
            this.setSuggestedTitle( this.config.suggestedTitleInitialSel );
        }
        
        this.clearFitOverrides();
        
        this.clearCardSpots();
        
        this.compareCardsEnabled(false);
        this.resetShow(false);
    },
    clearFitOverrides:function() {
        $.cookie( this.config.fitOverridesCookie, '', {path:'/',domain:'.capitalone.ca'} );
    },
    /**
     * Stash the state of the form in a cookie for retrieval on a later page
     */
    storeState:function() {
        this.form.storeState();
    },
    /**
     * Restore the state of the form from the persistence mechanism.
     */
    restoreState:function() {

        this.passback = this.form.restoreState();
        if( this.passback && this.passback.type && this.passback.type.length>0 )
        {
            if( this.passback.type == 'result' ) {
                
                this.completeForm();
                
                //compare cards click - blue button on final screen
                var here = this;
                $(this.config.compareLink).click(function(){here.compareSuggestedCards();});
            } else if( this.passback.type.length > 0 )
                this.swapOut( this.form.inputs[this.form.processor.currentInput].domElement );
                
            this.updateProgress( new Number($.cookie(this.config.progressCookie)) );
        
            this.getSuggestedCards();
        } else {
            this.setSuggestedTitle( this.config.suggestedTitleInitialSel );
            this.resetShow(false);
            this.passback = null;
        }
        
        return this.passback;
    }
};
