/* Copyright Carsala, Inc 2009
 *
 *
 */

// See http://yuiblog.com/blog/2007/06/12/module-pattern/
YAHOO.namespace("Carsala");

// alias to the Yahoo object
var YUC = YAHOO.util.Connect;

/* Pulled from Prototype.js and Javascript: The Good Parts. When we create a "member" method
 * that points to a function the scope of "this" isn't always what we expect. For example, if
 * you have this.something = function () { references this } and you say
 * var otherthing = this.something when otherthing() is called, the local value of this will
 * be the function object from the initial assignment of this.something. 
 *
 * This becomes problematic if you need to assign member methods of an object as 
 * callbacks. The way around this is the following bind code. This allows you to 
 * "bind" the local this to the object this in the referenced function. For example:
 *
 * // won't work
 * doX : function () {
 *     document.getElementById("someid").onclick = this.doY;
 * }
 * 
 * // will work
 * doY : function () {
 *     document.getElementById("someid").onclick = this.doY.bind(this);
 * }
 *
 *
 */
Function.prototype.bind = function(that) {
    var method = this, slice = Array.prototype.slice, args = slice.apply(arguments, [1]);
    return function (  ) {
        return method.apply(that, args.concat(slice.apply(arguments, [0]))); 
    };
};



/** 
 * buildParamString(params) 
 * 
 * Given an array of key => value params, build a URL param string. Used 
 * with YUIGet. 
 */ 
function buildParamString(params) { 
    var collapse = new Array(); 
    for (var param in params) { 
        collapse.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param])); 
    } 
 
    return collapse.join("&"); 
} 
 
 
 
/** 
 * Clean '$', and ',' from currency values. 
 * 
 */ 
function sanitizeCurrency(value) { 
    value = new String(value); 
    re = /\$/g; 
    value = value.replace(re, ''); 
    re = /,/g; 
    value = value.replace(re, ''); 
    return value; 
} 
 
 
/** 
 * YUIGet(url, params, callbacks) 
 * 
 * Call a asyncRequest with method GET. This is just a wrapper function for building the  
 * url parameters and calling asyncRequest with the given callbacks. Might look like 
 * YUIGet('kbb/models', { makeid: 2 }, { success, failure }) 
 */ 
function YUIGet(url, params, callbacks) { 
    var param_string = buildParamString(params); 
    var sUrl = url + "?" + param_string; 
     
    return YUC.asyncRequest('GET', sUrl, callbacks); 
} 

/** 
 * YUIGetJSON(url, params, callbacks) 
 * 
 * Same as above except the params are passed as a JSON string appended to
 * the end of the URL string. 
 *
 * Example:
 * some/url/set/{"ModelId":3,"Years":[2003,2004]}
 * 
 */ 
function YUIGetJSON(url, params, callbacks) { 
    var param_string = YAHOO.lang.JSON.stringify(params); 
    var trailingSlash = new RegExp("/$");
    var sUrl = '';
    if (url.match(trailingSlash) === null) {
        sUrl = url + "/" + param_string; 
    } else {
        sUrl = url + param_string; 
    }
    YAHOO.log("YUIGetJSON: sending '" + sUrl + "' to the server");
     
    return YUC.asyncRequest('GET', sUrl, callbacks); 
} 
 
/** 
 * YUIPost(url, params, callbacks) 
 *  
 * See YUIGet above. Same, but for posts. Untested and may not work. The 
 * params will probably be passed differently. 
 */ 
function YUIPost(url, params, callbacks) { 
    var param_string = buildParamString(params); 
    var sUrl = url + "?" + param_string; 
     
    return YUC.asyncRequest('POST', sUrl, callbacks); 
} 


/** 
 * YUIPostJSON(url, params, callbacks) 
 * 
 * Same as above except the params are passed as a JSON string appended to
 * the end of the URL string. 
 *
 * Example:
 * some/url/set/{"ModelId":3,"Years":[2003,2004]}
 * 
 */ 
