ClaMenu = function (target, items, options) {
	// current object closure
	var self = this;
	var content = jQuery('#content');


	/**
	 * Toggle hide/show functions
	 */
	self.toggle = function(target) {
		if (self.window.current === target && jQuery(self.window).css('display') === 'block') {
			return self.hide();
		} else {
			return self.show(target);
		}
	};
	/**
	 * Hide the menu
	 */
	self.hide = function() {
		jQuery(self.window).hide();
		content.empty();
	};
	/**
	 * Show the menu
	 */
	self.show = function(target) {
		// var content = jQuery('#content');
		self.window.current = target;
		// clear menu
		content.empty();
		// clone content of hidden div
		var cloned = jQuery(self.block).clone(true);
		content.append(cloned);
		// Set popup position
		var coord = jQuery(target).offset();
		jQuery(self.window).css('top', coord.top + jQuery(target).height());
		jQuery(self.window).css('left', coord.left + 5);
		// Show popup
		jQuery(self.window).show();
	};
	/**
	 * Create an unordered list of items
	 */
	self.buildItems = function() {
		self.block = jQuery('<ul/>');

		for(var key = 0; key < self.items.length; key++) {
			var entry = self.items[key];
			if ((entry !== null || entry !== '') && entry !== undefined) {
				var attributes = {};
				// It's been assumed that the first and the second values are always the html text
				// and the link address.
				if (entry.length > 2) {
					for(i = 2; i < entry.length; i++) { // Walks trough all extra attributes passed.
						if (entry[i].event) { // Get the events attributes.
							attributes[entry[i].event] = entry[i].action ? entry[i].action : cla.hideMenu();
						}
						else if (entry[i].attribute) { // Get all other attributes passed.
							attributes[entry[i].attribute] = entry[i].value ? entry[i].value : '';
						}
					}
				}
				var list_item;
				if (entry.length > 0) {
					attributes['html'] = entry[0];
					attributes['href'] = entry[1];
					list_item = jQuery('<li/>').append(jQuery('<a/>', attributes));
				} else {
					list_item = jQuery('<li/>').append(jQuery('<a/>'));
				}

				self.block.append(list_item);
			}
		}
		self.checkEvents(self.block);
	};
	/**
	 * Check if onclick property present add a menu hide if it's not'
	 */
	self.checkEvents = function(target) {
		jQuery('a', target).each(function(index, el) {
			el = jQuery(el);
			var action = el.attr('onclick');
			if (action) {
				el.prop('onclick', '');
				el.click(function(e) {
					eval(action);
					e.stopPropagation();
					cla.hideMenu();
					return false;
				});
			} else {
				el.prop('onclick', 'cla.hideMenu()');
			}
		});
	};
	/**
	 * Default options
	 */
	self.options = {
		win_id : 'cla_default_menu',
		items_prototype : 'menu_items'
	};
	/**
	 * Add any options passed to default options
	 */
	if (options) {
		jQuery.extend(self.options, options);
	}

	/**
	 * If click event is anywhere except a menu item close the menu
	 */
	jQuery('html').click(function() {
		self.hide();
	});

	self.window = document.getElementById(self.options.win_id);
	self.window.current = target;
	self.item_prototype = jQuery(document.getElementById(self.options.items_prototype));
	self.items = items;
	self.buildItems();
};

////////////////////////////////////////////////////////////
// wrapping object for Claromentis core functions
var cla = {
	init : function(){
		cla.notifications.init();	// notifications
		cla.confirmation.init();	// listener for confirmation dialog's
		cla.focus.init();			// listener for page focus/blur
		cla.checkIE();
		cla.pagetop.init();
		cla.enforceFocus.init();			// Fix for select2 when used in modal windows on IE11
		cla.isTouchDevice.init();
	},

	showMenu : function(event, items, options) {
		event = jQuery.event.fix(event);
		event.preventDefault();
		event.stopPropagation();

		var $target = jQuery(event.target);

		$target.unbind('click');
		event.target.menu = new ClaMenu(event.target, items, options);
		$target.click(function(e) {
			e.preventDefault();
			e.stopPropagation();
			this.menu.toggle(e.target);
		});
		event.target.menu.toggle(event.target);
	},
	hideMenu : function() {
		var menu = new ClaMenu('', []);
		menu.hide();
		return false;
	},
	setStatus: function (message, is_error) {
		var cm = jQuery('#common_message');
		document.title = (is_error ? 'ERROR: `' : '') + message;
		if (cm.length > 0)
		{
			if (is_error)
				message = '<font color="red">' +  message + '</font>';

			cm.html(message);
		} else
		{
			if (is_error)
				cla.showMessage(message, '', true);
		}
	},
	setPageTitle: function (title)
	{
		document.title = title;
	},
	showMessage: function (title, message, is_error)
	{
		var m_class;
		if (is_error === 'info')
			m_class = 'inner-info';
		else
			m_class = is_error ? 'inner-error' : 'inner-success';

		jQuery.meow({
			'title': title,
			'message': message,
			'duration' : (m_class === 'inner-error' ? Infinity : 5000),
			'sticky' : (m_class === 'inner-error'),
			'className' : m_class
		});
	}
};

