GFaces = {
	rowsSelected : function() {
		var rowCount = $(".rowCheckbox input:checkbox:checked").length;
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	},
	/*
	 * Define this up front so we know its being used in the gfaces namespace
	 */
	filesUploading : false
};

GFaces.inputFileBrowser = {
	popupToolFieldId : null,
	parentId : null,

	show : function(fieldId) {
		this.popupToolFieldId = fieldId;
	},

	selectFile : function(path, dialog) {
		var inputField = document.getElementById(this.popupToolFieldId);
		inputField.value = path;
		inputField.focus();
		$(inputField).trigger('input');
	}
};

GFaces.popupTool = {
	open : function(fieldId, url, width, height, winname) {
		popupToolFieldId = fieldId;
		scroll = 1;
		winl = (screen.width - width) / 2;
		wint = (screen.height - height) / 2;
		settings = "height=" + height + ",";
		settings += "width=" + width + ",";
		settings += "top=" + wint + ",";
		settings += "left=" + winl + ",";
		settings += "scrollbars=" + scroll + ",";
		settings += "resizable=yes";
		win = window.open(url, winname, settings);
		if (parseInt(navigator.appVersion) >= 4) {
			win.window.focus();
		}
	}
};

// Cross Browser selectionStart/selectionEnd
// Version 0.2
// Copyright (c) 2005-2007 KOSEKI Kengo
//
// This script is distributed under the MIT licence.
// http://www.opensource.org/licenses/mit-license.php
function LS_Selection(textareaElement) {
	this.element = textareaElement;
}

LS_Selection.prototype.create = function() {
	if (document.selection != null && this.element.selectionStart == null) {
		return this._ieGetSelection();
	} else {
		return this._mozillaGetSelection();
	}
}

LS_Selection.prototype._mozillaGetSelection = function() {
	return {
		start : this.element.selectionStart,
		end : this.element.selectionEnd
	};
}

LS_Selection.prototype._ieGetSelection = function() {
	this.element.focus();

	var range = document.selection.createRange();
	var bookmark = range.getBookmark();

	var contents = this.element.value;
	var originalContents = contents;
	var marker = this._createSelectionMarker();
	while (contents.indexOf(marker) != -1) {
		marker = this._createSelectionMarker();
	}

	var parent = range.parentElement();
	range.text = marker + range.text + marker;
	contents = this.element.value;

	var result = {};
	result.start = contents.indexOf(marker);
	contents = contents.replace(marker, "");
	result.end = contents.indexOf(marker);

	this.element.value = originalContents;
	range.moveToBookmark(bookmark);
	range.select();

	return result;
}

LS_Selection.prototype._createSelectionMarker = function() {
	return "##SELECTION_MARKER_" + Math.random() + "##";
}

/**
 * The VariablePopup is used on places like triggers. Basically when an input
 * field receives focus there appears a ${var} icon next to the field. When the
 * button is clicked it will show the variable popup.
 */
var VariablePopup = {
	attachedToField : null,
	caretInfo : {
		start : 0,
		end : 0
	},
	component : null,
	popupName : 'varPopup',

	showButton : function(obj) {
		// if an attached to object is present then hide it
		if (this.attachedToField != null && this.attachedToField.length > 0) {
			$('[id="' + this.attachedToField + '"]').addClass('Hidden');
		}

		// find the nearby button of this object
		var nearbyButton = $(obj).parents('.gfaces-input-with-variable').next(
				'td').find('button.Hidden');
		// show the button nearby associated to this object
		nearbyButton.removeClass('Hidden');

		// set the attached to object to the nearby button id
		this.attachedToField = $(nearbyButton).attr('id');

		// set this component to the current object
		this.component = obj;
	},

	showPopup : function(anchorId) {
		var ls_selection = new LS_Selection(this.component);
		var s = ls_selection.create();
		this.caretInfo.start = s.start;
		this.caretInfo.end = s.end;
		PF(this.popupName).show();
		return false;
	},

	insertVariable : function(evt) {
		var newValue = "${" + evt + "}";
		var val = this.component.value;
		if ($(this.component).hasClass('encryptedField')) {
			val = this.component.getHidden().value;
		}
		var beginning = val.substr(0, this.caretInfo.start);
		var end = val.substr(this.caretInfo.end, val.length);
		newValue = beginning + newValue + end;
		this.setValue(newValue);
		this.component.focus();
		PF(this.popupName).hide();
	},

	replaceVariable : function(evt) {
		var newValue = "${" + evt + "}";
		this.setValue(newValue);
		this.component.focus();
		PF(this.popupName).hide();
	},

	setValue : function(value) {
		var comp = this.component;
		$(comp).trigger('input');
		if ($(comp).hasClass('encryptedField')) {
			// If its a password field go through the special password logic
			comp.applyValue(value);
		} else {
			// Apply the value as normal
			comp.value = value;
		}
	}
};