function YUIPostJSON(url, params, callbacks) { 
    //var param_string = YAHOO.lang.JSON.stringify(params); 
    var param_string = buildParamString(params); 
    YAHOO.log("YUIPostJSON: sending '" + url + "' and '" + param_string + "' to the server");
     
    return YUC.asyncRequest('POST', url, callbacks, param_string); 
} 


/**
 * Updates the feedback area according to the response with the given HTML, and sets up the ContactUs button if needed.
 */
function updateFeedbackArea(response) {
	//Update the HTML.
    if (response["Feedback"]["FullSvcHTML"] != undefined) {
        YAHOO.log("**** loading FullSvcHTML");
        YAHOO.util.Dom.get('fullSvcFeedbackContainer').innerHTML = response["Feedback"]["FullSvcHTML"];
    }

    if (response["Feedback"]["BestDealsHTML"] != undefined) {
        YAHOO.log("**** loading BestDealsHTML");
    	YAHOO.util.Dom.get('bestDealsFeedbackContainer').innerHTML = response["Feedback"]["BestDealsHTML"];

        // setup the ContinueToCheckout button. This button isn't like a picker in that
        // it links to a separate page so simply use a link to load.
        YAHOO.util.Event.addListener(document.getElementById('ContinueToCheckout'), 
                "click", 
                function () {
                    // send to the location configured via php
                    window.location = YAHOO.Carsala.ConfiguratorCartURL;
                });

    }
	
	//Hook up the Contact Us picker, if needed.
	YAHOO.Carsala.Picker.instances['ContactUs'].setupButton();
	
	//Go through all of the problematic pickers.
	for(var picker in YAHOO.Carsala.Picker.instances){
		var set = false;
		
		if(response['Feedback']['ProblemPickers'] != undefined){
			for(var problemPicker in response['Feedback']['ProblemPickers']){
				if(response['Feedback']['ProblemPickers'][problemPicker] == picker){
					YAHOO.Carsala.Picker.instances[picker].setProblematic(true);
					set = true;
				}
			}
		}
		
		if(set == false){
			YAHOO.Carsala.Picker.instances[picker].setProblematic(false);
		}
	}
	
	if(response["StartQuote"]==undefined)
	{
		var dumpEnabled = document.getElementById("allowDump");
		
		if(dumpEnabled != null && dumpEnabled != undefined) {
			
			YUIPost("getcsrsummary/", null, {
	                success: function (o){
	                    var serverResponse;
	                    try {
	                        serverResponse = YAHOO.lang.JSON.parse(o.responseText);
	                    } catch (E) {
	                        document.getElementById('HowToContainer').innerHTML = "Error occurred.";
	                        return;
	                    }
	                    
	                    if (serverResponse == null || serverResponse == undefined || serverResponse["Result"] == false) {
	                    	document.getElementById('HowToContainer').innerHTML = "Error occurred.";
	                        return;
	                        
	                    } else {
	                    	
	                    	var results = "<span class=\"dashboard_row\">Subset Summary &raquo; </span>";
	                    	
	                    	for (key in serverResponse['TopRow']) {
	                    		results = results + "<span class=\"dashboard_topelem\"><strong>" + 
                                    key + "</strong>" + ": " + serverResponse['TopRow'][key] + "</span>";
							}
                            results = results + "\n<br />";
                            results = results + "<span class=\"dashboard_row\">Color Summary &raquo; </span>";

	                    	for (key in serverResponse['ColorRow']) {
	                    		results = results + "<span class=\"dashboard_colorelem\"><strong>" + 
                                    key + "</strong>" + ": " + serverResponse['ColorRow'][key] + "</span>";
							}
                            results = results + "\n";
							
                            //document.getElementById('HowToContainer').innerHTML = results;
							                    	
	                    }
	                    
	                    
	                        
	
	                },
	                
	                failure: function (o){
	                    // document.getElementById('HowToContainer').innerHTML = "Error occurred.";
	                    return;
	                }
	                
	            });
            
		}
		
		// Call the google page tracker with the feedback result state we 
        // landed on. This bugs me to use a global variable here, but for now
        // I think it is ok to put it in the Carsala namespace
        if (YAHOO.Carsala.googlePageTracker === undefined || YAHOO.Carsala.googlePageTracker === null) {
            YAHOO.log("## can't log the feedback state; google page tracker undefined");
        } else {
            if (response['Feedback']['QuoteStatus'] !== undefined) { 
                YAHOO.Carsala.googlePageTracker._trackPageview(response['Feedback']['QuoteStatus']);
            } else {
                YAHOO.log("## can't log the feedback state; no QuoteStatus in feedback");
            }
        }
	}
}