/*
 sElementId is 'id' attribut of the element to switch visibility
 sImageElementId is 'id' attribute of the image element that should switch
 between two images shows "hide/show" states
 sImgSrcToShow is a path to the image that should be taken for the 'hidden' state
 and for action 'Show'
 sImgSrcToHide is a path to the image that should be taken for the 'displayed'
 state and for action 'hide'
 */
function changeElementVisibility(sElementId, sImgElementId, sImgSrcToShow, sImgSrcToHide) {
	// Check if we have to switch image
	var img;
	var switch_image = false;
	if (sImgElementId && sImgSrcToShow && sImgSrcToHide) {
		img = jQuery('#' + sImgElementId).get(0);
		if (img) {
			switch_image = true;
		}
	}
	var el = jQuery('#' + sElementId);
	if (el.hasClass("d-none")) {
		el.removeClass("d-none");
		if (switch_image) {
			img.src = sImgSrcToHide;
		}
	} else {
		el.addClass("d-none");
		if (switch_image) {
			img.src = sImgSrcToShow;
		}
	}
	return false;
}

var JSLoaded = {};
//Create empty object

function LoadGlobalJSOnce(sJSFile, sCallFunc) {
	//Primary JSLoaded check
	if (!JSLoaded.core) {
		JSLoaded.core = {};
	}
	// Create core as its own object
	var ScriptPath = "/intranet/js/" + sJSFile + ".js";
	if (!JSLoaded.core[sJSFile]) {
		var tCallFunc = sCallFunc;
		jQuery.getScript(ScriptPath, function() {
			tCallFunc.call();
		});
	} else {
		sCallFunc.call();
	}
	JSLoaded.core[sJSFile] = true;
}

// similar to PHP function, this one can take additional parameters
function lmsg(message_key) {
	var out = '';
	if (!document.lc || document.lc[message_key] === null) {
		return message_key;
	}

	if (arguments.length > 1) {
		function localize_number(substring, number, strings) {
			var strs = strings.split('|');
			var index = lang_get_number_index(parseInt(number), document.lc['_cur_language']);
			var val = strs[index - 1];
			if (typeof val == 'undefined')
			{
				index = lang_get_number_index(parseInt(number), 'en');
				val = strs[index - 1];
			}
			if (val.indexOf('%d') === -1) {
				return number + ' ' + val;
			} else {
				return val.replace('%d', number);
			}
		}

		function lang_get_number_index(number, lang) {
			// see http://translate.sourceforge.net/wiki/l10n/pluralforms for other languages
			switch (lang) {
				// if you change this (add a new language), don't forget to do the same in localization.php
				case 'ru':
					return (number % 10 === 1 && number % 100 !== 11 ? 1 : (number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20) ? 2 : 3));
				case 'cz':
					return (number === 1) ? 1 : ((number >= 2 && number <= 4) ? 2 : 3);
				case 'jp':
					return number === 0 ? 1 : 2;
				default:
                    return number === 1 ? 1 : 2;
			}
		}

		var params = Array.prototype.slice.call(arguments, 1);
		if (typeof(document.lc[message_key]) === 'undefined')
		{
			console.log("Localization key " + message_key + " doesn't exist");
			out = message_key;
		} else
		{
			out = cla_sprintf_min(document.lc[message_key], params);
			if (document.lc[message_key].match(/\{%d/)) {
				out = out.replace(/\{(\d+) (.*?\|.*?)\}/g, localize_number);
			}
		}
	} else {
		out = document.lc[message_key];
	}
	return out;
}

function lmsg_key_exist(localization_key) {
    return !(typeof (localization_key) !== 'string'
        || !document.lc
        || document.lc[localization_key] === null
        || typeof (document.lc[localization_key]) === 'undefined');
}

