/**
 * Contains code for different components which can be plugged  				
 * into any page, to provide generic functionality
 */
/**
 *  Provides a wrapper for AJAX functionality.
 *  
 *  Creates and sends a new AJAX request sending with it all the params passed to it.
 *  The server response is assumed to be a JSON object which is passed back to the callback
 *  
 *  @param {String}   url             - URL to send the AJAX request to.
 *  @param {Object}   params          - Parameters to pass in the AJAX.
 *  @param {Function} successCallback - The function to call when a successful response is received 
 *  									from the server.
 *  @param {Object}   options         - Additional options, eg {method:"get"}
 *                                      see http://www.prototypejs.org/api/ajax/options for all options that can be passed
 */
var eCOM_AjaxCaller = new Class.create({
	initialize: function( url, params, successCallback, options ){
		options = Object.extend({
								method:     "post",
								parameters: params || {},
								onSuccess:  this.onSuccess.bind(this, successCallback),
								onFailure:  this.onFailure.bind(this)
    							}, options || {});
		//Create the AJAX call here
		new Ajax.Request(url, options);
	},
	/**
	 *  Converts the JSON response from the server into a native object and passes this 
	 *  back to the callBack function
	 *  @param {Function} callBack - The function to call in the originator.
	 *  @param {Object}   response - The response returned from the server
	 */
	onSuccess: function( callBack, response ) {
        var json = null;
        if(response.responseText) {
            json = response.responseText.evalJSON();
        }
        if(typeof callBack == "function") {
            callBack(json, response.request);
        }
	},
	/**
	 *  Generic function to call when there was a failure comunicating with the server
	 *  @param {Object} response - The response returned from the server
	 */
	onFailure: function( response ) {
		alert("Sorry, there was a problem communicating with the server\nResponse: "+response.getStatus()+" - "+response.getStatusText());
	}
}); /* End: eCOM_AjaxCaller */

/**
 *  Provides a wrapper for Legacy AJAX functionality that doesn't use JSON as the communication format.
 *  Extends eCOM_AjaxCaller. See eCOM_AjaxCaller for details of how to call the constructor.
 *  
 *  NOTE: This object should not be used for any new functionality but should only be used for
 *        converting LEGACY code to use the standard AJAX interface.
 */
var eCOM_AjaxCaller_Legacy = new Class.create(eCOM_AjaxCaller, {
	/**
	 *  Passes the response from the server back to the callBack function without modification
	 *  @param {Function} callBack - The function to call in the originator.
	 *  @param {Object}   response - The response returned from the server
	 */
	onSuccess: function( callBack, response ) {
		if(typeof callBack == "function") {
            callBack(response);
        }
	}
}); /* End: eCOM_AjaxCaller_Legacy */

/**
 *  Handles and extends the response that is sent from the server for all Ajax requests.
 *  @param {Object} response - Response object from the server.
 *                             Note: See the documentation on the Wiki for details of this object
 */
