// Behaviour: SNPC object that  contains private objetcts that handle site functionality
//                     Revaling module pattern used to  provide public API , which is only the ErrorHelper, as 
//                     it can be used by other site scripts to provide a consistent  site wide error reporting mechanism.
// Author: Karl Oakes
// Version: 1.0
var SNPC = function ($) {
    $(document).ready(function () {
        Login.init();
		Common.init();
		NavMenu.init();
		Overlay.init();
     });
	 // private login object 
	 var Login = {
	 // private methods and properties
		loginDivID: '#login',
        loginID: '#frm_login',
		loginNameID: '#login_name',
		rememberMeID: '#rememberme',
		logoutID: '#logout',
		welcomeDivID: '#welcome',
		errorDivClass : '.errorInfo',
		errorClass: '.error',
		loginURL: '/utils/login.php',
		theEmail: { 'theID': '#theemail', 'defValue': 'Email'},
		thePass: { 'theID': '#thepass', 'defValue': 'Password'},
		currentFormID: '',
		waitClass : '.wait', 
		hiddenClass: 'hidden',
	     init: function () {
            try {
				var that = this;
				// set  emai field to default value
				$(this.theEmail.theID).val( function (index, value) { return that.setValue(value, that.theEmail.defValue); }  );
				// clear default text on focus
				$(this.theEmail.theID).focus(function () {
					var $this = $(this);
					if ($this.val() == that.theEmail.defValue) { $this.val('');}
				});
				// image cycle setup
				$(this.imageSliderID).cycle({pause:1, height: 'auto', speed: 3000});
				// validate login form
				$(this.loginID).validate({ 
						rules : { 
							theemail: {
								required: true,
								email: true
							},
							thepass: {
								required: true,
								minlength: 6
							}
						},
						messages: {
							theemail :{ required: "Please enter a valid email address"},
							thepass : { required: "Please enter a password", minlength: jQuery.validator.format("Please enter at least {0} characters")}
						},	
						submitHandler : function (form) {
							try {
								//perform ajax call to check details
								// need form reference for later use in callbacks
								that.currentFormID = '#'+form.id;
								// clear error information
								$(that.errorDivClass+ " p", that.currentFormID).empty();
								// toggle busy
								that.toggleBusy(that);
								$.ajax({
									type: "POST",
									url: that.loginURL,
									context: that, // pass context of that (Login), used in callback
									dataType: "text",
									data: $(form).serialize(),
									success: that.onAjaxSuccess,
									error: that.onAjaxError // specific error handler
								});
								return false;
							}catch(ex) {
								ex.croakedInMethod = ' - in the submitHandler method of the validate plugin in the Login object in common$.js ';
								ErrorHelper.onError(ex); 
								return false;
							}
							
						}
					});
			} catch (ex) {
				ex.croakedInMethod = ' - in the init method of the Login object in common$.js ';
				ErrorHelper.onError(ex); 
            }
		},	
		// Behaviour: Helper to set default value  
		setValue : function(theVal, defVal){
				 return !theVal ? defVal : theVal;
		},
		// Behaviour: Login AJAX error handler
		 onAjaxError: function (xhrObj, status, errObj) {
            try {
				if (xhrObj.readyState == 0 || xhrObj.status == 0) { return; } // it's not really an error, user has navigated from the page before the request has completed
				// inform user
				$(this.errorDivClass+ " p", this.currentFormID).text("Sorry, an error has occurred, please retry.");
				// reset form depending on error state
				this.resetForm(true);
				this.currentFormID = ''; // reset current form ID  
				ErrorHelper.onError(new Error("Source: Login.onAjaxError method has been called when collecting " + this.loginURL +  " XHR response : " + xhrObj.responseText + "   in common$.js,  Status:" + status + " JS Error: " + errObj ));
			}catch (ex) {
				// reset form depending on error state
				this.resetForm(true);
				// inform user
				$(this.errorDivClass+ " p", this.currentFormID).text("Sorry, an error has occurred, please retry.");
				ex.croakedInMethod = ' - in the onAjaxError method of the Login object in common$.js ';
				ErrorHelper.onError(ex); 
            }
		},
        // // Behaviour: On a successful AJAX request, display validation error information 
        // //            or OK response to user
        // // Note:  The callbacks are returning functions, which are necessary 
        // //        	to capture the this/that context objects via closure as they are
        // //        	needed, as they hold DOM / jQuery references
        // // Data format: JSON { result : string containing boolean value , description  : string containing message descriptiion } 

        onAjaxSuccess: function (data) {
            try {
                var obj = $.parseJSON(data);
				var errFound = false;
                if (obj) {
					//check for login error
                     if ("result" in obj) {
						if ( ! obj.result) {
							$(this.errorDivClass+ " p", this.currentFormID).text(obj.description);
							errFound = true;
						}
						else {
                    // no error, display passed name in login name li 
							if ("description" in obj) { $(this.loginNameID).text("Hello, " + obj.description); }
						}
					 // reset form depending on error state
						this.resetForm(errFound);
					} 
				}
            }
            catch (ex) {
                $(this.errorDivClass+ " p", this.currentFormID).text("Sorry, an error has occurred, please retry.");
				// reset form depending on error state
				this.resetForm(true);
				// need to check  if the exception is an object or a string as parseJSON only sends back a string 
				var err = (typeof(ex) ==='string') ? new Error(ex) : ex ;
				err.croakedInMethod = ' - in the onAjaxSuccess method of the Login object in common$.js';
                ErrorHelper.onError(err);
            }
		},
		// // Behaviour: On AJAX success, reset form
		resetForm : function (errFound) {
			var $thisFrm = $(this.currentFormID);
			// toggle wait and remember me
			this.toggleBusy(this);
			this.currentFormID = ''; // reset current form ID 
			if (!errFound) {
				// no errors...
				// clear form fields
				$(this.theEmail.theID).val('');
				$(this.thePass.theID).val('');
				// display logout
				this.displayPanelDiv("login");
			}		
		},
		// Behaviour: switch panels, based on state i.e. login, not setup for logout as it is done server side	
		displayPanelDiv : function (state) {
			if (state == "login") {
				$(this.loginDivID).slideUp('slow');
				$(this.welcomeDivID).fadeIn('slow');
			}
		},
		// Behaviour: switch wait and remember me 	
		toggleBusy : function(that) {
			$(that.rememberMeID).toggleClass(that.hiddenClass);
			$(that.waitClass, that.currentFormID).toggleClass(that.hiddenClass);
		}
	 };
    //private common object
    var Common = {
    	noJSClass: '.noJS',
		imageSliderID : '#slides',
        init: function () {
			try {
				// remove any elements that would be displayed if js was disabled
				$(this.noJSClass).remove();
				// image cycle setup
				$(this.imageSliderID).cycle({pause:1, height: 'auto', speed: 4000});
				// add target _blank to anchors that are required to be opened in a new window 
				// without invalidating your XHTML
				$('a[rel="external"]').attr('target','_blank');
			} catch (ex) {
				ex.croakedInMethod = ' - in the init method of the Common object in common$.js ';
				ErrorHelper.onError(ex); 
            }
		}
	};
	//Private overlay forms object 
	// Handles Request for Callback and Order overlay form interaction
	// This is accomplished by adding event handlers to the order and callback classes 
	// and the title is modified based on element's class, classes are used as we may have
	// more than one callback / order on the page at once
	// Note: Register  overlay form  uses this functionality,  but the initial setup and display is handled within registeroverlay.js
	//            which is inserted server side. 
	var Overlay = {
		callBackDialogClass :   'a.callback',
		orderDialogClass :   'a.order',
		registerRequestDialogClass: 'a.register_request',
		registerRequestClass: 'register_request',
		overlayCloseID: '#overlay_close',	
		overlayDialogID : '#overlay_dialog',	
		overlayFrmID : '#frm_Overlay',
		overlaySubmitID: '#submit_overlay',
		registerRequestID: '#request',
		pageRequestID: '#page_request',
		$dialog : {},
		registerClass: 'register',
		order_callbackClass: 'order_callback',
		errorClass: 'error',
		errorLabels: 'label.error',
		emailURL : '/utils/contact_email.php',
		subjectID: 'subject',
		// default value array
		defValues: ['Name' , 'Pub', 'BDMs Name (if applicable)', 'Telephone', 'Email'],
		// frmInputs id's and default values
		frmInputs : {
			'ovr_name' : 'Name',
			'ovr_pub' : 'Pub',
			'ovr_bdm_name' : 'BDMs Name (if applicable)',
			'ovr_tel' : 'Telephone',
			'ovr_email' : 'Email'
		},
		
		init : function (){
			try {
				var that = this;
				//populate input data with default values, before modification
				$("input:text", this.overlayFrmID).each(function(){
					var $this = $(this);
					$this.data("defValue" , that.frmInputs[this.id]);
				});
				// clear input fields on focus
				$("input:text", this.overlayFrmID).live('focus', function () {
						var $this = $(this);
						if ($.inArray($this.val(), that.defValues) !== -1 ) { $this.val('');}
				});
				// setup overlay dialog, and set autoopen = false, just open and close as required 
				this.$dialog = $(this.overlayDialogID).dialog(	{ 	modal : true,
												height: 420,
												width: 600,
												position: "top",
												autoOpen: false
				});		
				// attach some titles to the order, callback and register request classes, which is used to populate the title
				// of the overlay form when required
				$(this.callBackDialogClass).data( 'title', 'REQUEST A CALLBACK');
				$(this.orderDialogClass).data( 'title', 'TO ORDER');
				$(this.registerRequestDialogClass).data( 'title', 'REGISTER');
				// click event handlers
				$(this.callBackDialogClass +"," + this.orderDialogClass + "," + this.registerRequestDialogClass).click(function() {
					try{
						if ($(this).hasClass(that.registerRequestClass)) {
							// register request ...
							//	remove order_callback class, display register class
							that.switchDialog(that.$dialog, that.order_callbackClass, that.registerClass);
							// display correct register request intro
							$(that.pageRequestID).hide();
							$(that.registerRequestID).show();
						}else{	
							// order / callback request
							// make sure the  order_callback class is displayed
							// remove register class
							that.switchDialog(that.$dialog, that.registerClass, that.order_callbackClass);
						}
						//   reset form 
						var $form = $(that.overlayFrmID);
						that.resetForm($form, that);
						//collect title data,  for the form title and to be used to identify the type of request 
						var title = $(this).data("title");
						// change title, collecting the title data
						$('h2', that.$dialog).text(title);
						// display dialog
						that.$dialog.dialog("open");
						// set focus on go Button to allow form inputs to display default values
						$(that.overlaySubmitID).focus();
						// populate inputs with default values held in expando properties
						$form.find("input:text").val( function(index, value) {
							return $(this).data('defValue');
						} );
						return false;
					} catch (ex) {
						ex.croakedInMethod = ' - in the callback and toorder click event of the init method of the Overlay object in common$.js ';
						ErrorHelper.onError(ex); 
						return false;
					}					
				});
				// overlay close 
				$( this.overlayCloseID).bind("click", function() {  that.$dialog.dialog("close");});	
				// validate plugin setup
				$(this.overlayFrmID).validate({ 
						rules : { 
							 ovr_email: {
								 required: true,
								 email: true
							 },
							ovr_name : "required",
							ovr_pub: "required",
							ovr_tel: "required"
						},
						 messages: {
							 ovr_email :{ required: "Please enter a valid email"},
							 ovr_name : { required: "Please enter your name"},
							 ovr_tel : { required: "Please enter your telephone no."},
							 ovr_pub : { required: "Please enter your pub"}
						 },	
						submitHandler : function (form) {
							try {
								//perform ajax call to mail details
								// fire and forget pattern used for ajax post
								// grab h2 data to determine subject and populate hidden form field
								var $frm = $(that.overlayFrmID);
								if ($frm.length>0) {
									// create hidden form field, which will be passed to identify the email subject 
									var $subject = $(that.subjectID);
									if($subject.length>0) { // subject input found, change value to current overlay H2
										$subject.val($('h2', that.overlayDialogID).text());
									}else{ // subject input not found, create
										$('<input>').attr({
											id: that.subjectID,
											type: 'hidden',
											name: that.subjectID,
											value: $('h2', that.overlayDialogID).text()
										}).appendTo($frm); 
									}
								}
								// perform ajax 
								$.ajax({
									type: "POST",
									url: that.emailURL,
									context: that, // pass context of that (Overlay), used in callback
									dataType: "text",
									data: $(form).serialize(),
									success: function () {
										// just close overlay
										that.$dialog.dialog("close");
									},
									error: that.onAjaxError 
								});
								return false;
							}catch(ex) {
								ex.croakedInMethod = ' - in the submitHandler method of the validate plugin in the Overlay object in common$.js ';
								ErrorHelper.onError(ex); 
								return false;
							}
						}
				});
			} catch (ex) {
				ex.croakedInMethod = ' - in the init method of the Overlay object in common$.js ';
				ErrorHelper.onError(ex); 
            }
		},
		// Behaviour: Overlay AJAX error handler
		 onAjaxError: function (xhrObj, status, errObj) {
            try {
				if (xhrObj.readyState == 0 || xhrObj.status == 0) { return; } // it's not really an error, user has navigated from the page before the request has completed
				// inform user
				$("p." + this.errorClass,  this.overlayFrmID ).text("Sorry, an error has occurred, please retry.");
				ErrorHelper.onError(new Error("Source: Overlay.onAjaxError method has been called when collecting " + this.emailURL + " XHR response : " + xhrObj.responseText + "   in common$.js,  Status:" + status + " JS Error: " + errObj ));
			}catch (ex) {
				// inform user
				$("p." + this.errorClass,  this.overlayFrmID ).text("Sorry, an error has occurred, please retry.");
				ex.croakedInMethod = ' - in the onAjaxError method of the Overlay object in common$.js ';
				ErrorHelper.onError(ex); 
            }
		},
		// Reset passed form
		resetForm: function($form, that){
			$form.find('input:text').removeClass(that.errorClass);
			$form.find(that.errorLabels).remove();
		},
		// switch passed dialog use by switching classes, which will display differing 
		// dialog output, i.e. Register or Order / Callback
		switchDialog : function( $dialog, removeClass, addClass ){
			$dialog.find("div") 
							  .eq(0)
							  .removeClass(removeClass)
							  .addClass(addClass);
		}
	};		
	
	// Menu object 
	var NavMenu = {
		theID: 'ul#menu_nav',
		init: function () {
			// hide all containing uls, unless the containing ul has the active class
			$(this.theID + ' li ul li ul')
				.hide() // hide all uls
				.children('li.active') // //look for active class
				.parent() // collect ul parent
				.show(); // display
			// display submenu if found....
			$(this.theID + ' li ul li a').click(
				function(){
					$(this).next().slideToggle("slow");
				}
			);
		}
	};
	
	// ErrorHelper, private object -  revealed for site use
    var ErrorHelper = {
         // private properties
        cgiURL: '/utils/sendJSError.php',
        // revealed public method
        onError: function (errObj) {
			try {
                var params = [];
                var prop;
                var i = 0;
                for (var prop in errObj) {
                    params[i] = 'error' + i + '=' + 'Error ' + prop + ' : ' + escape(errObj[prop]) + '.__';
                    i++;
                }
                if (navigator.userAgent) {
                    params[i] = 'client=' + 'User Agent: ' + escape(navigator.userAgent) + '.__';
                }
                if (navigator.vendor) {
                    params[i] += 'Vendor: ' + escape(navigator.vendor) + '.__';
                }
                if (navigator.platform) {
                    params[i] += 'Platform: ' + escape(navigator.platform) + '.__';
                }
                // add url to error information
                params[i] += 'URL: ' + location.href + '.__';
                // If we have an error in the ErrorHelper, just swallow error as we can't do anything about it
                // TODO : setup server side error emailer
				// send AJAX request, no callback needed, 'fire and forget pattern' due to low importance
                 $.ajax({
                     url: ErrorHelper.cgiURL,
					 type: "POST",
					 data:  params.join('&'),
                     cache: false,
                     error: function () { return true; } // swallow error
                });
				//console.log(errObj);
				 // return true to stop unfriendly browser alert
				return true;
            }
            catch (e) {
                // Error in errorhelper, probably ajax call not successful, squelch it as the user not interested 
				// return true to stop unfriendly browser alert
				return true;
            }

        }
	};
 // reveal public interface (API)
    return {
        // public property: ErrorHelper object
        ErrorHelper: {
            // public method
            onError: ErrorHelper.onError
        }
	}
   
 }(jQuery);