/**
 * Utility method to change all radio/checkboxes inside an area
 * the the value specified. This is used to do select all / select
 * none.
 *
 * @param DOM object the area to select all/none
 * @param bool the value to set the checked attribute to
 */
var fnChangeSelectAll = function (area, value) {
    var options = area.getElementsByTagName('INPUT');

    for(var i=0; i<options.length; i++)
    {
        options[i].checked = value;
    }
}

function SetUIState(state) {
    YAHOO.log('*** Setting UI state to "'+state+'"');
    
	if(YAHOO.Carsala.currentPicker){
		YAHOO.log('*** hiding "'+YAHOO.Carsala.currentPicker+'"');
        var p = YAHOO.Carsala.Picker.instances[YAHOO.Carsala.currentPicker];
        p.closeUI();
    }
    
    //Close the Thanks dialog, if needed.
    YAHOO.util.Dom.get('ThanksDialog').style.display='none';
    YAHOO.util.Dom.get('EmailASearchThanksDialog').style.display='none';
    
    
    YAHOO.Carsala.Picker.instances['EmailASearch'].enable(); // Enable the Email a Search button.
    YAHOO.util.Dom.addClass('SaveThisSearchButton', 'active'); // Enable the Save this Search button.
        
	if(state != 'index'){
		//We're showing a page.
		switch(state){
			case 'Thanks':
			case 'EmailASearchThanks':
				var p = YAHOO.Carsala.Picker.instances['MakeModelYear'];
	            p.hidePickerArea();
	            YAHOO.util.Dom.get(state+'Dialog').style.display='block';
                break;
			
			case 'SaveSearchOK':
                saveSearchOkDialog.show();
                var p = YAHOO.Carsala.Picker.instances['MakeModelYear'];
                p.showPickerArea();
                break;
                
            case 'SaveSearchFailure':
                SaveSearchFailDialog.show();
                var p = YAHOO.Carsala.Picker.instances['MakeModelYear'];
                p.showPickerArea();
                break;
                
			default:
                var p = YAHOO.Carsala.Picker.instances[state];
                p.openUI();
                
                break;
		}
    }else{
    	var p = YAHOO.Carsala.Picker.instances['MakeModelYear'];
    	p.showPickerArea();
    }
    
    hideInitialDialog();
}

var configConnection;