var eCOM_AjaxResponseHandler = new Class.create({
    //Setup statics
    typeError:           "error",
    typeValidationError: "validation_error",
    typeInfo:            "info",
    initialize: function( response ) {
        //Setup defaults for the values from the server
        this.messageType = this.typeInfo;
        this.success     = false;
        this.messages    = [];
        
        //TODO: the below variable has not been implemented in the HTML or the code
        this.ajaxMessagesElement = $("ajax-messages");

        //Add all the values from the response sent to from the server to "this"
        //Note: If there is any change of the name of the variables sent from the server then those changes will
        //      need to be replicated here.
        this.setSuccess(response.success);
        this.setMessageType(response.message_type);
        this.setMessages(response.messages);
    },
    /**
     *  sets the transaction success
     *  @param {boolean} success
     */
    setSuccess: function( success ) {
        this.success = success;
    },
    /**
     *  returns boolean indicating if the request was successful
     */
    requestSuccessful: function() {
        return this.success;
    },
    /**
     *  sets the message type
     *  @param {String} type - Can be either "error", "info", "validation_error"
     */
    setMessageType: function( type ) {
        if(type && typeof type === "string") {
            this.messageType = type.toLowerCase();
        }
    },
    /**
     *  returns the message type in lowercase
     *  @return string
     */
    getMessageType: function() {
        return this.messageType.toLowerCase();
    },
    /**
     * Sets multiple messages
     * @param {Array<string>} msgs - Messages retruned from the server
     */
    setMessages: function( msgs ) {
        this.messages = msgs || [];
    },
    /**
     * Adds and individual message to the messages collection
     * @param {string} message
     */
    addMessage: function( message ) {
        if(message && typeof message === "string" && message.length > 0) {
            this.messages.push(message);
        }
    },
    /**
     *  Based on the error type returns the generic header for the alert message to the user
     */
    getMessageHeader: function() {
        var header = "";
        switch(this.getMessageType()) {
            case this.typeError:
                header = "Error";
                break;
            case this.typeValidationError:
                header = "Validation Error";
                break;
            default: //Note this case captures this.typeInfo.
                header = "Information";
                break;
        }
        return header;
    },
    /**
     *  Adds default message to the messages.
     *  To be used when there is no message sent from the server.
     */
    setDefaultFailureMessage: function() {
        var msg = "";
        switch(this.getMessageType()) {
            case this.typeError:
                msg = "The update has not been saved as the server has returned an error";
                break;
            case this.typeValidationError:
                msg = "The update has not been saved as there was a problem with your request";
                break;
            default: //This case also captures this.typeInfo plus
                //Don't set a default message as if not message from server then don't want to display anything
                msg = "The operation was not successful; No reason was given by the server";
                break;
        }
        this.addMessage(msg);
    },
    /**
     *  Returns a boolean indicating if the object has any messages to display
     */
    hasMessages: function() {
        return this.messages && this.messages.size() > 0;
    },
    /**
     *  Displays the error message(s)
     */
    displayMessages: function() {
        //If there a place on the screen to display ajax error messages then update that else
        //display errors in a popup
        if(this.ajaxMessagesElement) {
            this.ajaxMessagesElement.update(this.messagesHtmlList());
        } else {
            this.popUpError();
        }
    },
    /**
     *  Generates the HTML for displaying the messages in a list with the appropriate CSS class applied
     */
    messagesHtmlList: function() {
        var className = "";
        switch(this.messageType) {
            case this.typeInfo:
                className = "server_info";
                break;
            case this.typeError:
                className = "server_error";
                break;
            case this.typeValidationError:
                className = "server_validation_error";
                break;
        }
        if(!this.hasMessages()) {
            this.setDefaultFailureMessage();
        }
        var html = "<ul class='"+className+"'>";
        for(var i=0, len=this.messages.size(); i<len; i++) {
            html += "<li>" + this.messages[i] + "</li>";
        }
        html += "</ul>";
        return html;
    },
    /**
     *  Displays non-info messages in an alert box
     */
    alertError: function() {
        var message = "";
        //Don't show "info" type messages in the alert.
        //This is to improve the user experience so they will only be prompted if there is a problem.
        if(!this.requestSuccessful() || (this.getMessageType() && this.getMessageType() !== this.typeInfo)) {
            message = this.getMessageHeader() + ":\n";
            if(!this.hasMessages()) {
                this.setDefaultFailureMessage();
            }
            this.messages.each(function(msg) {
                    message += " - " + msg + "\n";
                });
            alert(message);
        }
    },
    /**
     *  Displays messages in a modal popup box
     */
    popUpError: function() {
        if(!this.requestSuccessful() || (this.getMessageType() && this.getMessageType() !== this.typeInfo)) {
            var message = this.messagesHtmlList();
            var options = {hideCancelButton: true, title: this.getMessageHeader()};
            new eCOM_popUpDialogBox(message, options);
        }
    }
});
/**
 *  A object that contains a group of related checkBoxes
 *  @param {Object} masterCheckbox       - Id or DOM reference to the group master checkbox
 *  @param {Object} multiGroupController - An instance of an eCOM_multipleCheckBoxGroupController object [optional].
 *                  Note: This argument is only used if this group is one of many groups on a single page
 *  @param {Array}  childrenCheckboxes   - A collection of checkboxes to be used as the childern in the group [optional]
 *                  Note: This is only needed if the children and master are not contained in the same parent element
 */
