// UI Script GlobalFunctionsCERN
/**
 * @fileOverview UI Script with global client-side functions
 * @name GlobalFunctionshttps://cerndev.service-now.com/images/icons/find.gifxCERN
 */

/**
 * Check if a given user belongs to a given group.<br />
 * First we check if the result has been cached.<br />
 * If not, if the user is the currently logged in user, we will avoid doing an AJAX call.<br />
 * If not, if the group or user are undefined, null or empty, we return false.<br />
 * Otherwise, we have to check with an AJAX call in the server (we cannot have all the group memberships in the client).
 * @param {string} groupSysId sys_id of the group
 * @param {string} userSysId sys_id of the user
 * @returns {boolean} if the user belongs to the group
 */
function isUserGroupMember(groupSysId, userSysId) {

	// If the group or user are undefined, null or empty, we return false.
	if (!groupSysId || !userSysId) {
		return false;
	}

	// Check if we have already this answer in the cache
	if (cernCache.exists('isUserGroupMember', groupSysId, userSysId)) {
		return cernCache.get('isUserGroupMember', groupSysId, userSysId);
	}

	var answer = false;

	// Check if we have the answer in the scratchpad, where we store the current user's groups as a string of sys_id's separated by commas
	if (typeof g_scratchpad !== "undefined" && g_scratchpad && typeof g_scratchpad.groups === 'string' && userSysId == g_user.userID) {
		answer = g_scratchpad.groups && g_scratchpad.groups.indexOf(groupSysId) != -1;
		return cernCache.store(answer, 'isUserGroupMember', groupSysId, userSysId);
	} else {

		var grmember = new GlideAjax('functionsForClientScripts');
		grmember.addParam('sysparm_name', 'isUserMemberOf');
		grmember.addParam('sysparm_userID', userSysId);
		grmember.addParam('sysparm_groupID', groupSysId);
		grmember.getXMLAnswer(isUserMember);

	}
}

/**
 * Namespace where to put global client-side utility functions
 * @namespace cernui
 */