function SetConfigState(combinedState){
	YAHOO.log('*** Setting Config state to "'+combinedState+'"');
    
    var states = combinedState.split(',');
    
    state = states[0];
    UIState = states[1];
    
    // If we aren't trying to pull the 'init' state, and if this state is different
    // from the current, pull it from the site.
    if(state != 'init' && state != YAHOO.Carsala.currentState){
    	YAHOO.log('*** Pulling state "'+state+'" from server.');
    	
    	waitSpinner.show();
    	
    	if( YAHOO.Carsala.configConnection && 
                YAHOO.util.Connect.isCallInProgress(YAHOO.Carsala.configConnection)) {
            YAHOO.log("SetConfigState: *** previous connection still in progress; aborting!");    
            YAHOO.util.Connect.abort(YAHOO.Carsala.configConnection);
        }
            
    	YAHOO.Carsala.configConnection = YUIGet('state', {id: state}, {
    		success: function(o){
    			//Show the spinner again.
    			waitSpinner.show();
    			
    			var response = false;
    			
    			//Parse the response.
    			try{
    				response = YAHOO.lang.JSON.parse(o.responseText);
    				YAHOO.log('*** Pulled state "'+state+'" from server.');
    			}catch(e){
    				// TODO: Show an error message.
    				YAHOO.log('***** JSON parsing error when retrieving Configurator state "'+state+'"');
    			}
    			
    			if(response){
    				YAHOO.log('*** Dispatching new state.');
    				
    				//Dispatch the response to all of the pickers.
    				dispatchAfterMajorPicker(null, response);
    				YAHOO.log('*** Dispatched; updating Feedback.');
    				
    				//Update the feedback area.
    				updateFeedbackArea(response);
    				YAHOO.log('*** Updated; updating state.');
    				
    				//Set the current state.
                    YAHOO.Carsala.currentState = state;
    			}
    			
    			//Hide the spinner, now that we're done.
    			waitSpinner.hide();
                SetUIState(UIState);
    		},
    		
    		failure: function(){
    			// TODO: Show an error message and lock the UI.
    			YAHOO.log('***** Connection failed while retrieving Configurator state "'+state+'"');
    			waitSpinner.hide();
    			hideInitialDialog();
    		}
    		
    	});
    }else{
    	SetUIState(UIState);
    	hideInitialDialog();
    }
}

function hideInitialDialog(){
	var dialog = document.getElementById('InitialDialog');
	
    if(dialog && dialog.style.display != 'none'){
    	dialog.style.display = 'none';
    }
}

function SaveCurrentSearch(saveActionURL, loggedIn){
	// Get the current state.
    var states = YAHOO.util.History.getCurrentState("Config").split(',');
    var stateID = states[0];
    var saveURL = saveActionURL + stateID;
    
    // If they're logged in, we'll send an AJAX request directly; otherwise, we'll direct them to log in.
	if(loggedIn){
		// Send a call to the save action.
		waitSpinner.show();
		
		YUIPost(saveURL, null, {
			success: function(o){
				waitSpinner.hide();
				
				// Prase the response.
				try{
                    response = YAHOO.lang.JSON.parse(o.responseText);
                    
                }catch(e){
                    // TODO: Show an error message.
                    YAHOO.log('***** JSON parsing error when saving configurator state!"');
                    response = {Result: false};
                }
                
                
                if(response.Result){
                	YAHOO.log('***** Saving search success.');
                	saveSearchOkDialog.show();
                }else{
                	YAHOO.log('***** Saving search failure!');
                    SaveSearchFailDialog.show();
                }
			},
			
			failure: function(o){
				waitSpinner.hide();
				
				YAHOO.log('***** Saving search failed!');
				YAHOO.log(o.responseText);
			}
		});
	}else{
		// Send the user to the login page.
		window.location = saveURL;
	}
}

function SaveNewCurrentSearch(saveActionURL, id,loggedIn){
	// Get the current state.
    //var states = YAHOO.util.History.getCurrentState("Config").split(',');
    var stateID = id;
    var saveURL = saveActionURL + stateID;
    
    // If they're logged in, we'll send an AJAX request directly; otherwise, we'll direct them to log in.
	if(loggedIn){
		// Send a call to the save action.
		waitSpinner.show();
		
		YUIPost(saveURL, null, {
			success: function(o){
				waitSpinner.hide();
				
				// Prase the response.
				try{
                    response = YAHOO.lang.JSON.parse(o.responseText);
                    
                }catch(e){
                    // TODO: Show an error message.
                    YAHOO.log('***** JSON parsing error when saving configurator state!"');
                    response = {Result: false};
                }
                
                
                if(response.Result){
                	YAHOO.log('***** Saving search success.');
                	saveSearchOkDialog.show();
                }else{
                	YAHOO.log('***** Saving search failure!');
                    SaveSearchFailDialog.show();
                }
			},
			
			failure: function(o){
				waitSpinner.hide();
				
				YAHOO.log('***** Saving search failed!');
				YAHOO.log(o.responseText);
			}
		});
	}else{
		// Send the user to the login page.
		window.location = saveURL;
	}
}