var eCOM_checkBoxGroup = Class.create({
    klass: "eCOM_checkBoxGroup",
	initialize: function( masterCheckbox, multiGroupController, childrenCheckboxes ) {
		this.controller  = multiGroupController;
		this.masterCheckbox = $(masterCheckbox) || null;
		this.masterClickHandler    = this.masterClick.bindAsEventListener(this);
		this.checkboxClickHandler  = this.checkboxClick.bindAsEventListener(this);
		
        if(this.masterCheckbox) {
			if(!childrenCheckboxes){
                var parent = this.masterCheckbox.up();
                childrenCheckboxes = parent.select("input[type=\'checkbox\']").without(this.masterCheckbox);
			}
   			this.childrenCheckboxes = childrenCheckboxes;
    		Event.observe(this.masterCheckbox, "click", this.masterClickHandler);
    		this.registerChildren();
            if(this.controller) {
                this.controller.addGroup(this);
            }
        }
	},
    /**
     *  registers click listeners on all the children checkboxes
     */
    registerChildren: function() {
        //If there is no master then don't need to register any events
        if(this.masterCheckbox) {
            var self = this;
    		this.childrenCheckboxes.each( function(checkBox) {
    				self.registerClickEvent(checkBox);
    			});
        }
    },
    /**
     *  Adds a new checkbox to the collection and registers its listeners
     *  @param {Object} checkBox - DOM reference to a checkbox
     */
    addCheckBox: function( checkBox ) {
        this.childrenCheckboxes.push(checkBox);
        this.registerClickEvent(checkBox);
    },
    /**
     *  Registers a click event on the element passed in 
     *  @param {Object} checkBox - Check box to add the click listener to
     */
    registerClickEvent: function( checkBox ) {
        Event.observe(checkBox, "click", this.checkboxClickHandler);
    },
    /**
     *  Changes the selection of all the child checkboxes to match the parent
     *  @param {Object} event - Event created by clicking the parent checkbox
     */
	masterClick: function( event ) {
		var target = Event.element(event);
		this.changeSelection(target.checked);
		if(this.controller) {
			this.controller.uncheck();
		}
	},
    /**
     *  Remove the check from the parent and any master
     *  @param {Object} event - Event created by clicking on a child checkbox
     */
	checkboxClick: function( event ) {
		this.masterCheckbox.checked = false;
		if(this.controller) {
			this.controller.uncheck();
		}
	},
    /**
     *  Change all the children checkboxes to match the value passed in
     *  @param {Boolean} checked - Indicates the state to change the checkboxes to
     *                           - true:  Checks all the children
     *                           - false: Unchecks all the children
     */
	changeSelection: function( checked ) {
		this.masterCheckbox.checked = checked; //Note: This line is redundant if function called via onclick event but needed if called directly via code
		this.childrenCheckboxes.each(function(checkBox) {
				checkBox.checked = checked;
			});
	},
    /**
     *  Note: This is a helper function that shouldn't be needed once the initialize is refactored to take the
     *        collection of checkboxes
     *  @param {Object} checkboxes
     */
    setChildren: function( checkboxes ) {
        if(checkboxes) {
            this.childrenCheckboxes = checkboxes;
            this.registerChildren();
        }
    },
    /**
     *  Returns the reference for the master checkbox
     */
	getMasterCheckbox: function() {
		return this.masterCheckbox;
	},
    /**
     *  Returns references to all the seleced check boxes
     */
    getSelected: function() {
        return this.childrenCheckboxes.findAll(function(box) {
                                return box.checked;
                            });
    },
    /**
	 *  Hides all of the expanders in the collection
	 */
    hideAllCheckboxes: function() {
        this.childrenCheckboxes.invoke("hide");
    },
    /**
	 *  Displays all of the expanders in the collection
	 */
    showAllCheckboxes: function() {
        this.childrenCheckboxes.invoke("show");
    },
    /**
     *  Returns Boolean indicating if any of the children are selected
     *  @return {Boolean} - True: at least one child selected; False: no children selected;
     */
	anySelected: function() {
        var selected = false;
        if(this.masterCheckbox.checked) {
			//If the master is checked then we know that all other options have been selected
			selected = true;
		} else {
            /*
             *  The pluck function will return an array that will contain true-false values
             *  so if there is any true values in the array the running max on it will return true
             *  as this will be the maximum value in the array.
             */
    		selected = this.childrenCheckboxes.pluck("checked").max();
        }
        return selected || false;
	}
});/* End: eCOM_checkBoxGroup */
/**
 *  Collapsible list
 *  @param {String}  cssClass        - CSS class of the trigger that expands and contracts the lists
 *  @param {Object}  options         - Object containing additional optional options which are:
 *         {Boolean} collapsedOnLoad - Boolean indicating if the list will be collapsed on first load [optional]
 *                                   - true:          collapse list; 
 *                                   - false or null: leave list expanded (default);
 *  	   {String}  childCssClass   - CSS class of child lists to collapse [optional]
 *                                   - If not specified then will only collapse the first sublist found
 *  	   {Object}  listContainer   - A DOM reference of a container to limit this expandable list [optional]
 *                                   - Use this if there is multiple expandable lists on the page 
 *                                   - default: document.body
 *  	   {String}  grandParentTag  - The name of the tag that contains the expander and list elements [optional]
 *                                   - default: "li"
 *  	   {String}  collapseTitleText - title text to display when the collapse icon is displayed [optional]
 *                                       default - "Click to collapse"
 *  	   {String}  expandTitleText   - title text to display when the expand icon is displayed [optional]
 *                                       default - "Click to expand"
 */