var QuickHelp = {
	show : function(caller, helpText, defaultValue, additionalInfoURL) {
		var id = $(caller).attr('id');
		$('.QuickHelpPanel').removeClass('Hidden');
		// Set the help Text
		$('.QuickHelpText').html(helpText);

		// Update the default panel
		var QHDPanel = $('.QHDPanel');
		if (defaultValue != '') {
			QHDPanel.removeClass('Hidden');
			$('.QuickHelpDefault').html(defaultValue);
		} else {
			QHDPanel.addClass('Hidden');
		}

		// Load Additional Info URL
		var QHAIPanel = $('.QHAIPanel');
		if (additionalInfoURL != '') {
			QHAIPanel.removeClass('Hidden');
			QuickHelp._loadAddInfoURL(additionalInfoURL);
		} else {
			QHAIPanel.addClass('Hidden');
		}

		// Show the quickHelp Popup
		PF('QuickHelpPanel').show(id);
	},

	_loadAddInfoURL : function(url) {
		if (url.indexOf('javascript:') == 0) {
			url = url.substring(11);
		} else {
			if (!url.indexOf('http://') == 0) {
				url = window.location.host + url;
			}
			url = "GFaces.popupTool.open(null,'" + url
					+ "', '800', '600',null)";
		}

		$('.QuickHelpAddInfo').attr('onclick', url + "; return false;");
	}
}

/**
 * Returns the browser details as an object containing both name and version
 * 
 * @namespace GFaces
 * @method getBrowserInfo
 * @return browser information
 */
GFaces.getBrowserInfo = function() {
	try {
		var ua = navigator.userAgent, tem, M = ua
				.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i)
				|| [];
		if (/trident/i.test(M[1])) {
			tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
			return {
				name : 'IE',
				version : (tem[1] || '')
			};
		}
		if (M[1] === 'Chrome') {
			tem = ua.match(/\bOPR\/(\d+)/)
			if (tem != null) {
				return {
					name : 'Opera',
					version : tem[1]
				};
			}
		}
		M = M[2] ? [ M[1], M[2] ] : [ navigator.appName, navigator.appVersion,
				'-?' ];
		if ((tem = ua.match(/version\/(\d+)/i)) != null) {
			M.splice(1, 1, tem[1]);
		}
		return {
			name : M[0],
			version : M[1]
		};
	} catch (err) {
		return {
			name : "Unknown",
			version : 0
		};
	}
}

function htmlEncode(value) {
	return $('<div/>').text(value).html();
}

function FMCOpenHelp(id, skinName, searchQuery, firstPick, pathToHelpSystem) {
	MadCap.OpenHelp(id, skinName, searchQuery, firstPick, pathToHelpSystem);
}

/**
 * Determines if the current window is in an iframe. May be the case if the
 * application itself is embedded in an iframe or this script runs in an iframe
 * opened by the application.
 * 
 * @return {boolean} true = if current window is in an iframe.
 */
GFaces.isEmbeddedInIFrame = function() {
	return window !== parent;
}

/**
 * Determines if the current window is an iframe opened by the base application.
 * 
 * @return {boolean} true - if current window is an iframe opened by base
 *         application
 */
GFaces.isInternalIFrame = function() {
	var hasParentWindow = window !== parent;
	// Parent window might be an iframe embedding the application
	if (hasParentWindow) {
		try {
			// Cache original value (to make sure we don't overwrite anything)
			var originalTryIframe = parent.tryIframe;
			// Try to set something on parent (will get a cross-origin access
			// error if parent is embedding application)
			parent.tryIframe = true;
			// Reset original value
			parent.tryIframe = originalTryIframe;
		} catch (e) {
			// Cannot access parent frame, so we are in the application window
			// itself rather than an internal iframe
			return false;
		}
	}
	return hasParentWindow;
};