var cernui = {
	/**
	 * Sub-namespace where to put stuff related to hide and make read-only variables in tickets
	 * @namespace cernui.variables
	 */
	variables: {

		/**
		 * Hide variable values in tickets or ticket previews in approvals given certain conditions, such as the variable
		 * being of a certain type or the variable being mapped to a ticket field.
		 * Needs the g_scratchpad to be populated with certain stuff by a "display" business rule calling the Variable-Util script include.
		 */
		hideVariables: function() {
			var i; // index for all loops

			if (g_scratchpad.hasVariables && g_scratchpad.anyVariableToHide) { // Only do stuff if there are any variables worth hiding
				var varID, varName, varLabel;

				// If possible, hide the whole variables block
				if (g_scratchpad.hideAllVariables) {
					var target = jQuery("input[name='ni.WATERMARK']");
					var targetParent = target.parent();
					if (targetParent && targetParent.get(0) && targetParent.get(0).tagName == "") {
						target = targetParent;
					}
					target.next().andSelf().hide();

				} else {

					// Hide variables that the user can edit or checkboxes who always behave as editable for the purpose of hiding them
					if (g_scratchpad.writableVariablesToHide) {
						for (i = 0; i < g_scratchpad.writableVariablesToHide.length; i++) {
							varName = g_scratchpad.writableVariablesToHide[i];
							cernui.variables._hideWritableVariable(varName);
						}
					}


					// Hide normal variables
					if (g_scratchpad.readOnlyVariablesToHide) {
						for (i = 0; i < g_scratchpad.readOnlyVariablesToHide.length; i++) {
							varID = g_scratchpad.readOnlyVariablesToHide[i];
							cernui.variables._hideReadOnlyVariable(varID);
						}
					}

					// Hide multiline variables (only possible by label match)
					if (g_scratchpad.multilineVariablesToHide) {
						for (i = 0; i < g_scratchpad.multilineVariablesToHide.length; i++) {
							varLabel = g_scratchpad.multilineVariablesToHide[i];
							cernui.variables._hideMultilineVariable(varLabel);
						}
					}


					// Hide labels (and UI Macros with Label when user can write them)
					if (g_scratchpad.labelsToHide) {
						for (i = 0; i < g_scratchpad.labelsToHide.length; i++) {
							varID = g_scratchpad.labelsToHide[i];
							cernui.variables._hideLabel(varID);
						}
					}
				}

				// Hide all container headers. Note: container labels do not appear in current.variables
				jQuery("div.sc-container-fluid").parent().hide();

				// Hide all catalog help.
				jQuery("div.question_help_text").hide();

				// Hide all breaks
				jQuery("tr.io_break").hide();
			}
		},

		/**
		 * Make variable values read-only in tickets or ticket previews given certain conditions set by the Variable-Util script include.
		 * Needs the g_scratchpad to be populated with certain stuff by a "display" business rule calling the Variable-Util script include.
		 */
		makeVariablesReadOnly: function() {
			// Inspired by http://www.servicenowguru.com/scripting/business-rules-scripting/variables-form-readonly/
			if (g_scratchpad.hasVariables && g_scratchpad.anyVariableToMakeReadOnly) {
				// Only do stuff if there are any variables worth making read-only
				var i, varID; // loop variables

				// Normal variables. We set their "disabled" attribute
				if (g_scratchpad.writableVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableVariablesToMakeReadOnly[i];
						cernui.variables._makeNormalVariableReadOnly(varID);
					}
				}

				// Text field variables. We set their "readOnly" attribute
				if (g_scratchpad.writableTextVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableTextVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableTextVariablesToMakeReadOnly[i];
						cernui.variables._makeTextFieldVariableReadOnly(varID);
					}
				}

				// Reference variables. We set their 'readOnly' attribute, remove the associated icons (lookup and target).
				if (g_scratchpad.writableReferenceVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableReferenceVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableReferenceVariablesToMakeReadOnly[i];
						cernui.variables._makeReferenceVariableReadOnly(varID);
					}
				}

				// Date variables. We set their 'readOnly' attribute and hide the calendar icon.
				if (g_scratchpad.writableDateVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableDateVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableDateVariablesToMakeReadOnly[i];
						cernui.variables._makeDateVariableReadOnly(varID);
					}
				}

				// Radio buttons (multiple choice and numeric scale). We remove all radiobuttons and we insert the text of the selected one
				if (g_scratchpad.writableRadioButtonVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableRadioButtonVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableRadioButtonVariablesToMakeReadOnly[i];
						cernui.variables._makeRadioButtonVariableReadOnly(varID);
					}
				}

				// List collector variables. We disable many of their parts.
				if (g_scratchpad.writableListCollectorVariablesToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableListCollectorVariablesToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableListCollectorVariablesToMakeReadOnly[i];
						cernui.variables._makeListCollectorVariableReadOnly(varID);
					}
				}
				// Selected Box variables. We disable many of their parts.
				if (g_scratchpad.writableSelectBoxVariableToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableSelectBoxVariableToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableSelectBoxVariableToMakeReadOnly[i];
						cernui.variables._makeSelectBoxVariableReadOnly(varID);
					}
				}
				// Selected Box variables. We disable many of their parts.
				if (g_scratchpad.writableYesNoVariableToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableYesNoVariableToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableYesNoVariableToMakeReadOnly[i];
						cernui.variables._makeYesNoVariableReadOnly(varID);
					}
				}
				if (g_scratchpad.writableCheckBoxVariableToMakeReadOnly) {
					for (i = 0; i < g_scratchpad.writableCheckBoxVariableToMakeReadOnly.length; i++) {
						varID = g_scratchpad.writableCheckBoxVariableToMakeReadOnly[i];
						cernui.variables._makeCheckBoxVariableReadOnly(varID);
					}
				}

			}
		},

		/**
		 * Hides a writable variable given its variable name.
		 * @param {string} varName The name of the variable, for example "comments".
		 */
		_hideWritableVariable: function(varName) {

			if (typeof g_form != 'undefined') {
				g_form.setDisplay('variables.' + varName, false);
			} else {
				var tmp = jQuery('item[qname*="' + varName + '"]');
				if (tmp[0]) {
					tmp = jQuery('tr[id*=' + tmp[0].id + ']');
					if (tmp[0]) {
						tmp.remove();
					}
				}
			}
		},

		/**
		 * Hides a read-only variable given the sys_id of the variable definition
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_hideReadOnlyVariable: function(varID) {
			jQuery("tr#ni\\.QS" + varID + "_read_only").remove();
		},

		/**
		 * Hides a variable of type "multiline" given its label (not possible by variable name or variable sys_id given the current Service-Now implementation)
		 * @param {string} varLabel
		 */
		_hideMultilineVariable: function(varLabel) {
			jQuery("tr.io_label:visible").filter(function() {
				return jQuery.trim(jQuery(this).text()) == varLabel;
			}).next().andSelf().hide();
		},

		/**
		 * Hide a variable of type "label" or of type "ui macro with label" given the sys_id of the variable definition.
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_hideLabel: function(varID) {
			jQuery("tr#label_ni\\.QS" + varID).closest("table.io_table").prev().andSelf().hide();
		},

		/**
		 * Make a "normal" variable read-only by setting its "disabled" attribute to true
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeNormalVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById("ni.QS" + varID);
			if (targetWidget) {
				targetWidget.disabled = true;
			}
		},

		/**
		 * Make a "text field" variable read-only by setting its "readOnly" attribute to true
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeTextFieldVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById("ni.QS" + varID);
			if (targetWidget) {
				targetWidget.readOnly = true;
			}
		},

		/**
		 * Make a "reference" variable read-only by setting its "readOnly" attribute to true, hiding the "looking glass" icon, and the "on hover" icon
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeReferenceVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById("sys_display.ni.QS" + varID);
			if (targetWidget) {
				targetWidget.readOnly = true;
			}

			var targetLookupIcon = document.getElementById("lookup.ni.QS" + varID);
			if (targetLookupIcon) {
				targetLookupIcon.style.display = 'none';
			}

			var targetLinkIcon = document.getElementById("ni.QS" + varID + "LINK");
			if (targetLinkIcon) {
				targetLinkIcon.style.display = 'none';
			}
		},

		/**
		 * Make a "date" variable read-only by setting its "readOnly" attribute to true and hiding the calendar icon.
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeDateVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById('IO:' + varID);
			if (targetWidget) {
				targetWidget.readOnly = true;
			}
			jQuery(targetWidget).siblings('a').remove();
		},

		/**
		 * Make a radio button ("multiple choice" or "numeric scale") variable read-only by hiding all the radio buttons and just showing the selected value as text
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeRadioButtonVariableReadOnly: function(varID) {
			var selectedValue = jQuery("#label_ni\\.QS" + varID).parent().find("input[checked]").attr("title");
			if (selectedValue) {
				jQuery("#label_ni\\.QS" + varID).siblings().hide();
				jQuery("#label_ni\\.QS" + varID).after("<tr><td style='padding-left:8px;'>" + selectedValue + "</td></tr>");
			}
		},

		/**
		 * Make a "list collector" variable read-only by disabling the two select lists and hiding the modification buttons.
		 * @param {string} varID The sys_id of the variable definition.
		 */
		_makeListCollectorVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById('ni.QS' + varID);
			if (targetWidget) {
				var slushBucketTable = jQuery(targetWidget).siblings("table:first");
				//slushBucketTable.find("select").attr("disabled", true);
				slushBucketTable.find("input:text").attr("disabled", true);
				slushBucketTable.find("img[src*=arrow]").closest("table").hide();
			}
		},

		_makeSelectBoxVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById('ni.QS' + varID);
			if (targetWidget) {
				jQuery(targetWidget).find("option[selected!='selected']").hide();
			}
		},

		_makeCheckBoxVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById('ni.ni.QS' + varID);
			if (targetWidget) {
				targetWidget.disable();
			}
		},

		_makeYesNoVariableReadOnly: function(varID) {
			var targetWidget = document.getElementById('ni.QS' + varID);
			if (targetWidget) {
				targetWidget.parentNode.appendChild(document.createTextNode(targetWidget.value));
				targetWidget.hide();
			}
		}
	}, // variables

	/**
	 * Converts a date into an String format "Tuesday 25th March 2016"
	 * @param {date } The date to convert
	 * @param {locale } The specific locale. Supported "en" and "fr"
	 */
	formatDateToString: function(date, locale) {
		var monthNames = ["January", "February", "March", "April",
			"May", "June", "July", "August", "September",
			"October", "November", "December",
			"Janvier", "Février", "Mars", "Avril",
			"Mai", "Juin", "Juillet", "Août", "September",
			"Octobre", "Novembre", "Décembre"
		];
		var dayNames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday",
			"Lundi", "Mardi", "Mercredi", "Jeudi", "Vandredi", "Samedi", "Dimanche"
		];
		var day = date.getDate();
		var monthIndex = locale == 'fr' ? date.getMonth() + 12 : date.getMonth();
		var dayIndex = locale == 'fr' ? date.getDay() + 6 : date.getDay() - 1;
		var year = date.getFullYear();
		var daytext = date.getDate().toString();
		if (!locale || locale == "en") {
			if (daytext[daytext.length - 1] == "1" && daytext != "11") {
				daytext = "st";
			} else if (daytext[daytext.length - 1] == "2" && daytext != "12") {
				daytext = "nd";
			} else if (daytext[daytext.length - 1] == "3" && daytext != "13") {
				daytext = "rd";
			} else {
				daytext = "th";
			}
		} else if (locale == "fr") {
			daytext = "";
		}
		var fullDate = dayNames[dayIndex] + ' ' + day + daytext + ' ' + monthNames[monthIndex] + ' ' + year;
		return fullDate;
	}
};

/**
 * Receive a value and returns if it is a number or not.
 * @param {object} n object to be checked
 * returns {boolean} if the object is a number or not
 */
function isNumber(n) {
	if (window) {
		// Old portal
		n = parseFloat(n);
	}
	if ((undefined === n) || (null === n) || (isNaN(n)) || (typeof(n) !== "number")) {
		return false;
	} else {
		return true;
	}
}