var eCOM_collapsibleList = Class.create({
	initialize: function( cssClass, options ) {
        options = Object.extend({
                                collapseOnLoad:   false,
                                childCssClass:    null,
                                listContainer:    Element.extend(document.body),
                                grandParentTag:   "li",
                                collapseTitleText: "Click to collapse",
                                expandTitleText:   "Click to expand"
                                }, options || {});
        
        this.childCssClass    = options.childCssClass;
        this.expanderCssClass = cssClass;
		this.expanders        = [];
        this.listeners        = [];
        
        this.listContainer     = options.listContainer;
        this.grandParentTag    = options.grandParentTag
        
        this.collapseTitleText = options.collapseTitleText;
        this.expandTitleText   = options.expandTitleText;
        
		this.expanderClickHandler = this.expanderClick.bindAsEventListener(this);
        
		if(options.collapseOnLoad) {
			//Note: This will default all the sections to be collapsed on load
			this.collapseAll();
		}
        var listItems = this.listContainer.select("."+this.expanderCssClass);
        
		var self = this;
        //Register all the click events on the expanders and add any title text
		listItems.each( function(expander) {
				self.registerExpander(expander);
			});
	},
    /**
     *  Sets up and adds a list item as a expander
     *  @param {Object} newExpander - DOM reference to the list item to add as a list expander
     */
    registerExpander: function( newExpander ) {
        this.expanders.push(newExpander);
        this.addListener(newExpander);
        this.addTitleText(newExpander);
    },
    /**
     *  Adds a click event listener onto the element
     *  @param {Object} element - DOM element to add the click event to
     */
    addListener: function( element ) {
        this.listeners.push(Event.observe(element, "click", this.expanderClickHandler));
    },
    /**
     *  Adds title text to the element
     *  @param {Object} element - DOM reference to the element to add the title text to
     */
    addTitleText: function( element ) {
        if(element.hasClassName("closed")) {
            titleText = this.expandTitleText;
        } else {
            titleText = this.collapseTitleText;
        }
        element.setAttribute("title", titleText);
    },
    /**
     *  Adds a new list item to the collection of items to expand
     *  @param {Object} liElement - DOM refernce to the li reference to add to the collapsable list
     *  @param {Object} cssClass  - The CSS class of the expander [optional] defaults to one setup on object creation
     */
    registerListItem: function( liElement, cssClass ) {
        cssClass = cssClass || this.expanderCssClass;
        var expander = liElement.select("."+cssClass);
        this.registerExpander(expander.first()); //Need to use .first() as .select() returns an Array
    },
    /**
     *  Click handler that toggles the display of the list item
     *  @param {Object} event - Click event triggered by clicking on the list expander
     */
	expanderClick: function( event ) {
		Event.stop(event);
        var matchCssClass = "."+this.expanderCssClass;
		var target = Event.element(event);
        //If a child element of the trigger was clicked then navigate back to the trigger element 
        if(!target.match(matchCssClass)) { 
            target = target.up(matchCssClass);
        }
		this.toggleChildDisplay(target);
	},
    /**
     *  Locates and returns a collection of lists that are to be shown or hidden for a single list item
     *  @param {Object} expander - List expander to find all children list for
     */
    _locateLists: function( expander ) {
        var titleText = "";
		var grandParent = expander.up(this.grandParentTag);
        var lookFor = this.childCssClass || "ul"; //If there is a Css class passed in then use that instead
        var lists = grandParent.select(lookFor);
        return lists;
    },
    /**
     * Toggles the display of the children lists
     * @param {Object} expander - List expander that was clicked on
     */
	toggleChildDisplay: function( expander ) {
        var lists = this._locateLists(expander);
        lists.each(function( list ){ //Need an each to handle if more then one is found with the CSS class
                list.toggle();
            });
		expander.toggleClassName("closed");
        this.addTitleText(expander);
	},
    /**
     *  Collapses a single list item
     *  @param {Object} expander - The list item to collapse
     */
    collapse: function( expander ) {
    	var lists = this._locateLists(expander);
        lists.each(function( list ){ //Need an each to handle if more then one is found with the CSS class
                list.hide();
            });
		expander.addClassName("closed");
        this.addTitleText(expander);
    },
    /**
     *  Expands a single list item
     *  @param {Object} expander - The list item to expand
     */
    expand: function( expander ) {
        var lists = this._locateLists(expander);
        lists.each(function( list ){ //Need an each to handle if more then one is found with the CSS class
                list.show();
            });
		expander.removeClassName("closed");
        this.addTitleText(expander);
    },
    /**
     *  Collapses all the list items
     */
	collapseAll: function() {
		var self = this;
		this.expanders.each( function(expander) {
				self.collapse(expander);
			});
	}, 
    /**
     *  Expands all the list items
     */
	expandAll: function() {
		var self = this;
		this.expanders.each( function(expander) {
				self.expand(expander);
			});
	},
	/**
	 *  Hides all of the expanders in the collection
	 */
    hideAllExpanders: function() {
        this.expanders.invoke("hide");
    },
    /**
	 *  Displays all of the expanders in the collection
	 */
    showAllExpanders: function() {
        this.expanders.invoke("show");
    },
    /**
     * Returns reference to expander in the location passed in
     * @param {Integer or String} position 
     *             - Either:
     *                 a Zero based array index for the expander
     *             or 
     *                 "last" for the last expander in the collection
     */
    getExpander: function( position ) {
        if(position || position === 0) {
            if(typeof position === "string" && position.toLowerCase() === "last") {
                position = this.expanders.length-1;
            }
            return (position < this.expanders.length) ? this.expanders[position] : null;
        }
        return null;
    },
    /**
     *  clean up memory
     */
    destroy: function() {
        this.expanders.clear();
        this.expanders = null;
        //this.listeners;  //Need to remove all the listeners
    }
}); /* End: eCOM_collapsibleList */
/**
 *  Creates a dialog window that contains the HTML that is passed in and applies any CSS styles passed in
 *  the options
 *  
 * @param {String|Object} htmlContent - The HTML that will be displayed in the dialog window
 *                                    - Can be either a String or DOM Element or anything that the "Element.insert" function can accept. See the prototype documentation for more information
 * @param {Object} options - Object that contains various formatting options for the window
 *        Allowed options:
 *          - title:             Sets the title that will be displayed in the window; default = blank ("").
 *          - top:               Pixel offset from the top of the screen to position the window; default = 50% (centred on the screen).
 *          - left:              Pixel offset from the left of the screen to position the window; default = 50% (centred on the screen).
 *          - modal:             Boolean if set to true will display the popup in modal mode; default = true.
 *          - submitBtnText:     The text that will appear on the submit button; default = "OK".
 *          - cssClass:          An extra cssClass to add to the popup box to apply non-standard formatting with; default = null.
 *          - cancelBtnText:     The text that will appear on the cancel button; default = "Cancel".
 *          - hideSubmitButton:  Boolean if set to true will hide the submit button; default = false.
 *          - hideCancelButton:  Boolean if set to true will hide the cancel button; default = false.
 *          - backgroundCloseOnClick:  Boolean if set to true will mean that if the faded background is 
 *                               clicked by the user then the windown will close; default = false.
 *          - backingObject:     Reference to a JS Class that will be instantiated to control the popup; default = null. 
 *          - backingObjectData: Any data that is to be passed to the backing object when its instantiated; default = null. 
 *          - Plus any CSS styles as a name:value pair, eg {width: "280px"}.
 */