var ChangeHandler = {
	init : function(cfg) {
		var $this = this;

		this.iframeMode = GFaces.isInternalIFrame();
		
		this.cachedButtonClicks = [];
		
		if (this.iframeMode) {
			parent.ChangeHandler = this;
			$(window).on('beforeunload', function(event) {
				var cachedClicks = ChangeHandler.cachedButtonClicks;
				for ( var x in cachedClicks) {
					var cached = cachedClicks[x];
					$(cached.button).attr('onclick', cached.click);
				}
				ChangeHandler.initialized = false;
			});
		}

		this.handledResponse = false;
		this.callback = null;
		this.hashref = false;
		this.options = {
			saveSelector : cfg.saveSelector || '.SaveButton',
			changeListener : cfg.changeListener || changesMade,
			savePromptWidgetVar : cfg.promptWidgetVar || 'SavePrompt',
			beforeNavigateFunction : cfg.beforeNavigateFunction,
			hiddenHREFSelector : cfg.hiddenHREFSelector || '.HiddenHREF'
		};

		$(document).on('click', $this.options.saveSelector, function() {
			// If there is a validation error the HREF value is in
			// correctly getting submitted to the backing form so when
			// the save button was being clicked so it is redirecting the
			// wrong page when the save button is clicked
			$($this.options.hiddenHREFSelector).val('');
		});

		var ignoreInputSelector = cfg.ignoreInputSelector != undefined ? ', '
				+ cfg.ignoreInputSelector : '';

		var ignoreAutoCompleteEvent = cfg.ignoreAutoCompleteEvent != undefined ? cfg.ignoreAutoCompleteEvent
				: false;

		this.hasChanges = cfg.hasChanges || false; // Indicates whether there
		// have been changes

		// Determine if we are going after the web client or admin client header
		this.targetHeader = cfg.targetHeader
				|| '#layoutTop a:not(.ui-submenu-link)';
		// If we are after the web client, update to not target dropdown links 
		// when adding prompt listeners
		if (this.targetHeader == ".HeaderOuter a:not(.ui-submenu-link)[target!='_blank']"){
			this.targetHeader = ".HeaderOuter a:not(.ui-submenu-link):not(.dropdownLinkJS)[target!='_blank']";
		}

		// Bind the Menu Bar and Header links to prompt for saving
		// if changes have been made. this will also close the project if they
		// continue
		if (this.iframeMode) {
			this.addPromptListener(this.targetHeader, undefined,
					window.parent.document);
		} else {
			this.addPromptListener(this.targetHeader);
		}

		// Initialize all spots that we can have input changes

		// Standard Inputs
		var inputSelector = ':input:not(.ui-dialog :input'
				+ ignoreInputSelector + ')'
		$(document).on('input', inputSelector, this.changesMade);

		// Checkbox, Select, Radiobuttons

		var inputTypeSelector = 'input:checkbox:not(.ui-dialog :input:checkbox'
				+ ignoreInputSelector + '), select:not(.ui-dialog select'
				+ ignoreInputSelector
				+ '), input:radio:not(.ui-dialog :input:radio'
				+ ignoreInputSelector + ')'
		$(document).on('change', inputTypeSelector, this.changesMade);

		// Spinner
		// We need to override the spin method as the primefaces spinner does
		// not provide a way to capture on change when using a mouse wheel so we
		// can capture it all since all methods of changing the value go through
		// spin
		var _spin = PrimeFaces.widget.Spinner.prototype.spin;
		PrimeFaces.widget.Spinner.prototype.spin = function(dir) {
			_spin.call(this, dir);
			ChangeHandler.changesMade();
		}

		// PickList
		$(document).on('sortupdate', '.ui-picklist-target', this.changesMade);
		$(document).on('dblclick', '.ui-picklist-item', this.changesMade);
		$(document).on('click', '.ui-picklist-buttons :button',
				this.changesMade);

		// AutoComplete
		if (!ignoreAutoCompleteEvent) {
			$(document).on('click', '.ui-autocomplete-item', this.changesMade);
		}

		// Handle deletes and cuts. These are needed so we can properly detect
		// changes in IE 9.
		$(document).on('keydown', inputSelector, this.handleDelete);
		$(document).on('cut', inputSelector, function() {
			ChangeHandler.changesMade();
		});

		this.initialized = true;
	},

	handleDelete : function(event) {
		var key = event.which;
		if (key == 8 || key == 46) {
			ChangeHandler.changesMade();
		}
	},

	// Function for handling whenever changes are made.
	changesMade : function() {
		var $this = ChangeHandler;
		if (!$this.initialized || $this.hasChanges) {
			// Do nothing if there has already been marked a change
			return;
		}
		var opts = $this.options;

		// Enable the Save button
		var saveBtn = $(opts.saveSelector);
		saveBtn.removeAttr('disabled');
		saveBtn.removeClass('ui-state-disabled');

		// Indicate changes have happened
		$this.hasChanges = true;

		// Call remote command to store this on the backing form
		if (opts.changeListener) {
			opts.changeListener();
		}

	},
	
	// Method to handle prompting for changes or continuing on with a
	// navigation
	// click
	promptSaveFromMenu : function(callback, href) {
		var $this = ChangeHandler;
		var opts = $this.options;

		if (!$this.initialized) {
			// If not initialized just continue
			return true;
		}

		// If there are changes and the user hasn't seen the dialog
		if ($this.hasChanges && !$this.handledResponse) {

			// Cache the click for later use
			$this.callback = callback;
			
			// Deterimine if there is an href if there is not we do different logic
			if (!href || href == "#") {
				$this.hashref = false;
			} else {
				$this.hashref = true;
				$(opts.hiddenHREFSelector).val(href);
			}

			// Show the prompt for saving
			PF(opts.savePromptWidgetVar).show();
			return false;
		}
		// Reset the handledResponse to not handled
		$this.handledResponse = false;

		if (opts.beforeNavigateFunction) {
			opts.beforeNavigateFunction.apply(this);
		}
		return true;
	},

	// Method to handle prompting for changes or continuing on with a
	// navigation
	// click
	promptSave : function(event, sender, args) {
		var $this = ChangeHandler;
		var opts = $this.options;

		if (!$this.initialized) {
			// If not initialized just continue
			return true;
		}

		if ($this.hasChanges && !$this.handledResponse) {
			// If there are changes and the user hasn't seen the dialog

			// Cache the click for later use
			var clickedElement = sender || this;
			// Store callback to call this click later
			$this.callback = function() {
				clickedElement.click();
			}

			var href = $(clickedElement).attr('href');
			// Deterimine if there is an href if there is not we do different logic
			if (href == null || href == "#") {
				$this.hashref = false;
			} else {
				$this.hashref = true;
				$(opts.hiddenHREFSelector).val(href);
			}

			// Show the prompt for saving
			PF(opts.savePromptWidgetVar).show();

			// Stop all further listeners from doing anything
			event.stopPropagation();
			return false;
		}
		// Reset the handledResponse to not handled
		$this.handledResponse = false;

		if (opts.beforeNavigateFunction) {
			opts.beforeNavigateFunction.apply(this, args);
		}

		return true;
	},

	addPromptListener : function(selector, argsArray, doc) {
		var selection;
		if (!doc) {
			selection = $(selector);
		} else {
			selection = $(selector, doc);
		}
		selection.each(function() {
			var btn = $(this);
			var currentClick = btn.attr('onclick');
			if (!currentClick) {
				currentClick = "return true;";
			} else {
				// keep the original click so we can use it when the pages
				// leaves
				var cachedClick = {
					'button' : btn,
					'click' : currentClick
				};
				ChangeHandler.cachedButtonClicks.push(cachedClick);
			}
			btn.attr('onclick', 'if(ChangeHandler.promptSave(event, this,['
					+ argsArray + '])) {' + currentClick
					+ '} else { return false;}');
		});
	},

	handleSave : function(saveFunction) {
		if (!ChangeHandler.hashref) {
			saveFunction();
			return false;
		}
	},

	handleNoSave : function() {
		var $this = ChangeHandler;
		$this.handledResponse = true;
		if ($this.callback) {
			$this.callback();
		}
		return false;
	},
	handleCancel : function() {
		PF(ChangeHandler.options.savePromptWidgetVar).hide();
		$(ChangeHandler.options.hiddenHREFSelector).val('');
		return false;
	},
	setChangesMade : function(changesMade) {
		ChangeHandler.hasChanges = changesMade;
	}
};