/**
 * An object for maintaining state information about the min and max
 * year drop down menus.
 *
 * @param string the min year DOM id
 * @param string the max year DOM id
 * @param int the year floor or lower bound
 * @param int the year ceiling or upper bound
 */
function yearSetObject(yearMinId, yearMaxId, yearFloor, yearCeil) {
    this.yearMinId = yearMinId;
    this.yearMaxId = yearMaxId;
    this.yearFloor = yearFloor;
    this.yearCeil = yearCeil;

    if (this.yearFloor < 2000) {
        this.yearFloor = 2000;
    }

    if (this.yearCeil > new Date().getFullYear()) {
        this.yearCeil = new Date().getFullYear();
    }
}

/**
 * Get the updated <option> values for the max year selection.
 *
 * @param yearSetObject
 * @return string the new HTML selections 
 */
function updateMaxYearSelect(yearSetObj) {
    var yearMin = document.getElementById(yearSetObj.yearMinId);
    var yearMax = document.getElementById(yearSetObj.yearMaxId);
    var dateO = new Date();
    var i = 1;

    YAHOO.log("########## updating yearMax " + yearMax.value + " ceil " + yearSetObj.yearCeil);
	
    currentYearMax = yearMax.value;
    yearMax.options.length = 0 ;
    yearMax.options[0] = new Option("Choose...", 0);
    for (year = yearMin.value; 
            year <= Math.min(parseInt(yearMin.value) + 3, yearSetObj.yearCeil); year++) {
        // try and retain the selected year if possible
        yearMax.options[i] = new Option(year, year);
        if ((parseInt(currentYearMax) != 0) && (parseInt(currentYearMax) == year)) {
            yearMax.selectedIndex = i;
        } 

        i++;
    }
}



/**
 * Update the min year selection box.
 *
 * @param DOM object element
 * @param yearSetObject
 */
function updateMinYear(e, yearSetObj) {
    YAHOO.log("updating year Min from id "+yearSetObj.yearMinId);
    var yearMin = document.getElementById(yearSetObj.yearMinId);
    var i = 1;
	
    currentYearMin = yearMin.value;
    yearMin.options.length = 0;
    yearMin.options[0] = new Option("Choose...", 0);
    for (year = yearSetObj.yearFloor; year <= yearSetObj.yearCeil; year++) {
        yearMin.options[i] = new Option(year, year);
        if ((parseInt(currentYearMin) != 0) && (parseInt(currentYearMin) == year)) {
            yearMin.selectedIndex = i;
        }

        i++;
    }
}



/**
 * Update the max year selection box.
 *
 * @param DOM object element
 * @param yearSetObject
 */
function updateMaxYear(e, yearSetObj) {
    YAHOO.log("updating year Max from id "+yearSetObj.yearMaxId+
              " f "+yearSetObj.yearFloor+" c "+yearSetObj.yearCeil);
    var yearMin = document.getElementById(yearSetObj.yearMinId);
    var yearMax = document.getElementById(yearSetObj.yearMaxId);

    if (/\d{4}/.test(yearMin.value)) {
        if (yearMax.disabled == false && /\d{4}/.test(yearMax.value)) {
            YAHOO.log("a max year was already selected " + yearMax.value);
            YAHOO.log("max - min ?:" + (parseInt(yearMax.value) - parseInt(yearMin.value)));
            updateMaxYearSelect(yearSetObj);
        } else {
            // max year has not been touched
            yearMax.disabled = false;
            updateMaxYearSelect(yearSetObj);
        }
    } else {
        yearMax.disabled = true;
    }

}
