/* Copyright Carsala, Inc 2009
 * This Picker provides a generic interface for handling picker interactions 
 * with the rev 2 version of the consumer site.
 *
 *
 * @namespace Carsala
 * @module Picker
 */




// This empty function call is used to prevent global variables from eeking out
(function () { 

    // #### private functions here ####
    // we might want to move submitToServer here and possibly some others
    

    /* The constructor if you will. The YAHOO.Carsala object is created in 
       carsala.js. This object encapsulates most of the generic interactions
       with the pickers. Here is an example "new" invocation which is how you
       will want to create new pickers:

            var picker = new YAHOO.Carsala.Picker({
                         buttonId : "button",                   // the outer button div
                         buttonSummaryId : "buttonSummary",     // button summary
                         dialogId : "dialog",                   // the outer dialog div 
                         dialogSelectionId : "dialogSelection", // the inner selection div
                         dialogOkId : "dialogOk",               // ok button
                         dialogCancelId : "dialogCancel",       // cancel button
                         dialogErrorId : "dialogError",         // global error div

                         submitToUrl : "/some/controller",      // send GET request to

                         // You will need to provide this method to get the parameters
                         // that will be passed to the server. You don't have to worry
                         // about building the param string. That will be done for you.
                         callerGetParams : function () {
                            var param_array = {};
                            param_array["location"] = document.getElementById("someDialogSelect_Id").value;
                            return { somevalue : 0, json : YAHOO.lang.JSON.stringify(param_array) };
                         },

                         // Create this if you need to do some special post-processing
                         // on the response from the server. Most of the "default" actions
                         // should be handled for you already. See below.
                         callerSubmitSuccessCallback: function (that, response) {
                            // reference "this" object as "that" and the response 
                            // from the server 

                            // The below is already done for you if the Result
                            // value is true. Use this method to manipulate the
                            // DOM or reinitialize any components.
                            // that.getDialogSelection().innerHTML = response["Pickers"][that.name]["DialogHTML"]
                         },

                         // You can implemnet this if you need to. Takes same params as
                         // The success callback.
                         callerSubmitFailureCallback: null, 

                         // "Location" is how you can reference this picker 
                         // globally via YAHOO.Carsala.Picker.instances["Location"]
                         }, "Location"); 

            picker.setUp(); // you want to call this right after creation
    */
    YAHOO.Carsala.Picker = function (params, name) {
    
        // #### private variables here ####


        // copy over params
        for (var prop in params) {
            this[prop] = params[prop];
        }    


        // register the required DOM elements
        if (!this.pickerAreaId) {
            throw new Error("the pickerAreaId is undefined");
        } else {
            this.pickerArea = document.getElementById(this.pickerAreaId);
        }


        if (!this.buttonId) {
            throw new Error("the buttonId is undefined");
        } else {
            this.button = document.getElementById(this.buttonId);
        }

        if (!this.buttonSummaryId) {
            throw new Error("the buttonSummaryId is undefined");
        } else {
            this.buttonSummary = document.getElementById(this.buttonSummaryId);

            // capture for later replacement if necessary
            this.saveButtonSummary();
        }


        if (!this.dialogId) {
            throw new Error("the dialogId is undefined");
        } else {
            this.dialog = document.getElementById(this.dialogId);
        }

        if (!this.dialogSelectionId) {
            throw new Error("the dialogSelectionId is undefined");
        } else {
            this.dialogSelection = document.getElementById(this.dialogSelectionId);

            // capture for later replacement if necessary
            this.saveDialogSelection();
        }

        if (!this.dialogOkId) {
            throw new Error("the dialogOkId is undefined");
        } else {
            this.dialogOk = document.getElementById(this.dialogOkId);
        }

        if (!this.dialogCancelId) {
            throw new Error("the dialogCancelId is undefined");
        } else {
            this.dialogCancel = document.getElementById(this.dialogCancelId);
        }


        if (!this.dialogErrorId) {
            throw new Error("the dialogErrorId is undefined");
        } else {
            this.dialogError = document.getElementById(this.dialogErrorId);
        }
    


        // fill in our object in the global map
        if (name) {
            this.name = name;
            YAHOO.Carsala.Picker.instances[name] = this; 
        }


        return this;
 

    };

    // store instances globally for global retrieval
    YAHOO.Carsala.Picker.instances = {};


    // The prototype for this class
    YAHOO.Carsala.Picker.prototype = {
            name : null,                  // the name e.g. "Location"
            
            active: false,                // whether this picker can be opened or not

            getGooglePageTracker: null,      // Google page tracker object
            getClickyPageTracker: null,      // Clicky page tracker object
            
            pickerArea : null,            // the outer object containing the pickers and feedback
            pickerAreaId : null,          // the string id for the picker area

            button : null,                // the outer button DOM object
            buttonSummary : null,         // the button summary DOM object
            buttonId : null,              // string id of the outer button
            buttonSummaryId : null,       // string id of the button summary
            buttonSummaryHTML : null,     // local copy of button summary html

            dialog : null,                // outer dialog DOM object
            dialogSelection : null,       // dialog selection DOM object
            dialogId : null,              // string id of outer dialog
            dialogSelectionId : null,     // string id of dialog selection
            dialogSelectionHTML : null,   // local copy of dialog selection html

            dialogOk : null,              // ok button DOM object
            dialogCancel : null,          // cancel button DOM object
            dialogOkId : null,            // ok button string id
            dialogCancelId : null,        // cancel button string id

            dialogError : null,           // error DOM object
            dialogErrorId : null,         // error string id

            // capture the server JSON response; other pickers may need to process
            serverJSONResponse : null, 
    
            submitToUrl : '',             // the url we will submit to
            currentAsyncRequest : null,   // the request object

            // the user is ok to continue making state changes
            userOkToContinue : false,    
            
            currentStatus: 'hidden', 	  // whether the picker dialog is visible or hidden 

            /* ############################################################# */
            /* These should all be pretty clear. */

            getPickerArea : function () { return this.pickerArea; },

            getButton : function () { return this.button; },
            getButtonSummary : function () { return this.buttonSummary; },

            getDialog : function () { return this.dialog; },
            getDialogSelection : function () { return this.dialogSelection; },

            getDialogOk : function () { return this.dialogOk; },
            getDialogCancel : function () { return this.dialogCancel; },

            getDialogError : function () { return this.dialogError; },
            clearDialogError : function () { this.dialogError.innerHTML = ""; },

            saveButtonSummary : function () {
                this.buttonSummaryHTML = this.buttonSummary.innerHTML;
            },

            restoreButtonSummary : function () {
                this.buttonSummary.innerHTML = this.buttonSummaryHTML;
            },

            saveDialogSelection : function () {
                this.dialogSelectionHTML = this.dialogSelection.innerHTML;
            },

            restoreDialogSelection : function () {
                this.dialogSelection.innerHTML = this.dialogSelectionHTML;
            },

            spinner : null,

            launchSpinner : function () { 
                this.spinner.show();
            },

            closeSpinner : function () {
                this.spinner.hide();
            },

            openUI : function () {
            	YAHOO.log('***** '+this.name+'::openUI()');
            	YAHOO.Carsala.currentPicker = this.name;
            	
            	this.hidePickerArea();
            	this.showDialog();
            },
            
            closeUI : function () {
            	YAHOO.log('***** '+this.name+'::closeUI()');
            	
            	if(YAHOO.Carsala.currentPicker == this.name) {
            		YAHOO.Carsala.currentPicker = null;
            	}
            	
            	this.hideDialog();
                this.showPickerArea();
                this.closeSpinner();
            },
            
            
            showDialog : function () {
                YAHOO.log("YCP "+this.name+": showing dialog...");
                YAHOO.util.Dom.removeClass(this.dialog, 'hidden');
                
                // call the afterShowDialog function to do custom Dialog setup per picker.
                if (typeof this.afterShowDialog === 'function') {
                    try {
                        this.afterShowDialog();
                    } catch (E) {
                        YAHOO.log("showDialog: the afterShowDialog callback did not behave well: " + E);
                    }
                }
            	this.currentStatus = 'visible';
            },

            hideDialog: function () {
                YAHOO.log("YCP "+this.name+": hiding dialog...");
                YAHOO.util.Dom.addClass(this.dialog, 'hidden');
                
                // call the afterHideDialog function to do custom Dialog teardown per picker.
                if (typeof this.afterHideDialog === 'function') {
                    try {
                        this.afterHideDialog();
                    } catch (E) {
                        YAHOO.log("showDialog: the afterHideDialog callback did not behave well: " + E);
                    }
                }
            	this.currentStatus = 'hidden';
            },


            showPickerArea : function () {
                YAHOO.log("YCP "+this.name+": showing pickerArea...");
                this.pickerArea.style.display = "block";
            },

            hidePickerArea : function () {
                YAHOO.log("YCP "+this.name+": hiding pickerArea...");
                this.pickerArea.style.display = "none";
            },
            
            setProblematic : function (isAProblem) {
            	YAHOO.log("*** setProblematic:" + isAProblem);
            	YAHOO.log(this.button);
            	YAHOO.log("*** setProblematic end")
            	if(isAProblem){
            		YAHOO.util.Dom.addClass(this.buttonSummary, 'problematic');
            	}else{
            		YAHOO.util.Dom.removeClass(this.buttonSummary, 'problematic');
            	}
            },
            
            ////////////////////////////////////////////////////////
            showButton : function () {
                YAHOO.log("YCP "+this.name+": showing button...");
                this.button.style.display = "block";
            },

            hideButton : function () {
                YAHOO.log("YCP "+this.name+": hiding button...");
                this.button.style.display = "none";
            },
            ////////////////////////////////////////////////////////


            // Fired when you press the picker button
            pressButton : function (e) {
            	YAHOO.log("pressButton for "+this.button+", status:"+this.currentStatus);
            	if(!e){
            		e = window.event;
            	}
            	if(this.currentStatus == 'visible'){
            		YAHOO.util.History.navigate('Config', YAHOO.Carsala.currentState+',index');
            		this.restoreDialogSelection();
            		return false;
            	}
            	
            	// save the dialog selection area so we can replace it if they cancel
                this.saveDialogSelection();
                
            	// clear out any errors
                this.clearDialogError();
                
                YAHOO.util.History.navigate('Config', YAHOO.Carsala.currentState+','+this.name);
                
                // track this picker via the button id
                if (this.getGooglePageTracker != null && this.getGooglePageTracker() != null) {
                    var gpt = this.getGooglePageTracker();
                    gpt._trackPageview(this.buttonId);
                }
                if (this.getClickyPageTracker != null && this.getClickyPageTracker() != null) {
                    var co = this.getClickyPageTracker();
                    co.log('#picker/'+this.name, this.name+' Picker');
                }
                
                return false;
            },
            

            // Fired when you press the cancel button in the dialog
            pressCancel : function () {
                YAHOO.util.History.navigate('Config', YAHOO.Carsala.currentState+',index');
                this.restoreDialogSelection();
            },
            

            beforePressOk : null, // do validation here

            // Fired when you press the ok button in the dialog
            pressOk : function () {
                if (typeof this.beforePressOk === 'function') {
                    // do validation here if you need to
                    // validation function should return false if not
                    // validated and true if it is
                    if (!this.beforePressOk()) {
                        return;
                    }
                }

                // do ok stuff
                this.launchSpinner();

                // TODO: wrap in try..catch? Is it necessary?
                this.submitToServer();
            },
            
            /* ############################################################# */
            setupButton : function () {
            	YAHOO.log("setupButton for "+this.name);
                //this.button.onclick = this.pressButton.bind(this);
                YAHOO.util.Event.addListener(this.button, "click", this.pressButton, this, true);
                YAHOO.util.Dom.addClass(this.button, 'active');
            },

            disableButton : function () {
                YAHOO.util.Event.removeListener(this.button, "click", this.pressButton); 
            },

            setupDialog : function () {
                //this.dialogCancel.onclick = this.pressCancel.bind(this);
                YAHOO.util.Event.addListener(this.dialogCancel, "click", this.pressCancel, this, true); 
                //this.dialogOk.onclick = this.pressOk.bind(this);
                YAHOO.util.Event.addListener(this.dialogOk, "click", this.pressOk, this, true); 
            },

            disableDialog : function () {
                YAHOO.util.Event.removeListener(this.dialogCancel, "click", this.pressCancel);
                YAHOO.util.Event.removeListener(this.dialogOk, "click", this.pressOk);
            },

            setUp : function () {
                /* Fill in the default behaviours here like the spinner and whatever
                 * else we need. Must be done externally.
                 */
            	YAHOO.log("setup for "+this.name);
                if(this.active){
                	this.setupButton();
                }else if(YAHOO.util.Dom.hasClass(this.button, 'active')){
                	this.active = true;
                	this.setupButton();
                }
                
                if(this.used) {
                	YAHOO.util.Dom.addClass(this.button, 'used');
                }
                
                this.setupDialog();
            }, 

            
            /* ############################################################# */

            // This is a general function that covers most of the pickers, but should be overridden in some cases.
            callerGetParams : function(){
            	var selections = [];
            	
            	var selectionArea = this.getDialogSelection();
            	var options = selectionArea.getElementsByTagName('INPUT');
            	
            	var item;
            	
            	for(var i=0; i<options.length; i++)
			    {
			    	item =options[i];
			        if((item.type == 'checkbox' || item.type == 'radio') && item.checked) {
			            selections.push(item.value);
			            YAHOO.log('***** '+item.value);
			        }
			    }
			    
			    options = selectionArea.getElementsByTagName('SELECT');
            	for(var i=0; i<options.length; i++)
                {
                	item = options[i];
                    selections.push(item.options[item.selectedIndex].value);
                    YAHOO.log('***** '+item.options[item.selectedIndex].value);
                }
            	
                return { 'selections' : YAHOO.lang.JSON.stringify( selections ) };
            },
            
            callerSubmitSuccessCallback : null, /* function(this, o) {} */
            callerSubmitFailureCallback : null, /* function(this, o) {} */
            
            callerUpdateHTML: function(response) {
            	//Update the HTML, if it's set.
            	if(response["Pickers"] !== undefined && response["Pickers"][this.name] !== undefined){
            		
            		if(response['Pickers'][this.name]['DialogHTML'])
                        this.getDialogSelection().innerHTML = response["Pickers"][this.name]["DialogHTML"];
                    
                    if(response['Pickers'][this.name]['SummaryHTML'])
                        this.getButtonSummary().innerHTML = response["Pickers"][this.name]["SummaryHTML"];
                    
                    //Make it active, if needed.
                    if(response["Pickers"][this.name]["Active"]) {
                    	if(!this.active){
                    		this.active = true;
                    		this.setupButton();
                    	}
                    }
                    
            	}
            },
            
            // TODO: Maybe this can be a private method if we discover it never
            // needs to be overwritten
            submitSuccessCallback : function (o) {
            	// Close the spinner regardless of what happens.
            	this.closeSpinner();
            	
                // get and store the response
                YAHOO.log("* submitSuccessCallback: processing...");
                try {
                    this.serverJSONResponse = YAHOO.lang.JSON.parse(o.responseText);
                } catch (E) {
                    YAHOO.log("submitSuccessCallback: error parsing the JSON response: " + E + 
                              " JSON: " + o.responseText);
                    this.getDialogError().innerHTML = "Request error: Error processing response from server.";

                    YAHOO.util.History.navigate('Config', YAHOO.Carsala.currentState+','+'index');
                    return;
                }
                
                var response = this.serverJSONResponse;
                
                YAHOO.Carsala.currentState = response['StateID']; 
                
                // TODO: error checking on this JSON object?
                if (response["Result"] === true) {
                    YAHOO.log("submitSuccessCallback: Success, updating dialogSelection: " + o.responseText);
                    
                    this.callerUpdateHTML(response);
                    YAHOO.util.Dom.addClass(this.button, 'used');
                    
                    updateFeedbackArea(response);
                } else {
                    YAHOO.log("submitSuccessCallback: Error, the \"Result\" value was false or missing: " +
                            o.responseText);
                    // the request failed due to application error
                    var shouldContinue = true;
                    document.getElementById(this.dialogErrorId).innerHTML = response["ErrorMessage"];
                    
                    // call the caller failure CB
                    if (typeof this.callerSubmitFailureCallback === 'function') {
                        try {
                            shouldContinue = this.callerSubmitFailureCallback(this, response);
                        } catch (E) {
                            YAHOO.log("submitSuccessCallback: the failure callback did not behave well: " + E);
                        }
                    }
                    
                    // if the callback says not to continue, hide the spinner but keep it showing.
                    if(!shouldContinue){
                    	//Save the history as having been here again.
                    	YAHOO.util.History.navigate('Config', response['StateID']+','+this.name);
                        return;
                    }
                }

                // call the callers CB
                var successCallbackResult = true;
                
                if (typeof this.callerSubmitSuccessCallback === 'function') {
                    try {
                        successCallbackResult = this.callerSubmitSuccessCallback(this, response);
                    } catch (E) {
                        YAHOO.log("submitSuccessCallback: the success callback did not behave well: " + E);
                    }
                }
    
                //If the successCallback doesn't return false, we'll continue on.
                if(successCallbackResult == true) {
                	//Save the history as having gone to the index.
                    YAHOO.util.History.navigate('Config', response['StateID']+',index');
                      
                    // Navigating to 'index' will hide the dialog and show the picker area.  
                }else if(successCallbackResult !== false){
                	//Save the history as having gone somewhere.
                    YAHOO.util.History.navigate('Config', response['StateID']+','+successCallbackResult);
                }
                
                var car = document.getElementById('carfiguratorCar');
                if(car != undefined){
                	document.getElementById('carStep5').src = car.src;
                }
            },


            // TODO: Same as above. Maybe it can be a private method.
            submitFailureCallback : function (o) {
                YAHOO.log("* submitFailureCallback: processing...");
                // keep the response
                // TODO: This should be more user friendly!
                this.getDialogError().innerHTML = "Request error: " + o.statusText;

                // call the caller failure CB
                // TODO: wrap this in a try...catch
                if (typeof this.callerSubmitFailureCallback === 'function') {
                    try {
                        this.callerSubmitFailureCallback(this, o.statusText);
                    } catch (E) {
                        YAHOO.log("submitFailureCallback: the failure callback did not behave well: " + E);
                    }
                }
                
                // TODO: we will need to customize this after we decide
                // on how the error dialog will work
                this.closeUI();
            },

            // The function we use for the async GET request. Defaults to our 
            // standard YUIGet function.
            asyncGet : YUIPostJSON,


            // TODO: Can this method be private? I don't think it will need to
            // be changed.
            /* This method wraps the submission to the server. Most of the work
               is handled by the submitSuccessCallback or the submitFailureCallback.
               See above for their definitions.

               Note that the params are converted to a URL param string for you. You
               don't need to convert them in the callerGetParams. 
 
               See YUIGet for how the async request is done. It is defined in the 
               carsala.js file.
             */
            submitToServer : function () {
                // get the params to send
                params = {}
                if (typeof this.callerGetParams === 'function') {
                    params = this.callerGetParams();
                }
                // start the spinner
                this.launchSpinner();

                // submit the request
                YAHOO.log("submitToServer: sending request to " + this.submitToUrl);
                this.currentAsyncRequest = 
                    this.asyncGet(this.submitToUrl, 
                                  params, 
                                  { success: this.submitSuccessCallback.bind(this), 
                                    failure: this.submitFailureCallback.bind(this) });
                // return immediately
                
            }


    }


})();