// Returns formatted string similar to sprintf, but supports only %s, %d and %%
function cla_sprintf_min(format, params) {
	var regex = /%%|%(\d+\$)?([-+#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([sid])/g;
	var i = 0;

	// finalFormat()
	var doFormat = function(substring, valueIndex, flags, minWidth, _, precision, type) {
		if (substring === '%%') {
			return '%';
		}

		// grab value using valueIndex if required?
		var value = valueIndex ? params[valueIndex.slice(0, -1)] : params[i++];

		switch (type) {
			case 's':
				return String(value);
			case 'i':
			case 'd':
				return parseInt(+value, 10);
			default:
				return substring;
		}
	};
	return format.replace(regex, doFormat);
}

(function($){
	$(document).ready(function(){
		// main nav clock
		setInterval("cla.ui_update_clock()", 60000 );

		// stop disabled icon default action
		$('body').on('click', '.cla-icon-disabled', function(){
			return false;
		});

		$('.label-contrast').getContrast()

		// bootstrap popover selector (live)
		$('body').popover({selector:"*[rel='popover']"});


		// initialise some start-up functions
		cla.init();

		// bootstrap tooltip selector (live)
		if ( $('html').hasClass('no-touch') ) {
			// Only enable tooltips on non-touch devices
			jQuery('body').tooltip({
				selector: "*[rel='tooltip']",
				container : 'body'
			});
		}

		// remove message and is_error_message from the address bar if possible (if history API is supported)
		cla.ui_strip_keys();

		// automated tab binding
		$("div[data-controls-tabs]").each(function(){
			cla_tabs_init($(this));
		});

        $('[data-toggle-disable="true"]').change(function(){
            toggleCheckboxDisabled(this);
        }).each(function(){
            toggleCheckboxDisabled(this);
        });

        // Sets the max size (before scrolling) for the dropdown menus in the header.
        $('.claro-navbar').find('.dropdown, .application-toggle, .autocomplete').on('click', function(){
        	var menu = $(this);
	        	setDropdownMaxHeight(menu.find('.js-app-wrapper-list'), 180);
				setDropdownMaxHeight(menu.find('.js-search-suggestions-inner'), 180);

                var basicMenuOffset = 96;
                setDropdownMaxHeight(menu.find('.js-company-links-list'), basicMenuOffset);
                setDropdownMaxHeight(menu.find('.js-bookmarks-list'), basicMenuOffset);
                setDropdownMaxHeight(menu.find('.js-logged-on-list'), basicMenuOffset);
        })
	});


    // Textarea maxlength - Implementing support for this on browsers that don't support it
	if(!Modernizr.input.max){
		$("textarea").each(
			function(){
				if ($(this).attr("maxlength") !== "") {
					$(this).keyup(function(e){
						var msg = $(this),
							len = msg.val().length,
							maxlen = msg.attr('maxlength');

						if(len > maxlen) {
							msg.val(msg.val().substr(0,maxlen));
							e.preventDefault();
						}
					});
				}
			}
		);
	}

	//
	cla.enforceFocus = {
		init : function() {
			// Fix for dealing with focus issues when an absolutely positioned element cannot receive focus in a bootstrap modal window
			// https://github.com/twbs/bootstrap/issues/6996
			$.fn.modal.Constructor.prototype._enforceFocus = function() {
	            $(document).on('focusin.modal', function(e) {
	                if ($(e.target).hasClass('select2-input')) {
	                	return true;
	                }
	            });
	        };
        }
	};


    /*
     * Detect when the page has focus
     * If cla.focus.hasFocus is true then continue your client-side process
     *
     */
    cla.focus = {
		init : function(){
			var that = this;
			$(window).on('focus', function(){
				// that.hasFocus = true;
				that.setFocus(true);
			}).on('blur', function(){
				// that.hasFocus = false;
				that.setFocus(false);
			});
		},

		setFocus : function(focusState){
			this.hasFocus = focusState;
		},

		hasFocus : true
    };

    /*
     * Create a confirmation pop-up when an element is clicked
     * add the following 2 attributes to an element to add the confirmation pop-up
     *
     * data-toggle="confirm":  binds a click event to the element
     *
     * data-confirm="":        this is the message content for the confirmation pop-up
     *
     */
    cla.confirmation = {
		init : function(){
			var confirm = this;
			$("[data-toggle='confirm']").each(function(){
				$(this).on('click', function(){
					confirm.doConfirm(this);
				});
			});
		},

		doConfirm : function(elem){
			var confirmation = $(elem).data( 'confirm' );
			if(!window.confirm(confirmation)) {
				return false;
			}
		}
    };

})(jQuery);


 // page top
 // searching for application menu
cla.pagetop = {
	init : function(){
		// bind search input to filter apps on key press
		jQuery('#searchApp').on('keyup', cla.pagetop.filterApps);

		// auto focus on search box
		jQuery('#appMenu').on('click', function(){
			setTimeout(function(){
				// ?? needs setTimeout otherwise it doesn't focus!
    			jQuery("#searchApp").focus();
				cla.pagetop.filterReset();
			}, 0);
			cla.pagetop.keyEvent(true);
		});

		// clear search box
		jQuery('.app-wrapper-search-close').on('click', cla.pagetop.filterReset);

		// stop dropdown menu closing when clicking inside this menu
		jQuery('.app-wrapper').on('click', function(e){
			e.stopPropagation();
		})
	},

	keyEvent : function(state){
	 	if(state){
	 		jQuery('body').on('keydown', function(e){
	 			if(e.keyCode === 27) {
	 				jQuery('#appMenu').parent().removeClass('open');
	 				cla.pagetop.filterReset();
	 			}

	 			if (e.keyCode === 40 || e.keyCode === 38) {
					cla.pagetop.appSelect(e.keyCode);
					e.preventDefault();
				}
			    if (e.keyCode === 13) {
				    var term = jQuery('#searchApp').val();
				    if (term.length > 0)
				    {
					    var first_found = jQuery('#applications').find('li:visible');
					    if (first_found.length === 1)
					    {
						    var url = first_found.find('a').prop('href');
						    if (url !== undefined){
							    window.location.href = url;

							    //open in new window
							    // var redirectWindow = window.open(url);
							    // redirectWindow.location;
						    }
					    }

				    }
			    }
        	});
	 	} else {
	 		jQuery('body').unbind('keydown');
	 	}
	},

	appSelect : function(keycode){
		var prev = keycode === 38,
			appList = jQuery('.app-wrapper-list').find('li:visible'),
			currApp = appList.find('a:focus').parent(),
			item = currApp.nextAll(':visible').first().length === 0,
			currLink = currApp.nextAll(':visible');

		// if previous (up arrow), change our selectors to cycle up the list
		if( prev ) {
			item = currApp.prevAll(':visible').first().length === 0;
			currLink = currApp.prevAll(':visible');
		}

		// if focus is on search, goto the first or last visible app in the list
		if( jQuery('#searchApp:focus').length !== 0 ) {
			var nextApp = prev ? appList.last() : appList.first();
			nextApp.find('a').focus();
			return;
		}

		// if there are no next/prev apps cycle back to the search box
		if( item ){
			jQuery('#searchApp').focus();
			return;
		}

		currLink.first().find('a').focus();
	},

	filterReset : function(){
		jQuery('#searchApp').val('').focus();
		cla.pagetop.filterApps();
		return false;
	},

	filterApps : function(){
		var term = jQuery('#searchApp').val();

		if (term.length == 0)
		{
			jQuery('#applications').find('li').toggleClass('d-none', false);
		}
		else
		{
			jQuery('#applications').find('li').each(function(){
				var check = jQuery(this).find('a:Contains("' + term + '")').length === 0;
				jQuery(this).toggleClass('d-none', check);
			});
		}
		if(jQuery('html').hasClass('ie9')) {
			jQuery(".app-wrapper").css('zoom', 0).css('zoom', 1);
		}
	}
};

// check for touch devices
cla.isTouchDevice = {
	init : function(){
		var touchClass = 'no-touch';

		if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
			touchClass = 'touch-enabled';
		}

		jQuery('html').addClass(touchClass);
	}
}

// notifications panel in navbar
cla.notifications = {
	template: null,
	mouse_is_in: false,
    unread_count: 0,
    firstListLoad: true,

	close: function(){
		jQuery('body').unbind('click', cla.notifications.closeOnClickOutside);
		jQuery('#notifications').removeClass('open');
        jQuery('.js-unread-marker').removeClass('marker-fade');

    },

	show : function(){
		var list_el = jQuery('#notificationWrapper');

		jQuery.post('/intranet/communication/im_ajax_handler.php', {'get': 1}, function (data) {
			if (cla.notifications.template === null) {
				cla.notifications.template = _.template(jQuery('#notification_template').html());
			}

            list_el.empty();

			var messages = data.messages;
            var notification_html
            //append messages to notification template
			if (messages.length!==0) {
				jQuery.each(messages, function (idx, el) {
                    el.isLastItem = idx === (messages.length - 1);
					notification_html = cla.notifications.template(el);
					list_el.append(notification_html);
				});
			} else {
                cla.notifications.template_no_messages = _.template(jQuery('#notification_template_no_messages').html());
                list_el.append(cla.notifications.template_no_messages);
			}

            //fade in unread marker if it's the first load of the notification list
            if (cla.notifications.firstListLoad){
                jQuery('.js-unread-marker').addClass('marker-fade');
                cla.notifications.firstListLoad = false;
            }

			cla.notifications.setNewCount(data.unread);
		}, 'json');

		jQuery('.dropdown.open').removeClass('open');
		jQuery('#notifications, .dropdown.open').toggleClass('open', true);
		cla.notifications.resize();
		cla.notifications.mouse_is_in = true;

		// close notification list when clicking outside the container
		jQuery('body').bind('click', cla.notifications.closeOnClickOutside);
	},

    resize : function(){
        // Sets the max size (before scrolling) for the dropdown menus.
        setDropdownMaxHeight('#notificationWrapper', 140);
    },

	markAsRead : function(el, updateCount){
		var msgid = jQuery(el).data('messageid');

		if (msgid) {
			jQuery.post('/intranet/communication/im_ajax_handler.php', {read: msgid}, function (result) {
				el.removeClass('notification-unread');

				if (updateCount)
					cla.notifications.setNewCount(cla.notifications.unread_count - 1);
			});
		}
	},

	markAllAsRead : function(){
		var messages = jQuery("#notification_list").find(".notification-unread");

		// Get messages and their ids (to be marked as read)
		var messagesToMarkAsRead = [];
		var messagesToMarkAsReadIds = [];
		if (messages) {
			messages.each(function () {
				if (jQuery(this).data('messageid')) {
					messagesToMarkAsRead.push(jQuery(this));
					messagesToMarkAsReadIds.push(jQuery(this).data('messageid'));
				}
			});

			jQuery.post('/intranet/communication/im_ajax_handler.php', {read: messagesToMarkAsReadIds}, function (result) {

				jQuery(messagesToMarkAsRead).each(function () {
					jQuery(this).removeClass('notification-unread');
				});

				var newCount = (cla.notifications.unread_count - messages.length);
				newCount = newCount >= 0 ? newCount : 0;

				cla.notifications.setNewCount(newCount);
				cla.notifications.checkNewNotifications();
				cla.notifications.close();
				cla.notifications.show();
			});
		}
	},

	init : function(){
		// track mouse position for the notification list
		jQuery('#notification_list, #msg, #notifications').mouseenter(function(){
			cla.notifications.mouse_is_in = true;
		}).mouseleave(function(){
			cla.notifications.mouse_is_in = false;
		});

		// toggle notification list
        jQuery('.notification-toggle').click(function(event){
            if (cla.notifications.isListOpen()) {
                cla.notifications.close();
            } else {
                cla.notifications.show();
            }
        });

		// mark all as read
		jQuery("#notification_list").find(".markAllAsRead").click(function(){
			cla.notifications.markAllAsRead();
			return false;
		});

		// delete notification
		jQuery('#notification_list').on('click', '.js-notification-delete', function (event) {
			var el = jQuery(event.currentTarget).parents('[data-messageid]');
			var msgid = el.data('messageid');
			if (msgid) {
				jQuery.post('/intranet/communication/im_ajax_handler.php', {'del': msgid}, function (result) {
					el.remove();
				});
			}
			return false;
		});

		// close sibling notifications that are open
		jQuery('#notification_list').on('click', '.js-details', function (event) {
			var el = jQuery(event.currentTarget).parents('.notification');

			if (el.hasClass('active_notification')) {
				jQuery('.notification-text', el).collapse('hide');
				el.removeClass('active_notification');
			} else {
				jQuery('.notification-text', el).collapse('show');
				el.addClass('active_notification')
					.siblings()
					.removeClass('active_notification')
					.find('.collapse.in')
					.collapse('hide');

				if (el.hasClass('notification-unread')) {
					cla.notifications.markAsRead(el,true);
				}
			}

			return false;
		});
	},

    isListOpen : function ()
    {
        return jQuery('#notifications').hasClass('open');
    },

	closeOnClickOutside: function () {
		if (!cla.notifications.mouse_is_in) {
			cla.notifications.close();
		}
	},

	setNewCount: function (count) {
		var obj = jQuery('.js-notify-count'); //actually two objects
		var msg;
		obj.text(count);

		if (count <= 0) {
			msg = lmsg("infobar.notifications.no_message");

			// Hide if 0
			obj.hide(0, function(){
				jQuery(this).remove('notify-important');
			});
		} else {
			msg = lmsg("infobar.notifications.new_messages", count);

			// Show indication that it has changed
			if (cla.notifications.unread_count != count)
			{
				obj.removeClass('notify-important').hide();
                //make sure it is displayed
                obj.show(0, function(){
                	jQuery(this).addClass('notify-important').show();
				});

			}
		}

        cla.notifications.unread_count = count;
        if (count > 0)
            jQuery('#notificationMarkAsRead').show();
        else
            jQuery('#notificationMarkAsRead').hide();
		// Set the tooltip
		jQuery('#infobar_new_imessage_icon').attr('data-original-title', msg);

	},


	// IM background check, moved from im_check.html
	IM_check_period: 30,
	IM_check_show_mode: 1,
	IM_user_id: 0,
	IM_prev_request: null,

	checkNewNotifications: function() {
		if (cla.focus.hasFocus) {
			if(cla.notifications.IM_prev_request !== null)
				cla.notifications.IM_prev_request.abort();
			var url = "/intranet/communication/im_ajax_handler.php?uid=" + cla.notifications.IM_user_id + "&"+Math.random();
            cla.notifications.IM_prev_request = jQuery.get(url, null, function (result, status, xhr) {
				if (status === 'success' && result) {
					cla.notifications.setNewCount(result.unread);
				}
				cla.notifications.IM_prev_request = null;
			}, 'json');
		}
	},

	startChecking: function ()
	{
		cla.notifications.checkNewNotifications();
		setTimeout(cla.notifications.startChecking, cla.notifications.IM_check_period * 1000);
	},

	bgCheckInit: function (IM_check_period, IM_check_show_mode, IM_user_id)
	{
		cla.notifications.IM_check_period = IM_check_period;
		cla.notifications.IM_check_show_mode = IM_check_show_mode;
		cla.notifications.IM_user_id = IM_user_id;
		cla.notifications.startChecking();
	}
};

cla.checkIE  = function () {
	var ie = cla.detectIE();

	if(ie) {
		if(ie <= 8) {
			jQuery('html').addClass('ie-old');
		}
		jQuery('html').addClass('ie');
	}
	return ie;
}

cla.detectIE  = function () {
	var ua = window.navigator.userAgent;
	var msie = ua.indexOf('MSIE ');

	if (msie > 0) {
		// IE 10 or older => return version number
		return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
	}

	var trident = ua.indexOf('Trident/');
	if (trident > 0) {
		// IE 11 => return version number
		var rv = ua.indexOf('rv:');
		return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
	}

	// other browser
	return false;
};

cla.CList = {
    load: function (the_list, full_url, callback) {
            var params = {
                'data': the_list.attr('data-data')
            };

            if (params.data && full_url) {
                params.href = full_url.split('?', 2)[1];

                jQuery.post('/intranet/common/common_list_server.php', params, function (data) {
                    the_list.replaceWith(data);
                    // Hides the initial paging buttons when a new set is created upon table sorting
                    if($('.CommonListAjaxPaging').length > 1) {
                        $('.CommonListAjaxPaging').first().remove();
                    }

                    if (callback)
                        callback(the_list, full_url);
                });
            }
        },

    click: function (event) {
            var the_link = jQuery(event.currentTarget);
            var the_list = the_link.parents('.CommonListAjaxWrapper');

            var full_url = the_link.prop('href');

            if (the_list.attr('data-data') && full_url)
            {
                event.preventDefault();
                cla.CList.load(the_list, full_url, cla.CList.history_push);
            }
        },

    history_push: function (the_list, full_url) {
            if (Modernizr.history)
            {
                history.replaceState(the_list.attr('id'), null, location.href);
                history.pushState(the_list.attr('id'), null, full_url);
            }
        },

    history_pop: function(e) {
            if (typeof e.state === 'string')
            {
                var the_list = jq_$(e.state);
                if (the_list.hasClass('CommonListAjaxWrapper'))
                    cla.CList.load(the_list, location.href);
            }
        },

    init: function () {
        jQuery(document).on('click', '.CommonListAjaxPaging a',null, cla.CList.click)
            .on('click', 'a.CommonListAjaxHeader', null, cla.CList.click);

        window.setTimeout(function() {
			if(window.attachEvent) {
				window.attachEvent("popstate", cla.CList.history_pop, false);
			} else {
				window.addEventListener("popstate", cla.CList.history_pop, false);
			}
        }, 1);
    }
};

cla.GREPicker = {
    Init: function (type, element_id, query_params, placeholder, allow_unset) {
            var el = jq_$(element_id);
            el.select2({
                placeholder: placeholder,
                allowClear: allow_unset,
                width: '100%',
                ajax: {
                    url: "/intranet/common/gre_picker_server.php?"+query_params,
                    dataType: 'json',
					delay: 250,
                    data: function (params) {
                    	params.page = params.page || 0;
                        return {
                            kw: params.term, // search term
                            type: type,
                            page: params.page
                        };
                    },
                    processResults: function (results) {
                        return {
                        	results: results.data,
                        	pagination: {
                        		more: results.more
                        	}
                        };
                    }
                }
            });
        }
};

// clock -
cla.ui_update_clock = function() {

	var dataTime = jQuery('#navClock').attr('data-time'),
		dataFormat = jQuery('#navClock').attr('data-format');

	if (dataFormat !== undefined)
	{
		var stored_time = parse_time(dataTime);
		stored_time.minutes ++;
		if (stored_time.minutes === 60 && stored_time.hours === 23)
		{
			jQuery('#navClock').attr('title', '').attr('data-original-title', '');
		}

		jQuery("#navClock").attr("data-time",
			format_time_string(stored_time, "H:i")
		);

		jQuery('#navClockTime').text(
			format_time_string(stored_time, dataFormat)
		);
	}

	function parse_time(time)
	{
		var currentTime = time.split(":");
		return {hours: currentTime[0], minutes: currentTime[1]};
	}
};

cla.ui_strip_keys = function() {
	if (!Modernizr.history)
		return;

	var new_url = location.href;
	var keysToStrip = ["message", "is_error_message", "from_search", "from_list"];
	var queryParams=[];
	var anchor = "";

    if(new_url.indexOf('#') > -1) {
        fragments = new_url.split('#');
        new_url = fragments[0];
        anchor = fragments[1];
    }

	if(new_url.indexOf('?') > -1) {
        var fragments = new_url.split('?');
		new_url = fragments[0];
		queryParams = fragments[1].split('&').map(function(elem){
			return elem.split('=');
		});
    }

	//strip out excluded keys
	queryParams = queryParams.filter(function(param){
		return keysToStrip.indexOf(param[0]) === -1;
	});

	//re-construct query string
	queryString = queryParams.map(function(elem){
		return elem[0] + "=" + elem[1];
	}).join('&');

	if(queryString !== "")
		new_url += '?' + queryString;

	//add the anchor back on, if there was one
	if(anchor !== "")
		new_url += "#" + anchor;

	//if the url actually changed as a result of this, overwrite it in the history
	if (location.href !== new_url)
	{
		history.replaceState(history.state, null, new_url);
	}
};


// takes time object {hours: NN, minutes: NN} and formats it
function format_time_string(time, format) {
	// set defaults
	var replaceHours = "h"; // 12 hour clock
	var	hours = time.hours,
		minutes = time.minutes;

	// check for the hourly increment
	if (minutes >= 60) {
		// reset minutes and increment the hour
		minutes = 0;
		hours++;
	}
	if (hours >= 24)
		hours = 0;

	var suffix = (hours >= 12) ? "pm" : 'am';

	var hours12 = hours % 12;
	if (hours12 === 0) hours12 = 12;

	return format.
		replace("A", suffix.toUpperCase()).
		replace("a", suffix.toLowerCase()).
		replace('H', pad(hours, 2)).
		replace('h', pad(hours12, 2)).
		replace('G', hours).
		replace('g', hours12).
		replace("i", pad(minutes, 2));

	// padding zero's function
	function pad(number, length) {
		var str = '' + number;
		while (str.length < length) {
			str = '0' + str;
		}
		return str;
	}
}


// special symbols safe loading of jQuery-wrapped DOM object by ID. jQuery('#' +
// id) is unsafe as 'id' needs to be escaped
function jq_$(id) {
	return jQuery(document.getElementById(id));
}

// Init jQuery UI tabs. With support for "open all" and hash in URL
function cla_tabs_init(selector, options) {
	var cur_tab = window.location.hash.substring(2);

	if (cur_tab == 'all') {
		cur_tab = '';
		var all_active = true;
	}

	var all_element = jQuery(selector).find('ul li a[href="#all"]');
	if (all_element.size() > 0) {
		jQuery(selector).append('<div id="all" class="d-none"></div>');
	}

	if (options === undefined) {
		options = {};
	}

	if ( typeof options.show_override === 'function') {
		options.activate = options.show_override;
	} else {
		var orig_show_function = function() {};
		var orig_beforeActivate_function = function() {};
		if ( typeof options.activate === 'function') {
			orig_show_function = options.activate;
		}
		if ( typeof options.beforeActivate === 'function') {
			orig_beforeActivate_function = options.beforeActivate;
		}
		options.activate = function(event, ui) {
			window.location.hash = '_' + ui.newPanel.prop('id');
			if (ui.newPanel.prop('id') === 'all') {
			    selector.find(".ui-tabs-panel").show().addClass('show').attr('aria-expanded', true).attr('aria-hidden', false);
				//jQuery(selector + " .ui-tabs-hide").removeClass("ui-tabs-hide");
			} else {
                orig_show_function(event, ui);
			}
		};

		options.beforeActivate = function(event, ui) {
			if (ui.oldPanel.prop('id') === 'all') {

                selector.find(".ui-tabs-panel").hide().attr('aria-expanded', false).attr('aria-hidden', true);
			}
			orig_beforeActivate_function(event, ui);
		};
	}

	if (cur_tab.length > 0) {
		var tabs_elements = jQuery('ul li a', selector);
		var cur_element_idx = tabs_elements.index(jQuery('ul li a[href="#' + cur_tab + '"]', selector));
		if (cur_element_idx > 0)
			options.active = cur_element_idx;
	}

	if (typeof jQuery.fn.__tabs == 'undefined') {
		jQuery.fn.__tabs = function (a, b, c, d, e, f) {
			// Strip message must happen before we generate new hrefs or the tabs will have different base URLs
			// from the current page and the anchors will cause a bad reload loop inside the tab panel.
			cla.ui_strip_keys();

			if (jQuery('base').length > 0) {
				var base = location.href.replace(/#.*$/, '');
				jQuery('ul>li>a[href^="#"]', this).each(function () {
					var href = jQuery(this).attr('href');
					jQuery(this).attr('href', base + href);
				});
			}

			jQuery(this).tabs(a, b, c, d, e, f);
		};
	}


	jQuery(selector).__tabs(options);

	// switch to all tab once the tab are loaded.
	if (all_element.size() > 0 && all_active) {
		jQuery(all_element).click();
	}

	/**
	 * BT-5140, BT-4308
	 *
	 * The commented out code below is a change that added 'sticky' behaviour
	 * for tabs across multiple page loads. Unfortunately it's buggy, using only a single
	 * local storage variable for any set of tabs in multiple places across the site, and
	 * does this automatically anywhere we use tabs with seemingly no way to turn it
	 * off when we need to, such as for viewing infocapture tickets, which should
	 * always default to the main ticket view tab and not remember which tab was
	 * active on some other ticket.
	 *
	 * The code has been commented out rather than deleting so it can be referred to
	 * in future if we want to implement this correctly. For now, we're rolling it back.
	 * (Tez)
	 */
    //Retain correct navigation tab pill on page reload
    // jQuery('a[data-toggle="pill"]').on('show.bs.tab', function(e) {
    //     localStorage.setItem('activeTab', jQuery(e.target).attr('href'));
    // })
    // var activeTab = localStorage.getItem('activeTab');
	//
    // if(activeTab && jQuery(selector).find('a[href="' + activeTab + '"]').length > 0 ) {
    //     jQuery(selector).find('a[href="' + activeTab + '"]').tab('show');
    //     jQuery(selector).find(activeTab).attr('aria-hidden', 'false').show();
    // }
}

// new Contains method for case insensitive searching
/**
 * @return {boolean}
 */
jQuery.expr[':'].Contains = function(a, i, m) {
	return jQuery(a).text().toUpperCase()
		.indexOf(m[3].toUpperCase()) >= 0;
};

// Disables (toggle) the given elements.
function toggleCheckboxDisabled(elem){
    var target = jQuery(elem).data('toggle-target'),
        isChecked = jQuery(elem).prop('checked');
    jQuery(target).prop("disabled", !isChecked);
}

/**
 * Sets the max height of a dropdown menu based on the page height
 * @param targetMenu - target dropdown menu to set max height on.
 */
 function setDropdownMaxHeight(targetMenu, bottomOffset){
     var menu = jQuery(targetMenu);
     var dropdownBottomHeight = bottomOffset;
     var maxWindowSize = 767;

     // Checks that the window is above the max window size and applies the dropdown height limit if true
     if (menu.length && window.innerWidth > maxWindowSize) {
         var windowHeight = window.innerHeight;

         // calculates the height of the dropdown as the window height minus the offset
         var maxHeight = windowHeight - dropdownBottomHeight;

         menu.css({'max-height' : maxHeight}).addClass('overflow-auto');

     }
 }

cla.colours = {
	getContrastYIQ: function (hexcolor){
		var threshold = 200; // this should normally be 128 but this tended to use black too often
		var thresholdcolors = ['#ffffff', '#000000'];
		return cla.colours.getColorByThreshold(hexcolor, threshold, thresholdcolors);
	},

	getColorByThreshold: function (hexcolor, threshold, thresholdcolors) {
		var r,
			g,
			b,
			yiq;

		// convert to hex if not already
		hexcolor = cla.colours.rgb2hex(hexcolor);
		// remove hash
		hexcolor = hexcolor.replace('#', '');

		// Expand 3-character colours if needed
        if (hexcolor.length === 3)
        {
            r = hexcolor.substr(0,1);
            g = hexcolor.substr(1,1);
            b = hexcolor.substr(2,1);
            hexcolor = r+r + g+g + b+b;
        }

		r = parseInt(hexcolor.substr(0,2),16);
		g = parseInt(hexcolor.substr(2,2),16);
		b = parseInt(hexcolor.substr(4,2),16);
		yiq = ((r*299)+(g*587)+(b*114))/1000;

		return (yiq < threshold) ? thresholdcolors[0] : thresholdcolors[1];
	},

	rgb2hex: function(colour) {
	    var rgb = colour.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
	    if(rgb) {
		    function hex(x) {
		        return ("0" + parseInt(x).toString(16)).slice(-2);
		    }
		    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
		}
		return colour;
	},

    /**
     * Convert hex color code to RGB values in [0, 1] range
     * @param {string} hex - The hex color code (e.g., "#ff6347")
     * @returns {Array} - An array with RGB values in [0, 1] range
     */
    hex2rgb: function(hex) {
        // Remove the leading '#' if present
        hex = hex.replace(/^#/, '');

        // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
        if (hex.length === 3) {
            hex = hex.split('').map(char => char + char).join('');
        }

        // Parse the r, g, b values from the hex string
        let r = parseInt(hex.slice(0, 2), 16);
        let g = parseInt(hex.slice(2, 4), 16);
        let b = parseInt(hex.slice(4, 6), 16);

        // Normalize the values to the [0, 1] range
        r /= 255;
        g /= 255;
        b /= 255;

        return [r, g, b];
    }
};

jQuery.fn.extend({
	getContrast: function() {
		var labels = jQuery(this);

		if (labels) {
			labels.each(function(){
				var colour = jQuery(this).css('background-color');
				jQuery(this).attr("style", jQuery(this).attr('style') + '; ' + "color: " + cla.colours.getContrastYIQ(colour) + " !important" );
			})
		}
	},

    // get the offset width of an element whose parent is hidden
    getHiddenOffsetWidth: function () {
        // save a reference to a cloned element that can be measured
        var $hiddenElement = $(this).clone().appendTo('body');

        // calculate the width of the clone
        var width = $hiddenElement.outerWidth() || 0;

        // remove the clone from the DOM
        $hiddenElement.remove();

        return width;
    }

});