var eCOM_popUpDialogBox = Class.create({
	initialize: function( htmlContent, options ) {
        this.centrePopup = true;
        //If a specific location is passed in then don't try to centre the popup on the page
        if(options && (options.top || options.left)) {
            this.centrePopup = false;
        }
        options = Object.extend({ title: "",
                                  top: "50%",
    	                          left: "50%",
                                  width: "200px",
                                  modal: true,
                                  submitBtnText: "OK",
                                  cancelBtnText: "Cancel",
                                  cssClass: null,
                                  hideSubmitButton: false,
                                  hideCancelButton: false,
                                  backgroundCloseOnClick: false,
                                  backingObject: null,
                                  backingObjectData: null
                            }, options || {});
        
        this.options       = options;
		this.content       = htmlContent || "";
		this.title         = this.options.title;
		this.submitBtnText = this.options.submitBtnText;
        this.width         = this.options.width;
        
        this.callBack            = this.options.callBack;
        this.globalEventListener = this.options.globalEventListener;
        
        //Setup Statics
        this.cssClass           = "eCOM_popup_dialog_box";
        this.staticId           = "eCOM-popup-dialog-box-";
        this.backgroundCssClass = "eCOM_modal_fading";
     
        this.maxNum = 10; //Note: This will be the maximum number of popups that will be able to display at one time on a page
		
        this.popUpId     = "";
        this.formId      = "";
        this.submitBtnId = "";
        this.cancelBtnId = "";
        
        //Setup DOM element references
        this.cancelBtn = null;
        this.form      = null;
        this.popUp     = null;
        this.submitBtn = null;
        
        this.backingObject = null;
        var createPopUp    = false;
        
        //Setup event handlers
        this.handleCloseBtnClick   = this.cancel.bindAsEventListener(this);
        this.handleSubmitBtnClick  = this.submit.bindAsEventListener(this);
        this.handleKeyPress        = this._keyPress.bindAsEventListener(this);
        this.handleOtherClick      = this._handleOtherClick.bindAsEventListener(this);
        this.handleBackgroundClick = this._handleBackgroundClick.bindAsEventListener(this);
        
        for(var i=1; i<this.maxNum; i++) {
            this.popUpId = this.staticId + i;
            if(!$(this.popUpId)) { //If a popup with this id doesn't already exist then use this id
                createPopUp = true;
                break;
            }
        }
        if(options.cssClass) {
            this.cssClass += " " + options.cssClass;
        }
        if(createPopUp) {
            this.formId      = this.popUpId + "_form";
            this.submitBtnId = this.popUpId + "_submit";
            this.cancelBtnId = this.popUpId + "_cancel";
			this.create();
            if(this.centrePopup) {
                this.centreOnScreen();
            }
            this.displayPopUp();
		} else { //Note: This is just a safety to make sure 2 popups are not created with the same id
            alert("Sorry, unable to open anymore dialog boxes as the maximum number allowed on screen has been exceeded. Please close some dialog boxes and try again");
        }
        //Only create the backing object once everything has been setup
        if(typeof options.backingObject == "function") {
            this.backingObject = new options.backingObject(this, options.backingObjectData);
        }
	},
    /**
     *  Generates all the HTML for the popup and adds it to the page
     */
    create: function() {
        var htmlText = "";
        if( this.options.modal) {
            htmlText += this.getModalBackgroundHtml();
        }
        htmlText += "\
            <div id='"+this.popUpId+"' class='"+this.cssClass+"'>\
	            <form id='"+this.formId+"' onsubmit='return false'>\
    	            <h2>" + this.title + "</h2>\
    	            <div class='mainContents'>" + this.content + "</div>\
    	            <div class='buttonsContainer'>";
        if (!this.options.hideCancelButton) {
            htmlText += "<button id='" + this.cancelBtnId + "' class='cancel'>" + this.options.cancelBtnText + "</button>";
        }
        if (!this.options.hideSubmitButton) {
            htmlText += "<button id='" + this.submitBtnId + "' class='submit'>" + this.submitBtnText + "</button>";
        }
        htmlText += "\
                    </div>\
	            </form>\
            </div>";
        
        $(document.body).insert({ top: htmlText });
        
        this.popUp      = $(this.popUpId);
        this.form       = $(this.formId);
        this.submitBtn  = $(this.submitBtnId);
        this.cancelBtn  = $(this.cancelBtnId);
        this.background = $$("." + this.backgroundCssClass).first(); //Assume will be the first one found
        
        this.popUp.setStyle(this.options);
        
        this.setUpEvents();
    },
    /**
     *  Returns the HTML for the fading behind a modal window
     */
    getModalBackgroundHtml: function() {
        return "<div class='" + this.backgroundCssClass + "'></div>";
    },
    /**
     *  Sets up all the listeners for the popup
     */
    setUpEvents: function() {
        if(this.submitBtn) {
            this.submitBtn.observe("click", this.handleSubmitBtnClick);
        }
        if(this.cancelBtn) {
            this.cancelBtn.observe("click", this.handleCloseBtnClick);
        }
        this.popUp.observe("click", this.handleOtherClick);
        this.popUp.observe("keypress", this.handleKeyPress);
        this.background.observe("click", this.handleBackgroundClick);
    },
    /**
     *  removes all the listeners for the popup
     */
    removeEvents: function() {
        if(this.submitBtn) {
            this.submitBtn.stopObserving("click", this.handleSubmitBtnClick);
        }
        if(this.cancelBtn) {
            this.cancelBtn.stopObserving("click", this.handleCloseBtnClick);
        }
        this.popUp.stopObserving("click", this.handleOtherClick);
        this.popUp.stopObserving("keydown", this.handleKeyPress);
    },
    /**
     *  Retrieves the form element
     */
    getForm: function() {
        return this.form;
    },
    /**
     *  Stops clicks on any part of the popup other then the buttons from bubbling up from the popup
     *  @param {Object} event - Event object from a click on the popup
     */
    _handleOtherClick: function( event ) {
        Event.stop(event);
    },
    /**
     *  Captures all clicks made to the background
     *  @param {Object} event - Event object from a click on the faded background
     */
    _handleBackgroundClick: function( event ) {
        Event.stop(event);
        if(this.options.backgroundCloseOnClick) {
            this.close();
        }
    },
    /**
     *  Captures all keydown events looking for the Return and Esc keys to submit or cancel the action
     *  respectively
     *  @param {Object} event - Browser key press event
     */
    _keyPress: function( event ) {
        var key = event.keyCode;
        switch (key) {
            case Event.KEY_RETURN:
                this.submit(event);
                break;
            case Event.KEY_ESC:
                this.cancel(event);
                break;
        }
    },
    /**
     *  Handles the submit event
     *  @param {Object} event - Event that caused the submit
     */
    submit: function( event ) {
        if(event) {
            Event.stop(event);
        }
        this.close(true); //pass flag to run callback
    },
    /**
     *  Handles the cancel event
     *  @param {Object} event - Event that caused the cancel
     */
    cancel: function( event ) {
        if(event) {
            Event.stop(event);
        }
        this.close(false); //pass flag to not run callback
    },
    /**
     *  Closes the window
     *  @param {Boolean} doCallBack - Flag indicating if should run the callback
     *                              - true: runs callback
     *                              - false: doesn't run the callback
     */
    close: function( doCallBack ) {
        this.destroy();
        if(doCallBack) { //Only do the callBack on submit not on cancel
            if (typeof this.callBack == "function") {
                this.callBack(this.form.getElements());
            }
        }
    },
    /**
     *  Centres the popup on the screen
     */
    centreOnScreen: function() {
        var width  = this.popUp.getWidth();
        var height = this.popUp.getHeight();
        var verticalOffset   = "-" + parseInt(width / 2)  + "px";
        var horizontalOffset = "-" + parseInt(height / 2) + "px";
        
        var newStyle = {
            marginLeft: verticalOffset,
            marginTop:  horizontalOffset
            };
        this.popUp.setStyle(newStyle);
    },
    /**
     *  Displays the popup
     */
    displayPopUp: function() {
        this.popUp.setStyle({display: "block"});
        try { //Put a try around this call as there may not be any form elements in the popUp
            this.form.focusFirstElement();
        } catch(e) {}
    },
    /**
     *  Stops up all the eventlisteners, removes the HTML from the document and removes all references
     *  to DOM elements in order to stop memory leaks
     */
    destroy: function() {
        //Clean up to stop memory leaks
        //Remove eventlisteners
        this.removeEvents();
        
        if(this.options.modal) {
            this.popUp.previous(".eCOM_modal_fading").remove();
        }
        //Remove the elements from the DOM
        if(this.submitBtn) {
            this.submitBtn.remove();
        }
        if(this.cancelBtn) {
            this.cancelBtn.remove();
        }
        this.popUp.remove();
        
        //Remove any references to these elements
        this.submitBtn = null;
        this.cancelBtn = null;
        this.popUp = null;
    }
}); /* End: eCOM_popUpDialogBox */


