/**
 * Default GUI implementation
 * 
 * DEPENDENCIES:
 * - security.js
 * - rest.js
 * - jquery-1.3.2.min.js			// Jquery core
 * - jquery-ui-1.7.1.custom.min.js	// Jquery UI components
 * - jquery.form.js					// Jquery plugin for Ajax submission of forms
 * - jquery.validate.min.js			// Jquery form validation plugin
 * - jquery.dropshadow.js			// Jquery drop shadow plugin
 * - jquery.livequery.js			// Jquery LiveQuery plugin; (Allows binding event handling to elements not in DOM at load time)
 * 
 * @author Johan.Weitner
 * Ver: $Id: default.js,v 1.90 2010/06/28 08:14:08 marbjo Exp $
 * 
 */


var PlatsR_GUI = {
	
	BOOT_TIME: new Date(),
	
	PANEL_ANIM_SPEED: 150,
	ERRORS: "",
	NO_ERRORS: true,
	DEV_MODE: true,
	
	REGFORM_VALIDATOR: 	null,
	
	REGFORM_FIELD_LENGTH: {		// Read from serverside properties
		USERNAME: {
			MIN: 0,
			MAX: 0
		},
		PASSWORD: {
			MIN: 0,
			MAX: 0
		}
	},
	
	REGFORM_ERROR: {			// Read from serverside properties
		USERNAME: 		null,
		EMAIL:			null,
		PASSWORD:		null,
		PW_MATCH:		null,
		NO_CAPTCHA:		null,
		CAPTCHA_ERR:	null,
		GENERAL:		null
	},
	
	REGFORM: {					// Read from serverside properties
		REQUIRED: 		null,
		SUCCESS_HEADER: null,
		SUCCESS_MSG: 	null
	},
	
	LOCAL_STORAGE: null,		// Shortcut to jStore instance - for persistant local storage

	/**
	 * Initialize GUI when DOM is ready...
	 */
	init: function() {
		try {
			PlatsR_GUI.log("DOM ready - begin GUI init calls");
			PlatsR_GUI.justifyColumnHeights();
			PlatsR_GUI.initQuickForms();
			PlatsR_GUI.loadAppProps();
			PlatsR_GUI.initLoginDialog();
			PlatsR_GUI.initRegDialog();
			PlatsR_GUI.initRegForm();
			PlatsR_GUI.initPasswordDialog();

			if($("body.plats") || $("body.edit")) { 
				// If create/edit place, init edit form accordion
				PlatsR_GUI.initCreatePlaceForm();
			}

			if($("body.plats") || $("body.edit")) { 
				// If create/edit place, init confirm delete dialog
				PlatsR_GUI.initConfirmDeleteDialog();
			}
			
			if($("body.plats")) { // If browsing places, init lightbox
				PlatsR_GUI.initStoryLinks();
		   		PlatsR_GUI.initAddTagsLink();
		   		PlatsR_GUI.initBookmarkDialog();
		   		PlatsR_GUI.initGroupBookmarkLink();
		   		PlatsR_GUI.initAddToCollectionLink();
				PlatsR_GUI.initShowAllCollectionsLink();
				PlatsR_GUI.initImgBrowser();
				PlatsR_GUI.initVideoBrowser();
				PlatsR_GUI.initArchiveBrowser();
			}
			
			/*var lightBoxImages = $("a[rel^='prettyPhoto']"); 
			if(lightBoxImages) {
		   		try {
					lightBoxImages.prettyPhoto({
						showTitle: false
					});
				} catch(e) {}
			}*/
		   
		   PlatsR_GUI.log("Done with GUI init calls");
		} catch(e) {
			PlatsR_GUI.log("******   ERROR initializing GUI:   ******");
			PlatsR_GUI.log(e.message);
			PlatsR_GUI.NO_ERRORS = false;
		}
		
		PlatsR_GUI.log("**************************************************************");
		PlatsR_GUI.log("\tGUI initialized in " + (new Date() - PlatsR_GUI.BOOT_TIME) + " milliseconds.");
		PlatsR_GUI.log("**************************************************************");
	},
	
	
	
	initImgBrowser: function() {
		PlatsR_GUI.log("Initializing image browser");
		
		// Initialize main image lightbox
		$(".txtcontainer a").tooltip({ 
		    tip: '#imgtooltip',
			position: 'bottom center'
			//offset: [10, 2]
		}).overlay({ 
		    // div id for main image 
		    target: '#mainImageLightbox', 
		    expose: '#333', 
		    closeOnClick: false 
		}).gallery({ 
		    // do not use the same disabled class name as scrollable 
		    disabledClass: 'inactive' 
		});
		
		/* chained call: scrollable().find("a").tooltip().overlay().gallery(); */ 

		$(".browsercontainer .scrollable").scrollable({
			disabledClass: ''
		}).find("a").tooltip({ 
		    // use this single tooltip element for all trigger elements 
		    tip: '#imgtooltip',
			position: 'bottom center'
			//offset: [10, 2]
		}).overlay({ 
		    // each trigger uses the same overlay with id "gallery" 
		    target: '#gallery', 
		    // optional exposing effect with custom color 
		    expose: '#333', 
		    // clicking outside the overlay does not close it 
		    closeOnClick: false 
		// gallery plugin 
		}).gallery({ 
		    // do not use the same disabled class name as scrollable 
		    disabledClass: 'inactive'
		});
		
		PlatsR_GUI.log("Done initializing image browser");
	},
	

	initVideoBrowser: function() {
		PlatsR_GUI.log("Initializing video browser");
		
		$(".scrollableVideo").scrollable({
			disabledClass: ''
		}).find("a").tooltip({ 
		    tip: '#imgtooltip',
			position: 'bottom center'
			//offset: [10, 2]
		}).overlay({ 
		 
		    // each trigger uses the same overlay with id "videoGallery" 
		    target: '#videoGallery', 
		 
		    // optional exposing effect with custom color 
		    expose: '#333', 
		 
		    // clicking outside the overlay does not close it 
		    closeOnClick: false,
			
			onBeforeLoad: function() {
				var tmp = this.getTrigger().attr("href");
				var qStr = tmp.substring(tmp.indexOf("=") + 1);
				var videoURL = "http://www.youtube.com/v/"
				+ qStr + "&hl=sv_SE&fs=1&";
				
				var videoMarkup = '<object width="480" height="385"><param name="movie" value="'
				+ videoURL
				+ '"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="'
				+ videoURL
				+ '" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="480" height="385"></embed></object>'
				
				// grab wrapper element inside content
				var wrap = this.getOverlay().find(".contentWrap");
	
				// load the page specified in the trigger
				wrap.html(videoMarkup);
				
			} 
		});
		
		
		// Set container height to height of contained images
		var videoBrowserHeight = $(".scrollableVideo .items").outerHeight();
		$(".videobrowsercontainer").height(videoBrowserHeight);
		
		PlatsR_GUI.log("Done initializing video browser");
	},
	
	
	initArchiveBrowser: function() {
		PlatsR_GUI.log("Initializing archive browser");

		PlatsR_GUI.log("Initializing archive browser");
		PlatsR_GUI.log("Number of archive items: " + $(".archiveBrowser .items > span").length);
		if($(".archivebrowsercontainer .imgBrowserMargin")) {
			var lastItem = $(".archiveBrowser .items > span:last-child");
			$(".archiveBrowser .items").append(lastItem.clone());
			$(".archiveBrowser .items > span:last-child").hide();
			
		}
		PlatsR_GUI.log("Number of archive items: " + $(".archiveBrowser .items > span").length);
		
		
		$(".archiveBrowser").scrollable({
			disabledClass: '',
			items: ".archiveBrowser .items"
		}).find("a").overlay({
		    expose: '#333', 
		    target: '#archiveGallery', 
		    next: '.archivebrowsercontainer .next',
		    prev: '.archivebrowsercontainer .prev',

		    onBeforeLoad: function() {
				var wrap = this.getOverlay().find(".contentWrap");
				wrap.html('<iframe src="' + this.getTrigger().attr("href") + '" ' 
				+ 'width="700" height="600" frameborder="0">'
				+ '<p>Din webbl&auml;sare st&ouml;der inte frames.</p>'
				+ '</iframe>');
			}
		});

		PlatsR_GUI.log("Done initializing archive browser");
	},	
	
	initQuickForms: function() {
		PlatsR_GUI.log("Initializing quick forms");
		$("form.quicksearch .styledInput input").focus(function() {
			// Ugly workaround so the search field is not cleared when autocompleted
			if ($(this)[0].value == "Vad s\u00f6ker du?") {
				$(this).val("");
			}
		});
		$("form.quicklogin .styledInput input").focus(function() {
			$(this).val("");
		});
	},
	
	initTagCloud: function() {
		$('body.start #tagcloud a').tagcloud({
			size: {
				start: 9,
				end: 16,
				unit: "pt"
			}
		});
		$('body.plats #tagcloud a').tagcloud({
			size: {
				start: 8,
				end: 24,
				unit: "pt"
			}
		});
	},
	
	
	initStoryLinks: function() {
		PlatsR_GUI.log("Initializing story links...");
		// Init content popup
		var contentPopup = $("#contentPopup"); 
		contentPopup.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        modal: false,
	        draggable: false,
			resizable: false,
			width:600,
			zIndex: 2000,
			buttons: { 
				"St\u00e4ng": function() { 
					$(this).dialog("close");
					$(".ui-dialog-buttonpane button").blur();
				} 
			},
			close: function(event, ui) {
				var contentPopup = $("#contentPopup");
				contentPopup.dialog("option", "title", "Laddar...");
				contentPopup.empty();
				contentPopup.parent().removeShadow();
			}	        
	    });
	},
	
	
	showStory: function(url) {
		PlatsR_GUI.log("ShowStory invoked with URL: " + url);
		
		var contentPopup = $("#contentPopup");
		contentPopup.empty();
		
		contentPopup.load(url, {}, function() {
			var contentPopupTitle = $("#contentPopup h3");
			contentPopup.dialog('option', 'title', contentPopupTitle.html());
			contentPopupTitle.remove();
			contentPopup.parent().dropShadow();
		});
		
		contentPopup.dialog('open');
	},
	
	
	initAddTagsLink: function() {
		PlatsR_GUI.log("Initializing Add tags link...");
		$("a.addTagsLink").each(function(i) {
			$(this).click(function() {
				PlatsR_GUI.showAddTags(this.href);
				return false;
			});
		});
		
		// Init popup
		var addTagDialog = $("#addTagDialog");
		addTagDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			resizable: false,
			modal: true,
			width: 520,
			zIndex: 2000,
			close: function(event, ui) {
				var addTagDialog = $("#addTagDialog");
				addTagDialog.parent().removeShadow();
			}	        
	    });
	},
	
	
	showAddTags: function() {
		PlatsR_GUI.log("ShowAddTags invoked");
		var addTagDialog = $("#addTagDialog");
		addTagDialog.dialog('open');
		addTagDialog.parent().dropShadow();
	},
	

	initConfirmDeleteDialog: function() {
		// Init popup
		var confirmDeleteDialog = $("#confirmDeleteDialog");
		confirmDeleteDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			resizable: false,
			modal: true,
			width: 520,
			height: 170,
			zIndex: 2000,
			close: function(event, ui) {
				var confirmDeleteDialog = $("#confirmDeleteDialog");
				confirmDeleteDialog.parent().removeShadow();
			}	        
	    });
	},

	initBookmarkDialog: function() {
		// Init popup
		var bookmarkDialog = $("#bookmarkDialog");
		bookmarkDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			resizable: false,
			modal: true,
			width: 520,
			zIndex: 2000,
			close: function(event, ui) {
				var bookmarkDialog = $("#bookmarkDialog");
				bookmarkDialog.parent().removeShadow();
			}	        
	    });
	},

	initGroupBookmarkLink: function() {
		PlatsR_GUI.log("Initializing group bookmark link...");
		$("a.groupBookmarkLink").each(function(i) {
			$(this).click(function() {
				PlatsR_GUI.showGroupBookmark(this.href);
				return false;
			});
		});
		
		// Init popup
		var groupBookmarkDialog = $("#groupBookmarkDialog");
		groupBookmarkDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			resizable: false,
			modal: true,
			width: 520,
			close: function(event, ui) {
				var groupBookmarkDialog = $("#groupBookmarkDialog");
				groupBookmarkDialog.parent().removeShadow();
			}	        
	    });
	},

	showConfirmDelete: function() {
		PlatsR_GUI.log("showConfirmDelete invoked");
		var confirmDeleteDialog = $("#confirmDeleteDialog");
		confirmDeleteDialog.dialog('open');
		confirmDeleteDialog.parent().dropShadow();
	},

	showBookmark: function() {
		PlatsR_GUI.log("ShowBookmark invoked");
		var bookmarkDialog = $("#bookmarkDialog");
		bookmarkDialog.dialog('open');
		bookmarkDialog.parent().dropShadow();
	},

	showGroupBookmark: function() {
		PlatsR_GUI.log("ShowGroupBookmark invoked");
		var groupBookmarkDialog = $("#groupBookmarkDialog");
		groupBookmarkDialog.dialog('open');
		groupBookmarkDialog.parent().dropShadow();
	},

	initAddToCollectionLink: function() {
		PlatsR_GUI.log("Initializing add to collection link...");
		// Init popup
		var addToCollectionDialog = $("#addToCollectionDialog");
		addToCollectionDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			resizable: false,
			modal: true,
			width: 520,
			close: function(event, ui) {
				var addToCollectionDialog = $("#addToCollectionDialog");
				addToCollectionDialog.parent().removeShadow();
			}	        
	    });
	},

	showAddToCollection: function() {
		PlatsR_GUI.log("ShowAddToCollection invoked");
		var addToCollectionDialog = $("#addToCollectionDialog");
		addToCollectionDialog.dialog('open');
		addToCollectionDialog.parent().dropShadow();
	},

	initShowAllCollectionsLink: function() {
		PlatsR_GUI.log("Initializing show all collections link...");
		// Init popup
		var allCollectionsDialog = $("#allCollectionsDialog");
		allCollectionsDialog.dialog({
	        dialogClass: "storyDialog",
			bgiframe: true,
	        autoOpen: false,
	        draggable: false,
			width: 520,
			close: function(event, ui) {
				var allCollectionsDialog = $("#allCollectionsDialog");
				allCollectionsDialog.parent().removeShadow();
			}	        
	    });
	},

	showAllCollections: function() {
		PlatsR_GUI.log("showAllCollections invoked");
		var allCollectionsDialog = $("#allCollectionsDialog");
		allCollectionsDialog.dialog('open');
		allCollectionsDialog.parent().dropShadow();
	},

	/**
	 * Justify heights of given columns
	 */
	justifyColumnHeights: function() {
		$("body:not(.edit,.sok,.minsida) #main,#mainTwo .justifyHeight,body:not(.edit) #mainTwo .justifyHeight").vjustify(); 
	},
	
	
	/**
	 * Reads serverside properties from specified URL and 
	 * populates global variables from JSON server response.
	 * These are then saved to (and subsequently read from) 
	 * a local persistant storage to eliminate the need for 
	 * constant server roundtrips.
	 * TODO: Consider moving this to dedicated js source file; (it might grow excessively over time)
	 * TODO: Implement some serverside flag to indicate if locally stored strings should be forcefully refreshed.
	 */
	loadAppProps: function() {
		var loadStartTime = new Date();
		var url = "/platsr/properties";
		PlatsR_GUI.log("Loading application properties...");
		
		// General reg form strings
		$.getJSON(url, function(json){
			PlatsR_GUI.REGFORM.REQUIRED = json.registration_form_REQUIRED;
			PlatsR_GUI.REGFORM.SUCCESS_HEADER = json.registration_form_SUCCESS_HEADER;
			PlatsR_GUI.REGFORM.SUCCESS_MSG = json.registration_form_SUCCESS_MSG;
			
			// Minimum input value lengths for reg form
			PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MIN = json.registration_fieldLength_min_USERNAME;
			PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MAX = json.registration_fieldLength_max_USERNAME;
			PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MIN = json.registration_fieldLength_min_PASSWORD;
			PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MAX = json.registration_fieldLength_max_PASSWORD;
			
			// Reg form error messages
			PlatsR_GUI.REGFORM_ERROR.USERNAME = json.registration_validation_msg_USERNAME;
			PlatsR_GUI.REGFORM_ERROR.EMAIL = json.registration_validation_msg_EMAIL;
			PlatsR_GUI.REGFORM_ERROR.PASSWORD = json.registration_validation_msg_PASSWORD;
			PlatsR_GUI.REGFORM_ERROR.PW_MATCH = json.registration_validation_msg_PW_MATCH;
			PlatsR_GUI.REGFORM_ERROR.NO_CAPTCHA = json.registration_validation_msg_NO_CAPTCHA;
			PlatsR_GUI.REGFORM_ERROR.CAPTCHA_ERR = json.registration_validation_msg_CAPTCHA_ERR;
			PlatsR_GUI.REGFORM_ERROR.GENERAL = json.registration_validation_msg_GENERAL;
			
			// Show default response msg in form
			PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.REQUIRED);
		  
		  	// Set up and bind validator to signup form, now that error messages are loaded
		  	PlatsR_GUI.REGFORM_VALIDATOR = PlatsR_GUI.setupValidation();
			
			PlatsR_GUI.log("Loaded app properties in " + (new Date() - loadStartTime) + " ms.");
		});
		
		
		/**
		 * Init validator...
		 */
		
	},
	
	

	/**
	 * Initialize modal dialog for login form
	 * N.B: Depends on security.js
	 */
	initLoginDialog: function() {
	    PlatsR_GUI.log("initLoginDialog invoked");
		// Instantiate modal dialog
		try {
			$("#loginDialog").dialog({
				bgiframe: true,
		        autoOpen: false,
		        height: 530,
		        width: 522,
				zIndex: 2000,
		        modal: true,
		        draggable: false,
		        resizable: false,
		        closeOnEscape: false,
				dialogClass: "loginDialog",
				beforeclose: function(event, ui) {
					var location = '' + window.location;
					if (location.match("login-redirect")) {
						history.go(-1);
					} else {
						return true;
					}
				},
				open: function() {
					try {
						$(".dialogInnerWrap").dropShadow();
					} catch(e) {}
				},
				close: function() {
					$(".dialogInnerWrap").removeShadow();
		        },
				resizeStop: function(event, ui) {
					$(".dialogInnerWrap").redrawShadow();
				}
		    });
			
			$(".loginDialog").wrapInner("<div class='dialogInnerWrap'></div>"); // Workaround for drop shadow madness
			
		} catch(e) {
			PlatsR_GUI.log("Could not initialize login dialog: \n" + e.message);
			PlatsR_GUIs.NO_ERRORS = false;
		}
	},

	openLoginDialog: function(msg, url, includeMapState, loginFormId) {
		if (!msg) {
			msg = '';
		}
		if (url) {
			if (url.indexOf("http") == -1) {
				url = PlatsR_REST.getPageUrl(url, includeMapState);
			}
		} else {
			url = PlatsR_REST.getCurrentPageUrl(includeMapState);
		}
		if (!loginFormId) {
			loginFormId = '';
		}
		$('[name=msg]').val(msg);
		$('[name=url]').val(url);
		$('[name=loginFormId]').val(loginFormId);
		document.getElementById('loginIFrame').innerHTML = 
			'<iframe src="/platsr/login" ' 
			+ 'width="450" height="380" frameborder="0">'
			+ '<p>Din webbl&auml;sare st&ouml;der inte frames.</p>'
			+ '</iframe>';

		$('#loginDialog').dialog('open');
	},

	closeLoginDialog: function() {
		$('#loginDialog').dialog('close');
	},

	forumFixLoginDialog: function() {
		try {
			var browserName=navigator.appName;
			if (browserName=="Microsoft Internet Explorer") {
				$('.loginDialog').height('508px');
				$('#loginDialog').height('412px');
				$('.dialogInnerWrap').height('412px');
				$('.dialogInnerWrap').width('522px');
			}
		} catch(e) {}
	},

	/**
	 * Initialize modal dialog for signup form
	 * N.B: Depends on rest.js
	 */
	initRegDialog: function() {
		PlatsR_GUI.log("Init reg dialog invoked");
		try {
			// Instantiate modal dialog
		    $("#regDialog").dialog({
		        bgiframe: true,
		        autoOpen: false,
				width:	522,
		        height: 715,
		        modal: true,
		        resizable: false,
				stack: true,
				zIndex: 2000,
				dialogClass: "regDialog",
				open: function(event, ui) {
					PlatsR_GUI.log("Opened signup form...");
					$(".dialogInnerWrap").dropShadow();			
				},
				// Dialog close handler
				close: function(){
					PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.REQUIRED);
					$("#regform input.post").each(function(i) {
						this.value = "";
					});
					PlatsR_GUI.newCaptcha();
					PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.REQUIRED);
					$("#regform").show();
					try {
						PlatsR_GUI.REGFORM_VALIDATOR.resetForm();
						PlatsR_GUI.log("Validator reset");
					} catch(e) {
						PlatsR_GUI.log("Error: Could not reset validator");
					}
					$(".dialogInnerWrap").removeShadow();
		        },
				resizeStop: function(event, ui) {
					$(".dialogInnerWrap").redrawShadow();
				}
		    });
			
			// Event handler for Cancel link
			$('#regDialog #cancelDialog').click(function() {
				$('#regDialog').dialog('close');
			});

			// Prepare signup form for presentation
			try {
				$(".regDialog").wrapInner("<div class='dialogInnerWrap'></div>"); // Workaround for drop shadow madness
				PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.REQUIRED);
				$("#regform #PlatsRurl").val(PlatsR_REST.getEncodedPageUrl(true));
			} catch(e) {}
			
		    // Attach event handler to signup links
		    $('#registerlink,#quickregisterlink,#regfromlogindialoglink').click(function(){
		        PlatsR_GUI.openRegDialog();
		    });
			
			// Attach event handler to "New Captcha" link
		    $('#regform .newCaptchaLink').click(function(){
		        PlatsR_GUI.newCaptcha();
				return false;
		    });
			
		} catch(e) {
			PlatsR_GUI.log("Could not initialize signup dialog: \n" + e.message);
			PlatsR_GUI.NO_ERRORS = false;
		}
		
	},

	openRegDialog: function() {
        PlatsR_GUI.newCaptcha();
		$('#loginDialog').dialog('close');
		$('#regDialog').dialog('open');
		return false;
	},
	
	forumFixRegDialog: function() {
		try {
			var browserName=navigator.appName;
			if (browserName=="Microsoft Internet Explorer") {
				$('.regDialog').height('720px');
				$('#regDialog').height('720px');
				$('.dialogInnerWrap').height('720px');
				$('.dialogInnerWrap').width('522px');
			}
		} catch(e) {}
	},
	
	/**
	 * Get a new Captcha image from JForum
	 */
	newCaptcha: function() {
		// TODO: read JForum base URL from properties
		$("#captcha")[0].src = "/jforum/captcha/generate/" + new Date().getTime() + ".page";
		PlatsR_GUI.log("Captcha img updated...");
		return false;
	},

	
	/**
	 * Arm registration form for Ajax submission, and handle response
	 * N.B: Depends on jquery.form.js
	 * N.B: Depends on security.js
	 */
	initRegForm:	function() {
		PlatsR_GUI.log("Init reg form invoked");
		var validator;
		
		var regFormOpts = { 
        target:        "#dumpster",   			// target element for response - here a hidden dumpster div.
        beforeSubmit:  PlatsR_GUI.showRequest,  // pre-submit callback 
        success:       PlatsR_GUI.showResponse, // post-submit callback 
		
		dataFilter:	function(data, type) { // Purge response from page head etc
			PlatsR_GUI.log("Entering dataFilter...");
			$("#regFormLoading").hide();
			if(data.indexOf("Gratulerar!") != -1) {
				$("#regDialog").dialog("option", "title", PlatsR_GUI.REGFORM.SUCCESS_HEADER);
				PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.SUCCESS_MSG);
				$("#regFormWelcomMessage").hide();
				$("#regform").hide();				
				PlatsR_GUI.log("JForum returned: SUCCESS");
				return false;
				
			} else if(data.indexOf("Captcha-svar matchar inte") != -1) {
				PlatsR_GUI.log("JForum returned: CAPTCHA FAILURE");
				var errmsg = $(".forumline font[color=#ff0000]", jQuery(data)).text();
				PlatsR_GUI.log("Error msg: " + errmsg);
				PlatsR_GUI.showRegFormErrorResponse(PlatsR_GUI.REGFORM_ERROR.CAPTCHA_ERR);
				$('#regform #captchaResponse').addClass("invalid");
				return false;
				
			} else {
				PlatsR_GUI.log("JForum returned: FAILURE");
				var errmsg = $(".forumline font[color=#ff0000]", jQuery(data)).text();
				PlatsR_GUI.log("Error msg from JForum: " + errmsg);
				PlatsR_GUI.showRegFormErrorResponse(errmsg);
				return false;
			}
			PlatsR_GUI.log("Exiting dataFilter...");
			return data;
			}
		};

		// Bind form to ajaxForm and validator 
		try {
			$('#regform').ajaxForm(regFormOpts);	// Arm form for Ajax submission
		} catch(e) {
			PlatsR_GUI.log("Could not arm signup form with Ajax and/or validation: \n" + e.message);
			PlatsR_GUI.NO_ERRORS = false;
		}
		 
	},
	
	initPasswordDialog: function() {
	    PlatsR_GUI.log("initPasswordDialog invoked");
		// Instantiate modal dialog
		try {
			$("#passwordDialog").dialog({
				bgiframe: true,
		        autoOpen: false,
		        height: 530,
		        width: 522,
				zIndex: 2000,
		        modal: true,
		        draggable: false,
		        resizable: false,
		        closeOnEscape: false,
				dialogClass: "passwordDialog",
				open: function() {
					try {
						$(".passwordDialog .dialogInnerWrap").dropShadow();
					} catch(e) {}
				},
				close: function() {
					$(".passwordDialog .dialogInnerWrap").removeShadow();
		        },
				resizeStop: function(event, ui) {
					$(".passwordDialog .dialogInnerWrap").redrawShadow();
				}
		    });

			// Workaround for drop shadow madness
			$(".passwordDialog").wrapInner("<div class='dialogInnerWrap'></div>");
			
		} catch(e) {
			PlatsR_GUI.log("Could not initialize password dialog: \n" + e.message);
			PlatsR_GUIs.NO_ERRORS = false;
		}
	},

	openPasswordDialog: function() {
		$('#passwordDialog').dialog('open');
	},

	closePasswordDialog: function() {
		$('#passwordDialog').dialog('close');
	},

	forumFixPasswordDialog: function() {
		try {
			var browserName=navigator.appName;
			if (browserName=="Microsoft Internet Explorer") {
				$('.passwordDialog').height('508px');
				$('#passwordDialog').height('412px');
				$('.dialogInnerWrap').height('412px');
				$('.dialogInnerWrap').width('522px');
			}
		} catch(e) {}
	},

	showLoginResponse: function(responseText, statusText) {
		PlatsR_GUI.log("responseText" + responseText);
		PlatsR_GUI.log("statusText" + statusText);
		return false;
	},
	
	
	/**
	 * Instantiate signup form Validator object.
	 * N.B: Depends on /js/jquery.validate.min.js
	 */
	setupValidation: function() {
		PlatsR_GUI.log("Instantiating validator for signup form");
		var validator;
		try {
			validator = $("#regform").validate({
				errorClass: "invalid", // CSS class attached to invalid field(s)
				
				errorPlacement: function(error, element) { // Invoked when a field validation returns false
					// Some trickery to avoid flickering
					error.appendTo($("#dumpster"));
					if($("#dumpster label").html() != "") {
						PlatsR_GUI.showRegFormErrorResponse($("#dumpster").html());
						PlatsR_GUI.log("Printed error msg: " + $("#regFormErrorMessage").html());
					}
					$("#dumpster").empty();
				},
				
				success: function(label) { // Invoked when a field validation returns true
			        PlatsR_GUI.REGFORM_VALID = true;
					PlatsR_GUI.showRegFormInfoResponse(PlatsR_GUI.REGFORM.REQUIRED);
				},
				
				// Validation rules
				// These are global variables populated with a JSON object that is fetched from server at GUI init time
				// See: src/main/java/se/raa/platsr/app/PlatsrApplication.properties
				// Also: The function loadAppProps() above 
				rules: {
					username: {
				   		required: true,
				   		minlength: PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MIN,
				   		maxlength: PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MAX
					},
					password: {
						required: true,
						minlength: PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MIN,
						maxlength: PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MAX
					},
					password_confirm: {
						equalTo: "#password"
					},
					email: {
						required: true,
						email: true
					},
					captchaResponse: {
				   		required: true
					},
					accept: {
						required: true
					}
				},
				
				// Validation error messages
				// These are global variables that are populated with a JSON object 
				// that is fetched from server at GUI init time.
				// See: src/main/java/se/raa/platsr/app/PlatsrApplication.properties
				// Also: The function loadAppProps() above 
				messages: {
					username: {
						required: $.format(PlatsR_GUI.REGFORM_ERROR.USERNAME, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MAX),
				   		minlength: $.format(PlatsR_GUI.REGFORM_ERROR.USERNAME, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MAX),
				   		maxlength: $.format(PlatsR_GUI.REGFORM_ERROR.USERNAME, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.USERNAME.MAX)
				 	},
					password: {
						required: $.format(PlatsR_GUI.REGFORM_ERROR.PASSWORD, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MAX),
				   		minlength: $.format(PlatsR_GUI.REGFORM_ERROR.PASSWORD, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MAX),
				   		maxlength: $.format(PlatsR_GUI.REGFORM_ERROR.PASSWORD, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MIN, PlatsR_GUI.REGFORM_FIELD_LENGTH.PASSWORD.MAX)
					},
					password_confirm: {
						equalTo: PlatsR_GUI.REGFORM_ERROR.PW_MATCH
					},
					email: {
						required: PlatsR_GUI.REGFORM_ERROR.EMAIL,
						email: PlatsR_GUI.REGFORM_ERROR.EMAIL
					},
					captchaResponse: {
				   		required: PlatsR_GUI.REGFORM_ERROR.NO_CAPTCHA
					}
				}
			 });			
		} catch(e) {
			PlatsR_GUI.log("Could not create validator object for signup form");
		}
		return validator;
	},


	/**
	 * Pre-submit callback. Invoked when signup form is submitted.
	 * @param {Object} formData: Form data
	 * @param {Object} jqForm: Form object
	 * @param {Object} regFormOpts: AjaxForm options object
	 */ 
	showRequest:	function(formData, jqForm, regFormOpts) { 
		PlatsR_GUI.log("Pre-submit handler invoked");
		
		// Check form validity
		var valid = PlatsR_GUI.REGFORM_VALIDATOR.form();
		PlatsR_GUI.log("Form is valid: " + valid);
		if(valid) {
			PlatsR_GUI.log("Valid form submission attempt - prehandling");
			PlatsR_GUI.showLoadingAnim();
			// Log query string
			var queryString = $.param(formData); 
			PlatsR_GUI.log('Submitting: \n' + queryString); 
			
			// create cookies for login
			PlatsR_Security.createUserCookies(jqForm[0].username.value, jqForm[0].password.value);		
		} else {
			PlatsR_GUI.log("Caught invalid form submission attempt - Showing generic error msg");
			setTimeout("PlatsR_GUI.showGenericRegFormError()", 250);
		}
		// Return boolean valid, to intercept form submission if form is invalid
		return valid; 
	},


	/**
	 * Post-submit callback. Invoked when signup form is submitted.
	 * @param {Object} responseText
	 * @param {Object} statusText
	 */
	showResponse:	function(responseText, statusText)  { 
		PlatsR_GUI.log("Post-submit handler invoked");
		
		// Set form field "PlatsRurl" with value returned from getEncodedPageUrl
		$("#regform #PlatsRurl").val(PlatsR_REST.getEncodedPageUrl(true));
	},
	
	
	showLoadingAnim: function() {
		$("#regFormLoading").show();
	},
	
	
	showGenericRegFormError: function() {
		PlatsR_GUI.log("showGenericRegFormError invoked");
		PlatsR_GUI.showRegFormErrorResponse(PlatsR_GUI.REGFORM_ERROR.GENERAL);
		PlatsR_GUI.log("Showing error msg: " + $("#validationError").html());
	},
	
	
	/**
	 * Show INFO message in signup form response plate
	 * @param {Object} msg: Info message to show
	 */
	showRegFormInfoResponse: function(msg) {
		$("#regFormErrorResponse").hide();
		$("#regFormInfoMessage").html(msg);
		$("#regFormInfoResponse").show();
	},
	
	
	/**
	 * Show ERROR message in signup form response plate
	 * @param {Object} msg: Error message to show
	 */
	showRegFormErrorResponse: function(msg) {
		$("#regFormInfoResponse").hide();
		$("#regFormErrorMessage").html(msg);
		$("#regFormErrorResponse").show();
	},
	
	
	/**
	 * Instantiate accordion widget for the create-place form
	 */
	initCreatePlaceForm: function() {
		var urls;
		try {
			PlatsR_GUI.log("Initializing Create/Edit place form accordion widget");
			$("#newPlaceForm").accordion( {
				autoHeight: true, 
				clearStyle: true,
				collapsible: true,
				animated: false,
				active: -1,
				// Bind accordion events to contextual help bubble in right hand column
				changestart: function() {
					$("#contextualHelpBox").hide();
					$("#contextualHelpBox .helpBoxTxtContainer").empty();
				},
				change: function(event, ui) { 
					// Position of active accordion item, used for positioning help bubble
					var pos = ui.newHeader.position();
					if(pos) {
						// Help content, fetched from hidden element in accordion item
						var helpContent = ui.newHeader.next("fieldset").find(".helpContent");
						pos = pos.top;
						pos = (Math.round(pos) + "px");
						$("#contextualHelpBox").css("top", pos);
						$("#contextualHelpBox .helpBoxTxtContainer").html(helpContent.html());
						$("#contextualHelpBox").show();
					}
				}
				
			});
		} catch(e) {
			PlatsR_GUI.log("Could not initialize create/edit place form: \n" + e.message);
			PlatsR_GUI.NO_ERRORS = false;
		}
		// Open all accordions with archive import data
		$("#newPlaceForm .archiveImport").each(function(){
			$(this).show();
		});
	},

	/**
	 * Generic Ajax form
	 * @param {Object} formId: 						The html id attribute of the form
	 * @param {Object} sourceSelector [optional]: 	If specified, this selector will be extracted from and replace the response 
	 * @param {Object} targetSelector [optional]: 	Target selector to paste the response into. 
	 * 												(If omitted, the selector ".formPostResponse" will be used).
	 */
	postForm: function(formId, sourceSelector, targetSelector) {
		var queryString = $("#" + formId).formSerialize();	// Get form fields as URL query string 
		var url = $("#" + formId).attr("action"); 			// Get form action URL
		
		// Fallback targetSelector
		if (!targetSelector) {
			targetSelector = "#" + formId + " .formPostResponse";
		}
 		
		// Do the form submission with Ajax
		$.post(url, queryString, function(data) {
			var purgedData = data;
			// If sourceSelector, extract it from response DOM
			if(sourceSelector) {
				purgedData = $(targetSelector, jQuery(data));
			}
			
			// Paste response into targetSelector
			$(targetSelector).html(purgedData);
		}, "html"); 

		return false;
	},
	
	
	log: function(msg, isError) {
		// If not in dev mode, disable clientside logging
		if (!PlatsR_GUI.DEV_MODE) { 
			return;
		}
		
		PlatsR_GUI.ERRORS += "\n\n";
		PlatsR_GUI.ERRORS += msg;
		
		try {
			//alert(msg);
			console.log(msg);			
		} catch(e) {
			//alert(msg);
		}
	},
	
	
	
	/**
	 * Initialize jStore - support for persistant local storage
	 * See: http://plugins.jquery.com/project/jStore
	 */
	initStorage: function() {
		PlatsR_GUI.log("Initializing jStore...");
		jQuery.extend(jQuery.jStore.defaults, {  
			project: 'platsr',  
            //engine: 'flash',	//removing explicit choice of engine, let jStore decide; (although Flash has the widest client support)
            flash: 'jStore.Flash.Html'
        });
         
        jQuery.jStore.ready(function(engine){ 
			PlatsR_GUI.log("jStore ready");
				engine.ready(function(){ 
					PlatsR_GUI.log("jStore engine ready"); 
					var engine = this;  
					PlatsR_GUI.LOCAL_STORAGE = engine;
	            });
        });  
		
         
        $(function(){ 
            jQuery.jStore.load();  
			PlatsR_GUI.log("Current jStore engine in use: " + jQuery.jStore.CurrentEngine.jri);
        }); 
		
		PlatsR_GUI.log("Done initializing jStore.");
	},
	
	
	store: function(field, val) {
		PlatsR_GUI.log("Trying to store " + field + " with value " + val);
		try {
			PlatsR_GUI.LOCAL_STORAGE.set(field, val);			
		} catch(e) {
			PlatsR_GUI.log("Could not save field '" + field + "' to local storage: " + e.message);
		}
	},
	
	
	fetch: function(field) {
		PlatsR_GUI.log("Trying to fetch field '" + field + "'");
		try {
			var val = PlatsR_GUI.LOCAL_STORAGE.get(field);
			PlatsR_GUI.log("Local storage returned: " + val);
			return val;
		} catch(e) {
			PlatsR_GUI.log("Could not fetch from local storage: " + e.message);
			return null;
		}
	},
	
	editorEventCallback: function(event) {
		PlatsR_GUI.log("Event: " + event.type);
		var editor = tinyMCE.selectedInstance;
		var bm = editor.selection.getBookmark();
		var contentWithMarkup = editor.getContent(); 
		var rawContent = contentWithMarkup.replace(/<[^>]+>/g, '').replace(/&[^&]+;/g, '?');
		var rawLength = rawContent.length;
		var feedbackSelector = "#" + editor.settings.feedbackId;
		var submitSelector = (editor.settings.submitId == undefined) ? null : "." + editor.settings.submitId;
		if(rawLength > editor.settings.maxLength) {
			$(feedbackSelector).removeClass("hidden");
			if (submitSelector != null) {
				$(submitSelector).addClass("invalid");
				$(submitSelector).attr("disabled", true);
			}
		} else {
			$(feedbackSelector).addClass("hidden");
			if (submitSelector != null) {
				$(submitSelector).removeClass("invalid");
				$(submitSelector).attr("disabled", false);
			}
		}
		editor.focus();
		editor.selection.moveToBookmark(bm);
		
		return true;
	},
	
	editorSaveCallback: function(elementId, html, body) {
		var result = html.replace(/<script[^>]*>[^<]*<\/script>/g, '').replace(/<script.*\/>/g, '');
		result = result.replace(/<object[^>]*>[^<]*<\/object>/g, '').replace(/<object.*\/>/g, '');
		result = result.replace(/<img[^>]*>[^<]*<\/img>/g, '').replace(/<img.*\/>/g, '');
		result = result.replace(/<embed[^>]*>[^<]*<\/embed>/g, '').replace(/<embed.*\/>/g, '');

		return result;
	}
	
};


/**
 * vjustify - justify heights of elements in given JQuery selector
 * by: Michael Futreal, see: http://michael.futreal.com/jquery/vjustify
 */
jQuery.fn.vjustify = function() {
    PlatsR_GUI.log("VJustify invoked");
	var maxHeight=0;
    this.each(function(){
        if (this.offsetHeight>maxHeight) {maxHeight=this.offsetHeight;}
    });
	PlatsR_GUI.log("Max height found: " + maxHeight);
    this.each(function(){
        PlatsR_GUI.log("Setting max height for element");
		$(this).height(maxHeight + "px");
        if (this.offsetHeight>maxHeight) {
            $(this).height((maxHeight-(this.offsetHeight-maxHeight))+"px");
        }
    });
};


// Init GUI
$(document).ready(function() {
	PlatsR_GUI.init();
});