// Add ability to override primefaces functions with one function call which
// will help keep them grouped
// together
GFaces.PFOverride = {
	init : function() {
		this.DateTimePicker();
		this.OverlayPanel();
	}
}

// Override fixes for the date time picker
GFaces.PFOverride.DateTimePicker = function() {
	/*
	 * GA-5857 - The jquery time picker plugin is assuming that we are using an
	 * alterative field for time, however PrimeFaces is not initalizing that alt
	 * field so It is only using the date portion. To fix the issue, we had to
	 * change the $input.val() to get the next component which the full date
	 * time instead of just the date. The field is indicated with a 1.
	 */
	if ($.timepicker) {
		$.timepicker.__proto__._addTimePicker = function(dp_inst) {
			var currDT = $
					.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input
							.val()
							+ ' ' + this.$altInput.val()
							: this.$input.next().val() /* 1 */);
			this.timeDefined = this._parseTime(currDT);
			this._limitMinMaxDateTime(dp_inst, false);
			this._injectTimePicker();
			this._afterInject();
		};
	}
	/*
	 * GA-6260 - When Primefaces is formating the date for the inline calendar,
	 * for setting on the input field They were not passing in the locale to the
	 * date so it was returning back the wrong formatted date. To fix the issue
	 * two things were added a wrapper for the format settings and passing in
	 * the format config of those settings
	 * 
	 * 1) wrapper for the settings. 2) Pass in the format config into the format
	 * date function
	 */
	PrimeFaces.widget.Calendar.prototype.bindDateSelectListener = function() {
		var _self = this;

		this.cfg.onSelect = function() {
			if (_self.cfg.popup) {
				_self.fireDateSelectEvent();

				if (_self.cfg.focusOnSelect) {
					_self.refocusInput = true;
					_self.jqEl.focus();
					if (!(_self.cfg.showOn && _self.cfg.showOn === 'button')) {
						_self.jqEl.off('click.calendar').on('click.calendar',
								function() {
									$(this).datepicker("show");
								});
					}

					setTimeout(function() {
						_self.refocusInput = false;
					}, 10);
				}
			} else {
				// Wrap the config in the settings as the jquery time picker
				// expects a settings within the init
				// (1)
				var settingsObj = {
					settings : _self.cfg
				};

				var newDate = _self.cfg.timeOnly ? '' : $.datepicker
						.formatDate(_self.cfg.dateFormat, _self.getDate(),
						/* Begin 2 */$.datepicker
								._getFormatConfig(settingsObj) /* End 2 */
						);
				if (_self.cfg.timeFormat) {
					newDate += ' '
							+ _self.jqEl.find('.ui_tpicker_time_input')[0].value;
				}

				_self.input.val(newDate);
				_self.fireDateSelectEvent();
			}
		};
	}
}

GFaces.PFOverride.OverlayPanel = function() {
	PrimeFaces.widget.OverlayPanel.prototype.applyFocus = function() {
		var firstInput = this.jq
				.find(':not(:submit):not(:button):input:visible:enabled:first');
		if (firstInput.attr('type') == 'radio') {
			// If its a radio button get wrapping table, find the one marked as
			// active and set that as the first input

			firstInput = firstInput.closest('.ui-selectoneradio').find(
					'.ui-state-active').prev().children('input');
		}
		firstInput.focus();
	}
}

// Initialize the Primefaces overrides
GFaces.PFOverride.init();

GFaces.onShowConfirm = function(dialog) {
	var parent = dialog.jq.parent();
	var found = false;
	while (parent != null && parent.prop('tagName')) {
		var position = parent.css('position').toLowerCase();
		if (position == 'fixed') {
			found = true;
			break;
		}
		parent = parent.parent();
	}

	if (found) {
		dialog.modalOverlay.remove();
		parent.prepend(dialog.modalOverlay);
	}
}