var oReloadTimer = null;
var oCounterTimer = null;

function reloadDocument() {
	if(!withquery) history.pushState('', document.title, window.location.pathname);
	else if (window.location.href.match(/(&amp;|&)action=\w+/)) history.pushState('', document.title, window.location.href.replace(/(&amp;|&)action=\w+/,''));
	window.location.reload();
};

function cdpause() {
	clearTimeout(oReloadTimer);
};

function runReloadCounter() {
	var oReloadContent = document.getElementById("ReloadContent");
	if (oReloadContent) {
		if (counter < 0) {
			counter = counterfull;
		}
		counter--;
	}
};

function initDoc() {
	if (oReloadTimer) window.clearInterval(oReloadTimer);
	oReloadTimer = window.setInterval("reloadDocument();", counterfull * 1000);
	if (oCounterTimer) window.clearInterval(oCounterTimer);
	oCounterTimer = window.setInterval("runReloadCounter();", 1000);
};

/* Function for add new reader/user in readers.html/userconfig.html */
function addinsert() {
	cdpause();
	$("#searchTable").fadeOut('slow', function() {
		$("#newinsert").fadeIn('slow');
	});
}

/* Function for add new reader/user in readers.html/userconfig.html  */
function chkinsert(chkvalue) {
	if(existing_inserts.indexOf(encodeURIComponent(chkvalue))!=-1){
		alert('Entry "' + chkvalue + '" already exists!');
		return false;
	}
}

/* Function for del entry in readers.html/userconfig.html  */
function cleaninsert(deleteinsert) {
	var tmp_array = existing_inserts.slice();
	existing_inserts.length = 0;
	var i2 = 0;
	for (i = 0; i < tmp_array.length; i++) {
		if (tmp_array[i] != deleteinsert){
			existing_inserts[i2] = tmp_array[i];
			i2++;
		}
	}
}

var beep = (function () {
	var contextClass = (window.AudioContext ||
						window.webkitAudioContext ||
						window.mozAudioContext ||
						window.oAudioContext ||
						window.msAudioContext);
	if (contextClass) {
		var ctx = new contextClass();
		return function (duration, type, freq, vol, finishedCallback) {
			duration = +duration;
			// Only 0-4 are valid types.
			type = (type % 5) || 0;

			if (typeof finishedCallback != "function") {
				finishedCallback = function () {};
			}

			var osc = ctx.createOscillator();
			var gainNode = ctx.createGain();
			osc.type = type;
			osc.connect(gainNode);
			gainNode.connect(ctx.destination);
			gainNode.gain.value = vol;
			osc.type = type;
			osc.frequency.value = freq; // value in hertz
			osc.detune.value = 100; // value in cents
			osc.start(0);

			setTimeout(function () {
				osc.stop(0);
				finishedCallback();
			}, duration);
		};
	} else {
		return function (duration, type, freq, vol, finishedCallback) {return;};
	}
})();

String.prototype.toHHMMSS = function () {
	if (this.length < 1) {
		return ''
	}
	var sec_num = parseInt(this, 10); // don't forget the second param
	var years = Math.floor(sec_num / (86400*365));
	var days = Math.floor(sec_num / 86400);
	var hours = Math.floor(sec_num / 3600);
	var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
	var seconds = sec_num - (hours * 3600) - (minutes * 60);
	hours = hours - (24 * days);
	days = days - (365 * years);
	if (years < 1) {
		years = "";
	} else {
		years = years + "y ";
	}
	if (days < 1) {
		days = "";
	} else {
		days = days + "d ";
	}
	if (hours < 10) {
		hours = "0" + hours;
	}
	if (minutes < 10) {
		minutes = "0" + minutes;
	}
	if (seconds < 10) {
		seconds = "0" + seconds;
	}
	var time = days + hours + ':' + minutes + ':' + seconds;
	return time;
}

/*
 * General: Eventhandler
 */
$(function () {
	// Pollinterval UP
	$("#inc").click(function () {
		if (pollintervall > 98000 || polling) return;
		$(":text[name='pintervall']").val(Number($(":text[name='pintervall']").val()) + 1);
		pollintervall = $(":text[name='pintervall']").val() * 1000;
		if (!nostorage) {
			sessionStorage.pollintervall = pollintervall;
		}
	});
	// Pollinterval PAUSE
	$("#polling").click(function () {
		if (polling < 1) {
			polling = 1;
			$(":text[name='pintervall']").val('--');
			$('#polling').attr('class','pollingdisabled');
			$('#inc, #dec').attr('disabled','disabled');
		} else {
			polling = 0;
			$(":text[name='pintervall']").val(pollintervall/1000);
			$('#polling').attr('class','pollingenabled');
			$('#inc, #dec').removeAttr('disabled');
			clearTimeout(timer_ID);
			timer_ID = setTimeout("waitForMsg()", pollintervall);
		}
		if (!nostorage) {
			sessionStorage.polling = polling;
		}
	});
	// Pollinterval DOWN
	$("#dec").click(function () {
		if (pollintervall < 2000 || polling) return;
		$(":text[name='pintervall']").val(Number($(":text[name='pintervall']").val()) - 1);
		pollintervall = $(":text[name='pintervall']").val() * 1000;
		if (!nostorage) {
			sessionStorage.pollintervall = pollintervall;
		}
	});
	// Hover for showing Chart on Statuspage
	$('table.status').on('mouseover', 'tr > td.statuscol14', function (e) {
		var uid = '#' + $(this).parent().attr('id');
		if ('pcr'.indexOf($(uid).attr('class')) >= 0) {
			if ($(uid).data('ecmhistory')) {
				var head = $(uid + ' > td:nth-child(3)').attr('title').indexOf('(') > -1 ? $(uid + ' > td:nth-child(3)').attr('title').substring(0, $(uid + ' > td:nth-child(3)').attr('title').indexOf('(')-1) : $(uid + ' > td:nth-child(3)').attr('title');
				$('#charthead').text(head + ' History');
				$("#graph").html('');
				var arry = $(uid).data('ecmhistory').split(",");
				$.each(arry, function (index, value) {
					$("#graph").append(generateBar(value));
				});
				$("#chart").show();
			}
			$("#chart").offset({
				left: e.pageX + 20,
				top: e.pageY - 20
			});
		}
	});
	// Mousout for hiding Chart on Statuspage
	$('table.status').on('mouseout', 'tr > td.statuscol14', function () {
		$("#chart").hide();
	});

	$("#add1regex").click(function () {
		if (MAX_SEARCH_PATTERN > 98) return;
		MAX_SEARCH_PATTERN++;
		localStorage.MAX_SEARCH_PATTERN = MAX_SEARCH_PATTERN;
		var i = MAX_SEARCH_PATTERN;
		var beep_disabled = ' disabled="disabled" title="Not supported by your browser"';
		var contextClass = (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext);
		if (contextClass) { beep_disabled = ''; }
		var prefix = "0";
		if ( i > 9 ) { prefix = ""; }
		$('<LI class="regex" id="regexrow' + i + '">Search' + prefix + i + ': <input type="text" name="regex' + i + '" class="regexinput" ID="regex' + i + '" value=""> Found only: <input type="checkbox" id="whitelisted' + i + '"><label></label> Hide: <input type="checkbox" id="hidden' + i + '"><label></label> Back Color: <input size="7" maxlength="7" type="text" name="color' + i + '" class="colorinput" ID="color' + i + '" value=""> Color: <input size="7" maxlength="7" type="text" name="fcolor' + i + '" class="colorinput" ID="fcolor' + i + '" value=""> Beep: <input type="checkbox" id="beep' + i + '"' + beep_disabled +'><label></label></LI>').insertBefore(".regexdata_save");
		$('#color' + i).val($('.colorPicker_def_color').css('color'));
		$('#fcolor' + i).val($('.colorPicker_def_fcolor').css('color'));
		$('#color' + i).colorPicker();
		$('#fcolor' + i).colorPicker();
	});

	$("#del1regex").click(function () {
		var i = MAX_SEARCH_PATTERN;
		if (i < 2) return;
		if ($('#regex' + i).val() != '') if (!confirm('Search' + i + ' is not empty! Delete?')) return;
		$("#regexrow" + i).remove();
		localStorage.removeItem('regex' + i);
		localStorage.removeItem('color' + i);
		localStorage.removeItem('fcolor' + i);
		localStorage.removeItem('whitelisted' + i);
		localStorage.removeItem('hidden' + i);
		localStorage.removeItem('beep' + i);
		MAX_SEARCH_PATTERN--;
		localStorage.MAX_SEARCH_PATTERN = MAX_SEARCH_PATTERN;
	});

	$("#regexok").click(function () {

		for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
			var pattern = $('#regex' + i).val();
			if (pattern) {
				var color = $('#color' + i).val();
				var fcolor = $('#fcolor' + i).val();
			} else {
				var color = '';
				var fcolor = '';
			}
			localStorage['regex' + i] = pattern ? pattern : '';
			localStorage['color' + i] = color ? color : '';
			localStorage['fcolor' + i] = fcolor ? fcolor : '';
			localStorage['whitelisted' + i] = $('#whitelisted' + i).prop('checked') ? '1' : '0';
			localStorage['hidden' + i] = $('#hidden' + i).prop('checked') ? '1' : '0';
			localStorage['beep' + i] = $('#beep' + i).prop('checked') ? '1' : '0';
		}

	});

	$("#regexreset").click(function () {

		if (confirm('Delete all Filters and Colors?')) {
			for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
				$('#regex' + i).val('');
				$('#whitelisted' + i).prop('checked', false);
				$('#hidden' + i).prop('checked', false);
				$('#color' + i).val($('.colorPicker_def_color').css('color'));
				$('#color' + i).change();
				$('#fcolor' + i).val($('.colorPicker_def_fcolor').css('color'));
				$('#fcolor' + i).change();
				$('#beep' + i).prop('checked', false);
				localStorage['regex' + i] = '';
				localStorage['color' + i] = '';
				localStorage['fcolor' + i] = '';
				localStorage['whitelisted' + i] = '0';
				localStorage['hidden' + i] = '0';
				localStorage['beep' + i] = '0';
			}
		}

	});

	$(".sizemls a, .sizeml a").click(function () {
		maxloglines = parseInt($(this).attr('sendval'));
		$("#sizemfrom").text(' Switch displayed log lines from ' + maxloglines + ' to ');
		for (var i = 32; i <= 512; i *= 2) {
			$("#sizem" + i).attr('class', (maxloglines == i) ? 'sizemls' : 'sizeml');
		}
		return false;
	});

	$(".debugls a, .debugl a").click(function () {
		parameters = parameters + "&debug=" + $(this).attr('sendval');
		return false;
	});

	$("#savelog").on('click', function (event) {
		var txt = '';
		$("#livelogdata li").each(function (i) {
			txt += $(this).text() + '\n';
		});
		// Data URI
		txtData = 'data:application/txt;charset=utf-8,' + encodeURIComponent(txt);
		$(this).attr({
			'href': txtData,
			'target': '_blank'
		});
	});

	$("#showhidesettings").click(function () {
		if ($("#showhidesettings").val() == 'Show Settings') {
			$("#showhidesettings").val('Hide Settings');
			$("#regexdata").fadeIn('slow');
		} else {
			$("#showhidesettings").val('Show Settings');
			$("#regexdata").fadeOut('slow');
		}
	});

	$("#stoplog").click(function () {
		if ($("#stoplog").val() == 'Stop Log') {
			$("#stoplog").val('Start Log');
			stoppoll = 1;
		} else {
			$("#stoplog").val('Stop Log');
			stoppoll = 0;
			waitForMsg();
		}
	});

	$("#onlineidle").click(function () {
		if ($("#onlineidle").text() == 'Login*') {
			$("#onlineidle")
				.text('Online & Idle*')
				.attr('title', 'Login info (click to switch)');
		} else {
			$("#onlineidle")
				.text('Login*')
				.attr('title', 'Online & Idle info (click to switch)');
		}
		if (!nostorage) localStorage.loi = $("#onlineidle").text();
		waitForMsg();
	});

	// switch reader ON/OFF
	$("a.switchreader").click(function (e) {
		e.preventDefault();
		var parameters_old = parameters;
		parameters += '&label=' + $(this).data('reader-name') + '&action=' + $(this).data('next-action');
		var rowid = '#' + $(this).data('md5');
		var img = $(this).children("img");
		waitForMsg();
		if ($(this).data('next-action') == 'enable') {
			$(this).data('next-action', 'disable').attr('title', 'Disable Reader: ' + $(this).data('reader-name') + $(this).data('desc'));
			$(rowid).attr('class', 'enabledreader');
			img.attr('src', 'image?i=ICDIS').attr('alt', 'Disable');
		} else {
			$(this).data('next-action', 'enable').attr('title', 'Enable Reader: ' + $(this).data('reader-name') + $(this).data('desc'));
			$(rowid).attr('class', 'disabledreader');
			img.attr('src', 'image?i=ICENA').attr('alt', 'Enable');
		}
		parameters = parameters_old;
	});

	// delete reader
	$("a.deletereader").click(function (e) {
		e.preventDefault();
		if (confirm("Delete Reader " + $(this).data('reader-name') + "?")) {
			var parameters_old = parameters;
			parameters += '&label=' + $(this).data('reader-name') + '&action=' + $(this).data('next-action');
			cleaninsert($(this).data('reader-name'));
			waitForMsg();
			parameters = parameters_old;
			$('#' + $(this).data('md5')).fadeOut('slow');
		}
	});

	// switch user ON/OFF
	$("a.switchuser").click(function (e) {
		e.preventDefault();
		var parameters_old = parameters;
		parameters += '&user=' + $(this).data('user-name') + '&action=' + $(this).data('next-action');
		var rowid = '#' + $(this).data('md5');
		var img = $(this).children("img");
		waitForMsg();
		if ($(this).data('next-action') == 'enable') {
			$(this).data('next-action', 'disable').attr('title', 'Disable User: ' + $(this).data('user-name') + $(this).data('desc'));
			$(rowid).attr('class', 'offline');
			$(rowid + ' > td.usercol2').text('offline');
			img.attr('src', 'image?i=ICDIS').attr('alt', 'Disable');
		} else {
			$(this).data('next-action', 'enable').attr('title', 'Enable User: ' + $(this).data('user-name') + $(this).data('desc'));
			$(rowid).attr('class', 'disabled');
			$(rowid + ' > td.usercol2').text('offline (disabled)');
			img.attr('src', 'image?i=ICENA').attr('alt', 'Enable');
		}
		parameters = parameters_old;
	});

	// reset user stats
	$("a.resetuser").click(function (e) {
		e.preventDefault();
		if (confirm("Reset Stats for " + $(this).data('user-name') + "?")) {
			var parameters_old = parameters;
			parameters += '&user=' + $(this).data('user-name') + '&action=' + $(this).data('next-action');
			waitForMsg();
			parameters = parameters_old;
		}
	});

	// delete user
	$("a.deleteuser").click(function (e) {
		e.preventDefault();
		if (confirm("Delete User " + $(this).data('user-name') + "?")) {
			var parameters_old = parameters;
			parameters += '&user=' + $(this).data('user-name') + '&action=' + $(this).data('next-action');
			cleaninsert($(this).data('user-name'));
			waitForMsg();
			parameters = parameters_old;
			$('#' + $(this).data('md5')).fadeOut('slow');
		}
	});

	// search related events
	$("#searchTerm").keyup(function () {
		var value = $("#searchTerm").val().toLowerCase().trim();
		$("#dataTable tr").each(function (index) {
			if (!index) return;
			$(this).find("td").each(function () {
				var id = (($(this).data('sort-value') == undefined || $(this).hasClass("usercol2")) ? $(this).text() : $(this).data('sort-value').toString()).toLowerCase().trim();
				var not_found = (id.indexOf(value) == -1);
				$(this).closest('tr').toggle(!not_found);
				return not_found;
			});
		});
	});

	$("#searchTerm").click(function () {
		cdpause();
	});

	$("#searchTerm").blur(function () {
		initDoc();
	});

	var table = $('#dataTable').stupidtable();

	table.bind('beforetablesort', function (event, data) {
		lockpoll = 1;
		table.addClass("disabledtable");
	});

	table.bind('aftertablesort', function (event, data) {
		// data.column - the index of the column sorted after a click
		// data.direction - the sorting direction (either asc or desc)
		lockpoll = 0;
		table.removeClass("disabledtable");
	});

	// copy emm to single write emm
	$("a.tosingleemm").click(function (e) {
		var ins_emm = (/\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)\s+/).exec($(this).text());
		$('#singleemm').val(ins_emm[1]);
		$('#singleemm').change();
	});
});

/*
 * General: Update page footer and failbannotifier
 */
function updateFooter(data) {
	$("#curtime").text(' ' + data.oscam.curdate + ' | ' + data.oscam.curtime + ' ');
	$("#runtime").text(' ' + data.oscam.runtime);
	$("#uptime") .text(' ' + data.oscam.uptime);

	if ($("#fbnotifier > span.span_notifier").length) {
		if (data.oscam.failbannotifier > 0) {
			$("#fbnotifier > span.span_notifier")
				.text(data.oscam.failbannotifier);
		}
		else {
			$("#fbnotifier > span.span_notifier").remove();
		}
	}
	else if (data.oscam.failbannotifier > 0) {
		$("#fbnotifier")
			.append('<SPAN CLASS="span_notifier">'+ data.oscam.failbannotifier + '</SPAN>');
	}
}

/*
 *	identfy an element within string of elements
 */
var poll_excluded;

function is_nopoll(value) {
	return (poll_excluded.indexOf(value) > (-1)) ? true : false;
}

/*
 * Userpage Functions: Update Page
 */
function updateUserpage(data) {

	// update user lines
	$.each(data.oscam.users, function (i, item) {
		var uid = "#" + item.user.usermd5;
		poll_excluded = ($(uid).attr('nopoll') != undefined) ? $(uid).attr('nopoll') : '';

		switch (item.user.classname) {
		case 'online':
			$(uid).attr('class', item.user.classname);

			if (!is_nopoll('usercol1')) {
				if ($(uid + " td.usercol1 > span.span_notifier").length) {
					if(item.user.unotify){
						$(uid + " td.usercol1 > span.span_notifier")
							.text(item.user.unotify);
					}
					else {
						$(uid + " td.usercol1 > span.span_notifier").remove();
					}
				}
				else if(item.user.unotify) {
					$(uid + " td.usercol1")
						.append('<SPAN CLASS="span_notifier">'+ item.user.unotify + '</SPAN>');
				}
			}

			if (!is_nopoll('usercol2')) {
				$(uid + " td.usercol2")
					.attr('title', item.user.stats.expectsleep != 'undefined' ? (item.user.stats.expectsleep > 0 ? 'Sleeping in ' + item.user.stats.expectsleep + ' minutes' : 'Sleeping') : '')
					.data('sort-value', item.user.ip)
					.html("<B>" + item.user.status + "</B><br>" + item.user.ip);
			}

			if (!is_nopoll('usercol3')) {
				$(uid + " td.usercol3").html(item.user.stats.idle + "<br>" + item.user.stats.timeonchannel.toHHMMSS());
			}

			if (!is_nopoll('usercol4')) {
				if (item.user.protoicon.length > 0) {
					if (!$(uid + " td.usercol4 > img").length || $(uid + " td.usercol4 > img").attr('src')!='image?i=IC_' + item.user.protoicon) {
						var protoimage = $('<img class="protoicon" src="image?i=IC_' + item.user.protoicon + '" />');
						protoimage.hide();
						$(uid + " td.usercol4").html(protoimage);
						protoimage.fadeIn('slow');
					}
				} else {
					$(uid + " td.usercol4").text(item.user.protocol);
				}

				$(uid + " td.usercol4")
					.attr('title', item.user.prototitle)
					.data('sort-value', item.user.protosort);
			}

			// channel icon
			if (!is_nopoll('usercol6')) {
				$(uid + " td.usercol6")
					.attr('title', item.user.lastchanneltitle)
					.data('sort-value', item.user.lastchannelsort);

				if (item.user.lca.length > 0) {
					// if we already have a picon within link
					if ($(uid + " > td.usercol6 > img.usericon").length) {
						// we compare the picon name and switch if different
						var image = $(uid + " > td.usercol6 > img.usericon");
						if (image.attr('src') != 'image?i=IC_' + item.user.lca) {
							// set title of link as tooltip
							image.hide();
							image.attr('src', 'image?i=IC_' + item.user.lca);
							image.fadeIn('slow');
							image.attr('alt', item.user.lastchanneltitle);
							image.attr('title', item.user.lastchanneltitle);
						}
					} else {
						// we have no image so we have to create one

						// if we have picon clear text
						$(uid + " > td.usercol6").text('');

						// just to be sure that class of image is set
						if ($(uid + " > td.usercol6 > img").length) {
							$(uid + " > td.usercol6 > img").attr('class', 'usericon');
						}

						newimage = $('<img class="usericon" src="image?i=IC_' + item.user.lca + '">');
						newimage.hide();
						$(uid + " > td.usercol6").append(newimage);
						newimage.fadeIn('slow');
						newimage.attr('alt', item.user.lastchanneltitle);
						newimage.attr('title', item.user.lastchanneltitle);
					}
				} else {
					$(uid + " td.usercol6").html(item.user.lastchannel);
				}
			}

			if (!is_nopoll('usercol7')) {
				$(uid + " td.usercol7")
					.text(item.user.stats.cwlastresptimems);
			}
			//usercol8 ???
			if (!is_nopoll('usercol9')) {
				$(uid + " td.usercol9").text(item.user.stats.cwok);
			}
			if (!is_nopoll('usercol10')) {
				$(uid + " td.usercol10").text(item.user.stats.cwnok);
			}
			if (!is_nopoll('usercol11')) {
				$(uid + " td.usercol11").text(item.user.stats.cwignore);
			}
			if (!is_nopoll('usercol12')) {
				$(uid + " td.usercol12").text(item.user.stats.cwtimeout);
			}
			if (!is_nopoll('usercol13')) {
				$(uid + " td.usercol13").text(item.user.stats.cwccyclechecked + ' / ' + item.user.stats.cwcycleok + ' / ' + item.user.stats.cwcyclenok + ' / ' + item.user.stats.cwcycleign);
			}
			if (!is_nopoll('usercol14')) {
				$(uid + " td.usercol14").text(item.user.stats.cwcache);
			}
			if (!is_nopoll('usercol15')) {
				$(uid + " td.usercol15").text(item.user.stats.cwtun);
			}
			if (!is_nopoll('usercol16')) {
				$(uid + " td.usercol16").text(item.user.stats.cwcache);
			}
			if (!is_nopoll('usercol17')) {
				$(uid + " td.usercol17").text(item.user.stats.emmok);
			}
			if (!is_nopoll('usercol18')) {
				$(uid + " td.usercol18").text(item.user.stats.emmnok);
			}
			if (!is_nopoll('usercol19')) {
				$(uid + " td.usercol19").text(item.user.stats.cwrate + item.user.stats.cwrate2);
			}
			if (!is_nopoll('usercol22')) {
				$(uid + " td.usercol22").text(item.user.stats.cascusercomb);
			}
			if (!is_nopoll('usercol21')) {
				$(uid + " td.usercol21").text(item.user.stats.n_requ_m);
			}
			if (!is_nopoll('usercol20')) {
				$(uid + " td.usercol20")
					.attr('title', item.user.expview)
					.text(item.user.stats.expdate);
			}
			break;

		case 'connected':
			$(uid).attr('class', item.user.classname);

			if (!is_nopoll('usercol1')) {
				if ($(uid + " td.usercol1 > span.span_notifier").length) {
					if(item.user.unotify){
						$(uid + " td.usercol1 > span.span_notifier")
							.text(item.user.unotify);
					}
					else {
						$(uid + " td.usercol1 > span.span_notifier").remove();
					}
				}
				else if(item.user.unotify) {
					$(uid + " td.usercol1")
						.append('<SPAN CLASS="span_notifier">'+ item.user.unotify + '</SPAN>');
				}
			}

			if (!is_nopoll('usercol2')) {
				$(uid + " td.usercol2")
					.attr('title', '')
					.data('sort-value', item.user.ip)
					.html("<B>" + item.user.status + "</B><br>" + item.user.ip);
			}

			if (!is_nopoll('usercol3')) {
				$(uid + " td.usercol3").html(item.user.stats.idle + "<br>" + item.user.stats.timeonchannel.toHHMMSS());
			}

			if (!is_nopoll('usercol4')) {
				if (item.user.protoicon.length > 0) {
					if (!$(uid + " td.usercol4 > img").length || $(uid + " td.usercol4 > img").attr('src')!='image?i=IC_' + item.user.protoicon) {
						var protoimage = $('<img class="protoicon" src="image?i=IC_' + item.user.protoicon + '" />');
						protoimage.hide();
						$(uid + " td.usercol4").html(protoimage);
						protoimage.fadeIn('slow');
					}
				} else {
					$(uid + " td.usercol4").text(item.user.protocol);
				}
				$(uid + " td.usercol4")
					.attr('title', item.user.prototitle)
					.data('sort-value', item.user.protosort);
			}

			if (!is_nopoll('usercol6')) {
				// channel icon
				$(uid + " td.usercol6")
					.attr('title', item.user.lastchanneltitle)
					.data('sort-value', item.user.lastchannelsort);

				if (item.user.lca.length > 0) {
					var image;
					if ($(uid + " td.usercol6").html().length == 0) {
						image = $('<img class="usericon" src="image?i=IC_' + item.user.lca + '" />');
						image.hide();
						$(uid + " td.usercol6").prepend(image);
						image.fadeIn('slow');
					} else {
						image = $(uid + " td.usercol6 img.usericon");
						if (image.attr('src') != ('image?i=IC_' + item.user.lca)) {
							image.fadeOut('fast', function () {
								image.attr('src', 'image?i=IC_' + item.user.lca);
								image.fadeIn('slow');
							});
							image.attr('alt', item.user.lcb);
							image.attr('title', item.user.lastchanneltitle);
						}
					}
				} else {
					$(uid + " td.usercol6").html(item.user.lastchannel);
				}
			}

			if (!is_nopoll('usercol7')) {
				$(uid + " td.usercol7")
					.text(item.user.stats.cwlastresptimems);
			}
			if (!is_nopoll('usercol19')) {
				$(uid + " td.usercol19").text(item.user.stats.cwrate);
			}
			break;

		default:
			//check the last status
			if ('online,connected'.indexOf($(uid).attr('class')) > (-1)) {
				// last status was online so cleanup offline
				$(uid).attr('class', item.user.classname);
				if (!is_nopoll('usercol1')) {
					if ($(uid + " td.usercol1 > span.span_notifier").length) {
						$(uid + " td.usercol1 > span.span_notifier").remove();
					}
				}
				if (!is_nopoll('usercol2')) {
					$(uid + " td.usercol2")
						.attr('title', '')
						.html(item.user.status);
				}
				if (!is_nopoll('usercol3')) {
					$(uid + " td.usercol3").text('');
				}
				if (!is_nopoll('usercol4')) {
					$(uid + " td.usercol4")
						.text('')
						.attr('title', '');
					var protoimage = $(uid + " td.usercol4 img.protoicon");
					if (image) {
						protoimage.fadeOut('slow');
						protoimage.remove();
					}
				}

				//channelicon
				if (!is_nopoll('usercol6')) {
					$(uid + " td.usercol6")
						.text('')
						.data('sort-value', '');

					var image = $(uid + " td.usercol6 img.usericon");
					if (image) {
						image.fadeOut('slow');
						image.remove();
					}
				}
				if (!is_nopoll('usercol7')) {
					$(uid + " td.usercol7")
						.text('');
				}
			}
			break;
		}

		if (typeof custompoll == 'function') {
			custompoll(item);
		}

	});

	// update user totals + ECM
	updateTotals(data);

	// update footer
	updateFooter(data);
}

/*
 * Readerpage Functions: Update Page
 */
function updateReaderpage(data) {

	// update reader lines
	$.each(data.oscam.readers, function (i, item) {
		var uid = "#" + item.labelmd5;
		poll_excluded = ($(uid).attr('nopoll') != undefined) ? $(uid).attr('nopoll') : '';

		$(uid).attr('class', item.classname);

		if (!is_nopoll('readercol4')) {
			$(uid + " td.readercol4").text(item.stats.ecmsok + item.stats.ecmsokrel)
				.data('sort-value', item.stats.ecmsok);
		}
		if (!is_nopoll('readercol19')) {
			$(uid + " td.readercol19").text(item.stats.ecmsoklg + item.stats.ecmsoklgrel)
				.data('sort-value', item.stats.ecmsoklg);
		}
		if (!is_nopoll('readercol5')) {
			$(uid + " td.readercol5").text(item.stats.ecmsnok + item.stats.ecmsnokrel)
				.data('sort-value', item.stats.ecmsnok);
		}
		if (!is_nopoll('readercol6')) {
			$(uid + " td.readercol6").text(item.stats.ecmstout + item.stats.ecmstoutrel)
				.data('sort-value', item.stats.ecmstout);
		}
		if (!is_nopoll('readercol7')) {
			$(uid + " td.readercol7").text(item.stats.ecmsfiltered);
		}
		if (!is_nopoll('readercol8')) {
			$(uid + " td.readercol8").text(item.stats.emmerror);
		}
		if (!is_nopoll('readercol9')) {
			$(uid + " td.readercol9").text(item.stats.emmwritten);
		}
		if (!is_nopoll('readercol20')) {
			$(uid + " td.readercol20").html(item.status + "<BR>" + item.ip);
		}
		if (!is_nopoll('readercol10')) {
			$(uid + " td.readercol10").text(item.stats.emmskipped);
		}
		if (!is_nopoll('readercol11')) {
			$(uid + " td.readercol11").text(item.stats.emmblocked);
		}
		if (!is_nopoll('readercol12')) {
			$(uid + " td.readercol12").text(item.stats.lbweight);
		}
		if (!is_nopoll('readercol2')) {
			if (data.oscam.piconenabled == "1" && item.protoicon) {
				$(uid + " td.readercol2").html('<img class="protoicon" title="Protocol ' + item.protocol + ' ' +
					 item.prototitle + '" alt="IC_' + item.protoicon + '" src="image?i=IC_' + item.protoicon + '">');
			} else {
				$(uid + " td.readercol2").text(item.protocol);
			}

			$(uid + " td.readercol2")
				.data('sort-value', item.protosort);
		}

		if (typeof custompoll == 'function') {
			custompoll(item);
		}
	});

	// update user totals + ECM
	updateTotals(data);

	// update footer
	updateFooter(data);

}

/*
 *	LiveLog Functions: format the debuglevel switcher
 */
function setDebuglevel(debug, maxdebug) {
	var cs_dblevel = parseInt(debug);
	var maxlevel = parseInt(maxdebug);
	if (lastdebuglevel != cs_dblevel) {
		var lvl = 0;
		$("#debugfrom").text(' Switch Debug from ' + cs_dblevel + ' to ');
		for (var i = 0; i < maxlevel; i++) {
			lvl = 1 << i;
			if (cs_dblevel & lvl) {
				$("#debug" + lvl).attr('sendval', cs_dblevel - lvl);
			} else {
				$("#debug" + lvl).attr('sendval', cs_dblevel + lvl);
			}
			$("#debug" + lvl).attr('class', (cs_dblevel & lvl) ? 'debugls' : 'debugl');
		}
		lastdebuglevel = cs_dblevel;
	}
}

/*
 * Livelog Functions: get filter color
 */
function getLogColor(text) {

	if (nostorage) {
		return null;
	}

	for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
		var pattern = localStorage['regex' + i];
		var color = localStorage['color' + i];
		var fcolor = localStorage['fcolor' + i];
		var hidden = localStorage['hidden' + i];
		var beep = localStorage['beep' + i];
		var regex = new RegExp(pattern);
		if (pattern && (pattern != '') && (regex.exec(text))) {
			return {
				color: color,
				fcolor: fcolor,
				hidden: hidden,
				beep: beep
			}
		}
	}
	return null;
}

/*
 * Livelog Functions: get whitelist state
 */
function isWhitelisted(text) {

	if (nostorage) {
		return 1;
	}

	var numwhite = 0;
	for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
		numwhite += parseInt(localStorage['whitelisted' + i]);
	}
	if (numwhite > 0) {
		for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
			var whitelisted = localStorage['whitelisted' + i];
			var pattern = localStorage['regex' + i];
			var regex = new RegExp(pattern);
			if (pattern && (pattern != '') && (whitelisted == '1') && (regex.exec(text))) {
				return 1;
			}
		}
		return 0;
	} else {
		return 1;
	}
}

/*
 * LiveLog Functions: manage the delivered data / loglines
 */
function updateLogpage(data) {

	lockpoll = 1;

	if (data.oscam.debug) {
		setDebuglevel(data.oscam.debug, data.oscam.maxdebug);
	}
	if (data.oscam.logdisabled) {
		stoppoll = 1;
		$("#livelogdata").append('<li>Log is disabled</li>\n');
	}

	$.each(data.oscam.lines, function (i, item) {

		if (isWhitelisted(Base64.decode(item.line))) {
			var newcolor = getLogColor(Base64.decode(item.line));
			var newline = $('<li class="' + decodeURIComponent(item.usr) + '">' + Base64.decode(item.line) + '</li>\n');
			var hiddenline = 0;
			if (newcolor) {
				if (newcolor.hidden != '1') {
					if (newcolor.color && newcolor.color != '') {
						newline.css('background-color', newcolor.color);
					}
					if (newcolor.fcolor && newcolor.fcolor != '') {
						newline.css('color', newcolor.fcolor);
					}
					$("#livelogdata").append(newline);
					if (newcolor.beep == 1) {
						beep(50, 4, 1000, 0.2);
					}
				} else {
					hiddenline = 1;
				}
			} else {
				$("#livelogdata").append(newline);
			}

			if (!hiddenline) {
				if ($("#livelog:hover").length) {
					$('#livelog').stop(true);
				} else {
					$("#livelog").scrollTop($("#livelog").prop("scrollHeight"));
				}
			}
		}
		parameters = "?lastid=" + item.id;
	});

	var len = $("#livelogdata li").length;
	if (len > maxloglines) {
		$("#livelogdata li").slice(0, len - maxloglines).remove();
	}

	// update footer
	updateFooter(data);

	lockpoll = 0;

}

/*
 * Statuspage Functions: JQuery Extensions
 */
$.fn.toHtmlString = function () {
	return $('<td></td>').html($(this).clone()).html();
};

/*
 *	Statuspage Functions: Generate a Bar for Barchart
 */
function generateBar(value) {
	var bar = $('<div class="bar"/>');
	var maxheight = 75; //$( "#graph" ).height() -15;
	var numval = parseInt(value);
	numval = Math.floor(numval / 30);
	if (numval >= maxheight) {
		bar.css('background-color', '#FF0000');
		numval = maxheight;
	}
	bar.css('height', numval + 'px');
	return bar;
}

/*
 *	Statuspage Functions: Add/Remove Subheadline
 */
function addremoveSubheadline(remove, data, container, subheadline, type) {

	if (remove == 1 && $("#" + subheadline).length) {
		$("#" + subheadline)
			.fadeOut('slow')
			.remove();
		$(".status tbody:empty").hide();
	}

	if (remove == 0 && !$("#" + subheadline).length) {
		$(container).removeAttr('style');
		var strheadline = '<TR id="' + subheadline + '"><TD CLASS="subheadline" COLSPAN="12">';
		if (type == 'c') {
			if (data.oscam.status.ucac != '') { //hide idle clients
				strheadline += '<P id="chead">Clients <span id="ucs">' + data.oscam.status.ucs + '</span>/<span id="uca">' + data.oscam.status.uca + '</span> (<span id="ucac">' + data.oscam.status.ucac + '</span> with ECM within last <span id="cfgh">' + data.oscam.status.cfgh + '</span> seconds)</P>'
			} else {
				strheadline += '<P id="chead">Clients <span id="ucs">' + data.oscam.status.ucs + '</span>/<span id="uca">' + data.oscam.status.uca + '</span></P>'
			}
			strheadline += '<DIV><input type="button" onclick="window.location.href = \'status.html?hideidle=5\';" value="Show Hidden" title="Show Hidden User">';
			strheadline += '<input type="button" onclick="window.location.href = \'status.html?hideidle=0\';" value="Show Idle" title="Show Idle User">';
			strheadline += '<input type="button" onclick="window.location.href = \'status.html?hideidle=1\';" value="Hide Idle" title="Hide Idle User">';
		} else if (type == 'm') {
			strheadline += '<P id="shead">Server <span id="scs">' + data.oscam.status.scs + '</span>/<span id="sca">' + data.oscam.status.sca + '</span> & Monitors <span id="mcs">' + data.oscam.status.mcs + '</span>/<span id="mca">' + data.oscam.status.mca + '</span></P>'
			strheadline += '<DIV><input type="button" onclick="window.location.href = \'status.html?hideidle=2\';" value="Show Hidden" title="Show Hidden Server & Monitors">';
		}
		strheadline += '</DIV></TD></TR>';
		var headline = $(strheadline);
		headline.hide();
		$(container).append(headline);
		headline.fadeIn('slow');
	}
}

function fillStatus(list, type, data) {
	list.forEach(function(key) {
		$("#" + key).text(data.oscam[type][key]);
	});
}


/*
 *	Statuspage Functions: Update Totals cacheEx
 */
function updateCacheextotals(data) {
	fillStatus(["total_cachexpush", "total_cachexgot", "rel_cachexhit", "total_cachesize"], "totals", data);
}

/*
 *	Statuspage Functions: Update Totals User + Totals Reader + ECM + EMM
 */
function updateTotals(data) {
	fillStatus(["total_users", "total_active", "total_connected", "total_online", "total_disabled", "total_expired", "total_readers", "total_active_readers", "total_connected_readers", "total_disabled_readers", "total_cwok", "total_cwok_readers", "rel_cwok", "rel_cwok_readers", "total_cwcache", "rel_cwcache", "total_cwnok", "total_cwnok_readers", "rel_cwnok", "rel_cwnok_readers", "total_cwtout", "total_cwtout_readers", "rel_cwtout", "rel_cwtout_readers", "total_cwign", "total_ecm_min", "total_cw", "total_cwpos", "total_cwpos_readers", "rel_cwpos", "rel_cwpos_readers", "total_cwneg", "total_cwneg_readers", "rel_cwneg", "rel_cwneg_readers", "total_emok", "rel_emok", "total_emnok", "rel_emnok", "total_em", "total_elenr", "total_eheadr", "total_emmerroruk_readers", "total_emmerrorg_readers", "total_emmerrors_readers", "total_emmerroruq_readers", "total_emmwrittenuk_readers", "total_emmwritteng_readers", "total_emmwrittens_readers", "total_emmwrittenuq_readers", "total_emmskippeduk_readers", "total_emmskippedg_readers", "total_emmskippeds_readers", "total_emmskippeduq_readers", "total_emmblockeduk_readers", "total_emmblockedg_readers", "total_emmblockeds_readers", "total_emmblockeduq_readers", "total_sum_all_readers_ecm", "total_sum_all_readers_emm"], "totals", data);
}

/*
 *	Statuspage Functions: Update Totals Sysinfo
 */
var first_run = 1;

function updateSysinfo(data) {
	fillStatus(["mem_cur_total", "mem_cur_free", "mem_cur_used", "mem_cur_buff", "mem_cur_cached", "mem_cur_totalsw", "mem_cur_freesw", "mem_cur_usedsw", "mem_cur_shared", "oscam_vmsize", "oscam_rsssize", "server_procs", "cpu_load_0", "cpu_load_1", "cpu_load_2"], "sysinfo", data);
	$("#mem_cur_freem").attr('title', 'max Free: ' + data.oscam.sysinfo.mem_cur_freem + ' \n(incl. Buffer & Cached)');
	if (!first_run) {
		fillStatus(["oscam_refresh", "oscam_cpu_user", "oscam_cpu_sys", "oscam_cpu_sum"], "sysinfo", data);
	}
	first_run = 0;
}

/*
 *	Statuspage Functions: Update Page
 */
function updateStatuspage(data) {

	var updatedclients = "";
	// update status lines
	$.each(data.oscam.status.client, function (i, item) {
		var newrow;

		//add ID's for type c and m to list of existing elements. We need this to delete all not longer existing
		updatedclients += item.thid + ",";

		var uid = "#" + item.thid;
		poll_excluded = ($(uid).attr('nopoll') != undefined) ? $(uid).attr('nopoll') : '';

		if (!$(uid).length && 'rpcxm'.indexOf(item.type) > (-1)) {
			//build new row
			var rowcontent = '<TR ID="' + item.thid + '"><TD CLASS="statuscol0"/><TD CLASS="statuscol1"/><TD CLASS="statuscol4"/>';
			rowcontent += '<TD CLASS="statuscol5"/><TD CLASS="statuscol7"/><TD CLASS="statuscol8"/><TD CLASS="statuscol9"/>';
			rowcontent += '<TD CLASS="statuscol12"/><TD CLASS="statuscol13"/><TD CLASS="statuscol14"/><TD CLASS="statuscol15"/>';
			rowcontent += '<TD CLASS="statuscol16"/></TR>';
			newrow = $(rowcontent);
			newrow.hide();
			// if we have no clients we have to add the headline first

			// append new clientrow to table
			var container = '';
			if ('hms'.indexOf(item.type) > (-1)) {
				container = '#tbodys';
				if (item.type == 'm') {
					if (!$("#Serverheadline").length) {
						addremoveSubheadline(0, data, container, "Serverheadline", item.type);
					} else if (!$("#mca").length) {
						$("#shead").append(' & Monitors <span id="mcs">' + data.oscam.status.mcs + '</span>/<span id="mca">' + data.oscam.status.mca + '</span>');
					}
				}
			} else if ('px'.indexOf(item.type) > (-1)) {
				container = '#tbodyp';
			} else {
				container = '#tbody' + item.type;
				if (!$("#Userheadline").length && item.type == 'c') {
					addremoveSubheadline(0, data, container, "Userheadline", item.type);
				}
			}
			$(container).append(newrow);

			var name1, name2, name3, kill1, kill2, kill3, edit1;
			switch (item.type) {
			case 'c':
			case 'm':
				name1 = 'User';
				name2 = item.name_enc;
				kill1 = '" href="status.html?action=kill&threadid=' + item.thid.substring(3, item.thid.length);
				kill2 = 'Kill'
				kill3 = 'ICKIL';
				edit1 = 'user_edit.html?user=';
				break;
			case 'r':
			case 'p':
			case 'x':
				name1 = (item.type == 'r') ? 'Reader' : 'Proxy';
				name2 = item.rname_enc;
				kill1 = '" href="status.html?action=restart&label=' + name2;
				kill2 = 'Restart';
				kill3 = 'ICRES';
				edit1 = 'readerconfig.html?label=';
				break;
			}
			name3 = decodeURIComponent(name2);

			if (!is_nopoll('statuscol0')) {
				$(uid + " > td.statuscol0").append('<a title="Hide ' +
					name1 + ': ' + name3 + (item.desc ? '\n' + item.desc.replace('&#13;', '') : '') +
					'" href="status.html?hide=' +
					item.thid.substring(3, item.thid.length) +
					'"><img class="icon" alt="Hide"' +
					'" src="image?i=ICHID">');
			}

			if (!is_nopoll('statuscol1')) {
				$(uid + " > td.statuscol1").append('<a title="' + kill2 + ' ' +
					name1 + ': ' + name3 + (item.desc ? '\n' + item.desc.replace('&#13;', '') : '') +
					kill1 + '"><img class="icon" alt="' + kill2 +
					'" src="image?i=' + kill3 + '">');
			}

			if (!is_nopoll('statuscol4')) {
				if (data.oscam.piconenabled == "1" && !item.upicmissing) {
					$(uid + " > td.statuscol4").append('<a href="' + edit1 + name2 + '"><img class="statususericon" title="Edit ' +
						name1 + ': ' + name3 + (item.desc ? '\n' + item.desc.replace('&#13;', '') : '') + '" src="image?i=IC_' + name2 + '"></a>');
				} else {
					$(uid + " > td.statuscol4").append('<a href="' + edit1 + name2 + '" title="Edit ' + name1 + ': ' +
						name3 + (item.desc ? '\n' + item.desc.replace('&#13;', '') : '') + '\n' + item.upicmissing + '">' + name3 + '</a>');
				}
			}

			if (!is_nopoll('statuscol13')) {
				$(uid + " > td.statuscol13").append('<A HREF="files.html?file=' + data.oscam.srvidfile + '" TITLE="' + item.request + '"/>');
			}

			if (!is_nopoll('statuscol9')) {
				if (data.oscam.piconenabled == "1" && item.protoicon) {
					$(uid + " > td.statuscol9").append('<img class="protoicon" title="Protocol ' + item.protocol + ' ' +
						item.protocolext + '" alt="IC_' + item.protoicon + '" src="image?i=IC_' + item.protoicon + '">');
				} else {
					$(uid + " > td.statuscol9").attr('title', item.protocolext).text(item.protocol);
				}
			}
		}

		$(uid).attr('class', item.type).data('ecmhistory', item.request.ecmhistory).removeAttr('style');

		// fix for anonymous newcamd-clients
		if ($(uid + " > td.statuscol4").text().match('anonymous')) {
			if (!is_nopoll('statuscol9')) {
				if (data.oscam.piconenabled == "1" && item.protoicon) {
					$(uid + " > td.statuscol9").html('<img class="protoicon" title="Protocol ' + item.protocol + ' ' +
						item.protocolext + '" alt="IC_' + item.protoicon + '" src="image?i=IC_' + item.protoicon + '">');
				} else {
					$(uid + " > td.statuscol9").attr('title', item.protocolext).text(item.protocol);
				}
			}

			if (!is_nopoll('statuscol4')) {
				if (data.oscam.piconenabled == "1" && !item.upicmissing) {
					$(uid + " > td.statuscol4").html('<a href="user_edit.html?user=' + item.name_enc +
						'"><img class="statususericon" title="Edit User: ' + decodeURIComponent(item.name_enc) + item.desc +
						'" src="image?i=IC_' + item.name_enc + '"></a>');
				} else {
					$(uid + " > td.statuscol4").html('<a href="user_edit.html?user=' + item.name_enc + '" title="Edit User: ' +
						decodeURIComponent(item.name_enc) + item.desc + item.upicmissing + '">' + decodeURIComponent(item.name_enc) + '</a>');
				}
			}
		}

		if (!is_nopoll('statuscol5')) {
			switch (item.au) {
			case '0':
				$(uid + " > td.statuscol5").text('OFF').attr('class', 'statuscol5 statuscol5OFF');
				break;
			case '-1':
				$(uid + " > td.statuscol5").html('<a class="tooltip" href="#">ON<span>' + item.aufmt + '</span></a>').attr('class', 'statuscol5 statuscol5ON');
				break;
			default:
				$(uid + " > td.statuscol5").html('<a class="tooltip" href="#">ACTIVE<span>' + item.aufmt + '</span></a>').attr('class', 'statuscol5 statuscol5ACTIVE');
				break;
			}
		}

		if (!is_nopoll('statuscol4')) {
			$(uid + " > td.statuscol4").attr('title', decodeURIComponent(item.type == 'c' ? item.name_enc : item.rname_enc) + (item.desc ? '\n' + item.desc.replace('&#13;', '') : ''));
		}
		if (!is_nopoll('statuscol7')) {
			$(uid + " > td.statuscol7").text(item.connection.ip);
		}
		if (!is_nopoll('statuscol8')) {
			$(uid + " > td.statuscol8").text(item.connection.port);
		}
		if (!is_nopoll('statuscol9')) {
			$(uid + " > td.statuscol9").attr('title', item.protocolext);
		}
		if (!is_nopoll('statuscol12')) {
			$(uid + " > td.statuscol12").text(item.request.srvid + ':' + item.request.caid + '@' + item.request.provid);
		}

		if (!is_nopoll('statuscol13')) {
			var newimage;

			if (data.oscam.piconenabled == '1' && item.request.srvid != '0000' && item.request.picon) {

				// if we already have a picon within link
				if ($(uid + " > td.statuscol13 > a > img.statususericon").length) {
					// we compare the picon name and switch if different
					var image = $(uid + " > td.statuscol13 > a > img.statususericon");
					if (image.attr('src') != 'image?i=IC_' + item.request.picon) {
						// set title of link as tooltip
						$(uid + " > td.statuscol13 > a").attr('title', item.request.chname + item.request.chprovider);
						image.hide();
						image.attr('src', 'image?i=IC_' + item.request.picon);
						image.fadeIn('slow');
					}
				} else {
					// we have no image so we have to create one

					// if we have picon clear text
					$(uid + " > td.statuscol13").text('');

					// if we have no link we create one
					if (!$(uid + " > td.statuscol13 > a").length) {
						$(uid + " > td.statuscol13").append('<a href="files.html?file=' + data.oscam.srvidfile + '"/>');
					}
					// set title of link as tooltip
					$(uid + " > td.statuscol13 > a").attr('title', item.request.chname + item.request.chprovider);

					// just to be sure that class of image is set
					if ($(uid + " > td.statuscol13 > a > img").length) {
						$(uid + " > td.statuscol13 > a > img").attr('class', 'statususericon');
					}

					newimage = $('<img class="statususericon" src="image?i=IC_' + item.request.picon + '">');
					newimage.hide();
					$(uid + " > td.statuscol13 > a").append(newimage);
					newimage.fadeIn('slow');
				}

			} else {
				// picon is not delivered in JSON - we set the text of column
				if (item.request.chname && item.request.srvid != '0000') {
					$(uid + " > td.statuscol13").html('<a href="files.html?file=' + data.oscam.srvidfile + '"/>');
					$(uid + " > td.statuscol13 > a").html(item.request.chname + item.request.chprovider);
					$(uid + " > td.statuscol13 > a").attr('title', item.request.chname + item.request.chprovider);
				} else {
					$(uid + " > td.statuscol13").html('');
				}
			}
		}

		if (!is_nopoll('statuscol14')) {
			if ('hms'.indexOf(item.type) > (-1)) {
				$(uid + " > td.statuscol14").text('');
			} else {
				var value = item.type == 'c' ? (item.request.answered ? item.request.answered + ' (' + item.request.msvalue + ' ms)' : '') : item.request.lbvalue;
				if (data.oscam.lbdefined) {
					var label = item.rname_enc.replace('+%28cache%29', '');
					var name = item.type == 'c' ? item.request.answered.replace(' (cache)', '') : decodeURIComponent(label);
					if (!$(uid + " > td.statuscol14 > a").length) {
						$(uid + " > td.statuscol14")
							.text('')
							.append('<a href="readerstats.html?label=' + label + '&amp;show=0" TITLE="Show statistics for: ' + name + '">');
					} else {
						$(uid + " > td.statuscol14 > a")
							.attr('href','readerstats.html?label=' + label + '&show=0')
							.attr('title','Show statistics for: ' + name);
					}
					$(uid + " > td.statuscol14 > a").text(value);
				} else {
					$(uid + " > td.statuscol14").text(value);
				}
			}
		}

		if (!is_nopoll('statuscol15')) {
			if ($("#onlineidle").text() != 'Login*') {
				$(uid + " > td.statuscol15")
					.html(item.times.online.toHHMMSS() + '<br>' + item.times.idle.toHHMMSS())
					.attr('title', 'Login: ' + item.times.loginfmt);
			} else {
				$(uid + " > td.statuscol15")
					.html(item.times.loginfmt.substring(0, 8) + '<br>' + item.times.loginfmt.substring(10, 18))
					.attr('title', 'Online: ' + item.times.online.toHHMMSS() + '\nIDLE: ' + item.times.idle.toHHMMSS());
			}
		}

		if (!is_nopoll('statuscol16')) {
			var entitlement = '';

			switch (item.type) {
			case 'r':
				// entitlement for native cards

				var activeentitlements = item.connection.entitlements.length;
				if (activeentitlements > 0) {
					entitlement += '<br><a href="entitlements.html?label=' + item.rname_enc + '&hideexpired=1" class="tooltip">';
					entitlement += '(' + activeentitlements + ' entitlement' + ((activeentitlements != 1) ? 's)' : ')');
					entitlement += '<span>';
					$.each(item.connection.entitlements, function (i, obj) {
						entitlement += obj.caid + ':' + obj.provid + '<br>' + obj.exp + '<br><br>';
					});
					entitlement = entitlement.substring(0, entitlement.length - 4);
					entitlement += '</span></a>';
				} else {
					entitlement += '<br><a href="entitlements.html?label=';
					entitlement += item.rname_enc + '&hideexpired=1" class="tooltip1">(no entitlements)<span>No active entitlements found</span></a>';
				}
				break;

			case 'p':
				if (item.connection.entitlements.length > 0 && item.protocol.indexOf('cccam') > -1) {
					// cccam
					var entobj = item.connection.entitlements[0];
					entitlement += '<br><a href="entitlements.html?label=' + item.rname_enc + '" class="tooltip' + entobj.cccreshare + '">';
					entitlement += '(' + entobj.locals + ' of ' + entobj.cccount + ' card' + (entobj.cccount > 1 ? "s" : "") + ')';
					entitlement += '<span>card_count=' + entobj.cccount + '<br>';
					entitlement += 'hop1=' + entobj.ccchop1 + '<br>';
					entitlement += 'hop2=' + entobj.ccchop2 + '<br>';
					entitlement += 'hopx=' + entobj.ccchopx + '<br>';
					entitlement += 'currenthops=' + entobj.ccccurr + '<br><br>';
					entitlement += 'reshare0=' + entobj.cccres0 + '<br>';
					entitlement += 'reshare1=' + entobj.cccres1 + '<br>';
					entitlement += 'reshare2=' + entobj.cccres2 + '<br>';
					entitlement += 'resharex=' + entobj.cccresx + '</span></a>';
				}
				if (item.protocol.indexOf('gbox') > -1) {
					// TO DO gbox
					var $html = $(uid + " > td.statuscol16").toHtmlString();
					if ($html != undefined) {
						entitlement = $html.substring($html.indexOf('<br>'), $html.indexOf('</a>'));
						if (entitlement) entitlement += '</a>';
					}
				}
				break;
			}

			$(uid + " > td.statuscol16").empty().html(item.connection.status + entitlement).attr('class', 'statuscol16 statuscol16' + item.connection.status);
		}

		if (newrow) {
			newrow.fadeIn("slow");
		}

		if (typeof custompoll == 'function') {
			custompoll(item);
		}

	});

	//remove non existing elements
	$("tr.c, tr.m, tr.r, tr.p, tr.h").each(function () {
		if (updatedclients.indexOf($(this).attr('id')) == -1) {
			$(this).fadeOut('slow').remove();
		}
	});

	// if we have no clients left we remove the headline
	if (!$("tr.c").length && data.oscam.status.uca == '0') {
		addremoveSubheadline(1, '', '', "Userheadline", 'c');
	}
	// if we have no servers/monitors left we remove the headline
	if (!$("tr.m").length && data.oscam.status.mca == '0') {
		if ($("#mca").length) {
			$("#shead").replaceWith('<P id="shead">Server <span id="scs">' + data.oscam.status.scs + '</span>/<span id="sca">' + data.oscam.status.sca + '</span></P>');
		}
		if (!$("tr.s").length && !$("tr.h").length && data.oscam.status.sch == '0') {
			addremoveSubheadline(1, '', '', "Serverheadline", 'm');
		}
	}

	//update client-headline
	if (data.oscam.status.uca != '0') {
		if (!$("#Userheadline").length) {
			addremoveSubheadline(0, data, "#tbodyc", "Userheadline", "c");
		} else {
			$("#ucs").text(data.oscam.status.ucs);
			$("#uca").text(data.oscam.status.uca);
			if (data.oscam.status.ucac != '0') $("#ucac").text(data.oscam.status.ucac);
		}
	}
	//update server/monitor-headline
	if (data.oscam.status.mca != '0' && $("#mcs")) {
		$("#mcs").text(data.oscam.status.mcs);
		$("#mca").text(data.oscam.status.mca);
	}

	//update reader-headline
	if(data.oscam.status.rco != '0') {
		var rcon = (data.oscam.status.rca - data.oscam.status.rco);
		if($("#rco").length) {
			$("#rcc").text(data.oscam.status.rcc);
			$("#rca").text(data.oscam.status.rca);
			$("#rco").text(rcon);
		} else {
			$("#rhead").html('Readers <span id="rcc">' + data.oscam.status.rcc + '</span>/' + data.oscam.status.rca + ' (<span id="rco">' + rcon + '</span> of ' + data.oscam.status.rca + ' CARDOK)');
		}
	} else if($("#rco").length) {
		$("#rhead").html('Readers <span id="rcc">' + data.oscam.status.rcc + '</span>/' + data.oscam.status.rca);
	} else {
		$("#rcc").text(data.oscam.status.rcc);
		$("#rca").text(data.oscam.status.rca);
	}

	//update proxy-headline
	if(data.oscam.status.pco != '0') {
		var pcon = (data.oscam.status.pca - data.oscam.status.pco);
		if($("#pco").length) {
			$("#pcc").text(data.oscam.status.pcc);
			$("#pca").text(data.oscam.status.pca);
			$("#pco").text(pcon);
		} else {
			$("#phead").html('Proxies <span id="pcc">' + data.oscam.status.pcc + '</span>/' + data.oscam.status.pca + ' (<span id="pco">' + pcon + '</span> of ' + data.oscam.status.pca + ' online)');
		}
	} else if($("#pco").length) {
		$("#phead").html('Proxies <span id="pcc">' + data.oscam.status.pcc + '</span>/' + data.oscam.status.pca);
	} else {
		$("#pcc").text(data.oscam.status.pcc);
		$("#pca").text(data.oscam.status.pca);
	}

	// update footer
	updateFooter(data);

	// sysinfos
	if ($("#mem_cur_total").length) updateSysinfo(data);

	// user + ecm totals
	if ($("#total_users").length) updateTotals(data);

	// cachex
	if ($("#total_cachexpush").length) updateCacheextotals(data);

}


/*
 *	General fork into page refresh functions
 */
function updatePage(data) {

	// show heartbeat
	if ($("input.pintervall").length && $("input.pintervall").css("background-color") != $("#picolor").css("background-color")) {
		var orgstyle = $("input.pintervall").css("background-color");
		$("input.pintervall").css("background-color", $("#picolor").css("background-color"));
	}

	switch (page) {
	case 'status':
		updateStatuspage(data);
		break;
	case 'user':
		updateUserpage(data);
		break;
	case 'reader':
		updateReaderpage(data);
		break;
	case 'livelog':
		updateLogpage(data);
		break;
	case 'cacheex':
		updateCacheextotals(data);
		break;
	default:
		break;
	}

	// hide heartbeat
	if ($("input.pintervall").length && $("input.pintervall").css("background-color") == $("#picolor").css("background-color")) {
		setTimeout(function () {
			$("input.pintervall").css("background-color", orgstyle);
		}, 300);
	}

	if (typeof afterpoll == 'function') {
		afterpoll();
	}
}

function setPollerr(error) {
	if (error && !$("#pollerr").length) {
		$("body").append('<div id="pollerr" style="top:5px;left:5px;background-color:red;color:yellow;">POLLERR</div>');
	} else {
		if ($("#pollerr").length) {
			$("#pollerr").fadeOut('slow').remove();
		}
	}
}

/*
 * General Polling
 */
var lockpoll = 0;
var timer_ID;

function waitForMsg() {

	if (typeof pollrefresh == 'undefined') return;

	if (lockpoll > 0) {
		/* assumed that previous poll is not finnished yet we not
		call new data and just set the next intervall */
		clearTimeout(timer_ID);
		timer_ID = setTimeout("waitForMsg()", pollintervall);
		return;
	}

	$.ajax({
		type: "GET",
		url: jsonurl + parameters,
		dataType: "JSON",
		async: true,
		cache: false,
		success: function (data) {
			setPollerr(0);
			if ((!pollrefresh || polling ) && page != 'livelog') return;
			updatePage(data);
			if (!stoppoll) {
				clearTimeout(timer_ID);
				timer_ID = setTimeout("waitForMsg()", pollintervall);
			}
		},
		error: function (XMLHttpRequest, textStatus, errorThrown) {
			clearTimeout(timer_ID);
			timer_ID = setTimeout("waitForMsg()", 15000);
			setPollerr(1);
		}
	});
}

/*
 * General: Set Poll Interval
 */
function setPollrefresh() {
	// Set pollintervall, if pollrefresh set to 0 disable polling
	if (pollrefresh) {
		pollintervall = parseInt(pollrefresh) * 1000;
		if (pollintervall > 99000) pollintervall = 99000;
		if (!nostorage) {
			if (sessionStorage.pollintervall) pollintervall = sessionStorage.pollintervall;
			else sessionStorage.pollintervall = pollintervall;
			if (sessionStorage.polling == 1) polling = 1;
		}
	}
}

// static for paranoid Browsers
var nostorage = 0;

/*
 * General: Start Polling
 */
$(document).ready(function () {

	try {
		if (!localStorage) {
			nostorage = 1;
			// remove whole filter block - makes no sense
			// without saving
			$('#regex').remove();
		}
	} catch(err){
		nostorage = 1;
		$('#regex').remove();
	}

	// set default to nothing excluded
	poll_excluded = '';

	// help wiki links
	if (typeof oscamconf != "undefined") {
		var wikihref = "https://git.streamboard.tv/common/oscam/-/wikis/pages/configuration/oscam." + oscamconf + "#";
		$("form table a").click(function () {
			if (!$(this).attr("href") && !$(this).attr("name")) {
				if ($(this).data('p')) {
					var parm = $(this).data('p');
				} else {
					var parm = $(this).parent().next().find("input,select,textarea").attr('name');
				}
				window.open(wikihref + parm);
			}
		});
	}

	// Title
	var pagename = (typeof page != 'undefined' ? page : $(location).attr('pathname').replace(/.*\/|\.[^.]*$/g, ''));
	$(document).attr('title', $(document).attr('title') + ' (' + pagename[0].toUpperCase() + pagename.slice(1) + ')');

	if (typeof page != 'undefined') {

		switch (page) {

		case 'livelog':

			var saved_regex = localStorage.MAX_SEARCH_PATTERN;
			MAX_SEARCH_PATTERN = parseInt(saved_regex ? saved_regex : MAX_SEARCH_PATTERN);
			$('<LI style="display:none;"><span class="colorPicker_def_color"></span><span class="colorPicker_def_fcolor"></span></LI>').insertBefore(".regexdata_save");

			var beep_disabled = ' disabled="disabled" title="Not supported by your browser"';
			var contextClass = (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext);
			if (contextClass) { beep_disabled = ''; }

			for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {

				var prefix = "0";
				if ( i > 9 ) { prefix = ""; }

				$('<LI class="regex" id="regexrow' + i + '">Search' + prefix + i + ': <input type="text" name="regex' + i + '" class="regexinput" ID="regex' + i + '" value=""> Found only: <input type="checkbox" id="whitelisted' + i + '"><label></label> Hide: <input type="checkbox" id="hidden' + i + '"><label></label> Back Color: <input size="7" maxlength="7" type="text" name="color' + i + '" class="colorinput" ID="color' + i + '" value=""> Color: <input size="7" maxlength="7" type="text" name="fcolor' + i + '" class="colorinput" ID="fcolor' + i + '" value=""> Beep: <input type="checkbox" id="beep' + i + '"' + beep_disabled +'><label></label></LI>').insertBefore(".regexdata_save");
			}

			if (!nostorage) {
				for (var i = 1; i < MAX_SEARCH_PATTERN + 1; i++) {
					var pattern = localStorage['regex' + i];
					var color = localStorage['color' + i];
					var fcolor = localStorage['fcolor' + i];
					$('#regex' + i).val(pattern ? pattern : '');
					$('#color' + i).val(color ? color : $('.colorPicker_def_color').css('color'));
					$('#fcolor' + i).val(fcolor ? fcolor : $('.colorPicker_def_fcolor').css('color'));
					$('#color' + i).colorPicker();
					$('#fcolor' + i).colorPicker();
					$('#whitelisted' + i).prop('checked', localStorage['whitelisted' + i] == '1' ? true : false);
					$('#hidden' + i).prop('checked', localStorage['hidden' + i] == '1' ? true : false);
					$('#beep' + i).prop('checked', localStorage['beep' + i] == '1' ? true : false);
				}
			}
			waitForMsg();

			break;

		case 'status':

			$(".status tbody:empty").hide();
			$("#chart").hide();
			if (!nostorage) {
				if (localStorage.loi == 'Login*') {
					$("#onlineidle")
						.text('Login*')
						.css('cursor','pointer')
						.attr('title', 'Online & Idle info (click to switch)');
				} else {
					$("#onlineidle")
						.text('Online & Idle*')
						.css('cursor','pointer')
						.attr('title', 'Login info (click to switch)');
				}
			}
			break;

		default:

			break;
		}

		// if pollrefresh set to 0 hide pollselector
		setPollrefresh();
		if (pollrefresh) {
			if (polling) {
				$(":text[name='pintervall']").val('--');
				$('#polling').attr('class','pollingdisabled');
				$('#inc, #dec').attr('disabled','disabled');
			} else {
				$(":text[name='pintervall']").val(pollintervall / 1000);
				$('#polling').attr('class','pollingenabled');
				$('#inc, #dec').removeAttr('disabled');
				waitForMsg();
			}
			$("#poll").show();
		}
	}
});

function decodeVideoguardEMM(text, target, addHideButton) {

	text = text.trim();

	var bytes = text.replace(/[^A-Fa-f0-9]/g, "").toUpperCase().match(/.{1,2}/g) || [];
	var html = '';

	if (addHideButton) {
		html += '<p><input type="button" value="Hide" title="Hide" onclick="$(\'' + target + '\').css(\'display\', \'none\');" /></p><br/>';
	}

  var AddTextType = {"data":"Data", "length":"Length", "type":"Type", "emmType":"EMM-Type", "encryptionType":"Encryption Type",
  	"keyIndex":"Key-Index", "keyIndex2":"Key-Index2", "fixedValue":"Fixed Value", "pairingDevice":"Pairing Device", "date":"Date",
  	"checksum":"Checksum", "emmStartMarker":"EMM Marker", "cardSerial":"Serial Number (Smartcard)",
  	"boxSerial":"Serial Number (Receiver)", "emmEndMarker":"Sub-EMM End", "rest":"rest ????",
  	"cardEmmLength":"Card EMM Length", "cardNanoLength":"Card Nano Length", "irdEmmLength":"IRD EMM Length",
  	"filterSectionLength":"Filter Section Length", "irdNanoLength":"IRD Nano Length", "cardNanoType":"Card Nano Type",
  	"irdNanoType":"IRD Nano Type", "filterNanoType":"Filter Nano Type", "cardGroupSerial":"Serial Number (Card Group)",
  	"mpegSectionLength":"EMM Length", "irdEmmChecksum":"IRD EMM Checksum", "pairingdeviceCount":"Pairing Device Count"};

	function addText(count, color, text, parm) {

		html += '<font style="color: ' + color + '"><b>';

		var ret = '';
		for (var i = 0; i < count; i++) {
			var v = bytes.shift();
			if (typeof v === 'undefined') {
				v = 'XX';
			}
			html += v + ' ';
			ret += v;
			if (((i + 1) % 16) == 0) {
				html += '<br/>';
			}
		}

		switch (text) {
			case AddTextType.emmStartMarker:
				if(ret.substring(2) == '00') {
					text += " (cccam)";
				}
				break;

			case AddTextType.mpegSectionLength:
				var len = ((parseInt(parm, 16) << 8) + parseInt(ret, 16)) & 0x0FFF;
				text += ' - <b>' + len + '</b>';

				if (bytes.length >= len) {
					text += ' - <font style="color:#009900"><b>OK (' + bytes.length + ')</b></font>';
				} else {
					text += ' - <font style="color:#F00000"><b>FAIL (' + bytes.length + ')</b></font>';
				}
				ret = len;
				break;

			case AddTextType.length:
			case AddTextType.cardEmmLength:
			case AddTextType.cardNanoLength:
			case AddTextType.irdEmmLength:
			case AddTextType.filterSectionLength:
			case AddTextType.irdNanoLength:

				var len = parseInt(ret, 16);
				text += ' - <b>' + len + '</b>';

				if (bytes.length >= len) {
					text += ' - <font style="color:#009900"><b>OK (' + bytes.length + ')</b></font>';
				} else {
					text += ' - <font style="color:#F00000"><b>FAIL (' + bytes.length + ')</b></font>';
				}
				ret = len;
				break;
			case AddTextType.type:

				var type = parseInt(ret, 16) & 0xC0;
				var subEmmCount = ((parseInt(ret, 16) & 0x30) >> 16) + 1;

				if (type == 0x40) {
					text += ' - <b>unique</b> EMM For Smartcard';
				}
				else if (type == 0xC0) {
					text += ' - <b>unique</b> EMM For Receiver/CAM';
				}
				else if (type == 0x80) {
					text += ' - <b>shared</b> EMM For Smartcard';
				}
				else {
					text += ' - <b>global</b> EMM';
				}

				text += ' (' + subEmmCount + ' Sub EMMs)';

				break;

			case AddTextType.emmType:
				switch (ret) {
					case '02':
						text += ' - <b>Default</b>';
						break;
					case '07':
						text += ' - <b>With Filter Nanos</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}
				break;

			case AddTextType.encryptionType:
				switch (ret) {
					case '44':
						text += ' - <b>User-Encryption</b>';
						break;
					case '60':
						text += ' - <b>System-Encryption</b>';
						break;
					case '40':
						text += ' - <b>System-Encryption</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}

				break;

			case AddTextType.cardNanoType:
				switch (ret) {
					case '01':
						text += ' - <b>Set date</b>';
						break;
					case '90':
						text += ' - <b>Encrypted Nano</b>';
						break;
					case '41':
						text += ' - <b>Add a ChID</b>';
						break;
					case '42':
						text += ' - <b>Delete a ChID</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}
				break;

			case AddTextType.irdNanoType:
				switch (ret) {
					case '02':
						text += ' - <b>Set Date/Time</b>';
						break;
					case '07':
					case '08':
						text += ' - <b>Download Firmware</b>';
						break;
					case '2B':
						text += ' - <b>Pairing Data</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}
				break;

			case AddTextType.filterNanoType:
				switch (ret) {
					case '30':
						text += ' - <b>Always Valid</b>';
						break;
					case '31':
						text += ' - <b>Card Address</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}
				break;

			case AddTextType.keyIndex:

				if (!isV14V15) {
					text += ' - <b>' + ret + '</b>';
				}

				switch (ret) {
					case '01':
						text += ' - <b>V14</b>';
						break;
					case '02':
						text += ' - <b>V15</b>';
						break;
					default:
						text += ' - <b>unknown</b>';
						break;
				}

				break;
			case AddTextType.keyIndex2:
				text += ' - <b>unknown</b>';
				break;
			case AddTextType.fixedValue:
				if (ret == parm) {
					text += ' - <font style="color:#009900"><b>OK</b></font>';
				} else {
					text += ' - <font style="color:#F00000"><b>FAIL (' + parm + ')</b></font>';
				}
				break;
			case AddTextType.pairingDevice:
				switch (ret) {
					default: text += ' - <b>Device ' + ret + '</b>';
					break;
				}
				break;
			case AddTextType.date:
				var b = ret.replace(/[^A-Fa-f0-9]/g, "").match(/.{1,2}/g) || [];

				var bin = parseInt(b[2] + b[3], 16);
				var time = {};
				time.s = ((bin & parseInt('11111', 2)) * 2);
				bin = bin >>> 5;
				time.m = (bin & parseInt('111111', 2));
				bin = bin >>> 6;
				time.h = (bin & parseInt('11111', 2));
				bin = bin >>> 5;

				bin = parseInt(b[0] + b[1], 16);
				var date = {};
				date.d = (bin & parseInt('11111111', 2));
				bin = bin >>> 8;
				date.m = (bin & parseInt('11111111', 2));
				bin = bin >>> 8;

				date.y = parseInt(date.m / 12) + 2004;
				date.m -= (((date.y - 2004) * 12) - 1);

				text += ' - <b>' + date.d + '.' + date.m + '.' + date.y + '</b>';
				text += ' <b>' + time.h + ':' + time.m + ':' + time.s + ' UTC</b>';
				break;
			case AddTextType.checksum:
			case AddTextType.irdEmmChecksum:
				var checksumData = parseInt(ret, 16);
				var checksum = 0x00;

				for(var i = 0; i < parm.length; i++) {
					checksum += parseInt(parm[i], 16);
					checksum &= 0xFF;
				}

				if (checksumData == checksum) {
					text += ' - <font style="color:#009900"><b>OK</b></font>';
				} else {
					text += ' - <font style="color:#F00000"><b>FAIL (' + checksum.toString(16).toUpperCase() + ')</b></font>';
				}
				break;
		}

		html += '</b></font> - ' + text + '<br/>';
		return ret;
	}

	function ReadSingleCardEMM() {
		var cardEmmLength = addText(1, '#00F', AddTextType.cardEmmLength);
		var remainingDataLength = cardEmmLength;

		while (remainingDataLength > 0 && bytes.length) {
			var cardNanoType = addText(1, '#008000', AddTextType.cardNanoType);

			var fixedSizeNanos = {
				"01": 0x04,
				"09": 0x03,
				"10": 0x02,
				"19": 0x01,
				"1E": 0x08,
				"24": 0x00,
				"25": 0x00,
				"27": 0x0D,
				"2B": 0x02,//0x03
				"2D": 0x04,
				"30": 0x00,
				"31": 0x04,//0x03
				"32": 0x03,
				"33": 0x23,
				"3D": 0x02,
				"3E": 0x00,
				"41": 0x05,//0x04
				"42": 0x02,
				"44": 0x04,
				"4E": 0x04,
				"7A": 0x02,

				"02": 0x01,
				"03": 0x03,
				"04": 0x00,
				"48": 0x00,
				"C0": 0x00,

			};

			if (fixedSizeNanos[cardNanoType] != undefined) {

				if (cardNanoType == "01") {
					addText(4, '#00A0A0', AddTextType.date);
				}
				else {
					addText(fixedSizeNanos[cardNanoType], '#000', AddTextType.data);
				}
				remainingDataLength -= fixedSizeNanos[cardNanoType] + 1;
			}
			else {
				var cardNanoLength = addText(1, '#00F', AddTextType.cardNanoLength);

				if (cardNanoType == "90") {
					var encryptionType = addText(1, '#b22222', AddTextType.encryptionType);
					switch (encryptionType) {
						case '40':
						case '44':
						case '60':
							addText(1, '#b22222', AddTextType.keyIndex);
							addText((cardNanoLength - 2), '#000', AddTextType.data);

							break;
						default:
							addText(1, '#b22222', AddTextType.keyIndex2);
							addText((cardNanoLength - 2), '#000', AddTextType.data);
							break;
					}
				}
				else {
					addText(cardNanoLength, '#000', AddTextType.data);
				}

				remainingDataLength -= cardNanoLength + 2;
			}

		}

	}

	function ReadIrdNano() {

	var irdNanoType = addText(1, '#008000', AddTextType.irdNanoType);

	var fixedSizeNanos = {
		"02": 0x04,
	};

	if (fixedSizeNanos[irdNanoType] != undefined) {

		if (irdNanoType == "02") {
			addText(4, '#00A0A0', AddTextType.date);
		}
		else {
			addText(fixedSizeNanos[cardNanoType], '#000', AddTextType.data);
		}
		return fixedSizeNanos[irdNanoType] + 1;
	}
	else {
		var irdNanoLength = addText(1, '#00F', AddTextType.irdNanoLength);

		switch (irdNanoType) {
			case '2B':
				addText(1, '#000', AddTextType.pairingdeviceCount);

				var remainingDataLengthNano = irdNanoLength - 1;
				while (remainingDataLengthNano > 0 && bytes.length) {
					var startLength = bytes.length;
					addText(1, '#E000E0', AddTextType.pairingDevice);
					addText(4, '#cc7000', AddTextType.boxSerial);
					ReadSingleCardEMM();
					remainingDataLengthNano -= startLength - bytes.length;
				}
				break;

			default:
				addText(irdNanoLength, '#000', AddTextType.data);
				break;
		}

		return irdNanoLength + 2;
	}
}

	var partOfLength = bytes[1];
	addText(2, '#000', AddTextType.emmStartMarker);
	addText(1, '#00F', AddTextType.mpegSectionLength, partOfLength);

	var filterByte = parseInt(addText(1, '#199a8d', AddTextType.type), 16);
	var type = filterByte & 0xC0;
	var subEmmCount = ((filterByte & 0x30) >> 16) + 1;

	if(partOfLength != 0) { // partOfLength == 0 for emms by cccam clients, these do not have the serials part
		for(var i = 0; i < subEmmCount; i++) {
 			if (type == 0x40) { // unique: card
				addText(4, '#cc7000', AddTextType.cardSerial);
			} else if (type == 0xC0) { // unique: receiver/cam
				addText(4, '#cc7000', AddTextType.boxSerial);
			} else if (type == 0x80) { // shared: card group
				addText(3, '#cc7000', AddTextType.cardGroupSerial);
				addText(1, '#000', AddTextType.fixedValue, '01');
			}
		}
	}

	while (bytes.length) {
		var emmtype = addText(1, '#008000', AddTextType.emmType);

		var irdEmmLength = addText(1, '#00F', AddTextType.irdEmmLength);
		var checksumData = {};

		if (irdEmmLength > 0) {
			checksumData = bytes.slice(0, irdEmmLength - 1);
			checksumData.unshift(irdEmmLength.toString(16));
			checksumData.unshift(emmtype);
		}

		if (irdEmmLength > 0) {
			switch (emmtype) {
				case '02':

					var remainingDataLength = irdEmmLength - 1;
					while(remainingDataLength > 0 && bytes.length) {
						remainingDataLength -= ReadIrdNano();
					}
					break;

				case '07':
					var filterSectionLength = addText(1, '#00F', AddTextType.filterSectionLength);
					var remainingDataLength = filterSectionLength;

					while (remainingDataLength > 0 && bytes.length) {
						var filterNano = addText(1, '#008000', AddTextType.filterNanoType);
						switch (filterNano) {
							case '30':
								remainingDataLength -= 1;
								break;

							case '31':
								addText(4, '#cc7000', AddTextType.cardSerial);
								remainingDataLength -= 5;
								break;

							default:
								addText(remainingDataLength - 1, '#000', AddTextType.data);
								remainingDataLength = 0;
								break;
						}
					}

					var remainingDataLength = irdEmmLength - 1 - filterSectionLength - 1;
					while(remainingDataLength > 0 && bytes.length) {
						remainingDataLength -= ReadIrdNano();
					}
					break;

				default:
					addText(irdEmmLength - 1, '#000', AddTextType.data);
					break;
			}

			addText(1, '#800080', AddTextType.irdEmmChecksum, checksumData);
		}

		ReadSingleCardEMM();
	}

	$(target).html(html);
}

/**
 * Really Simple Color Picker in jQuery
 *
 * Licensed under the MIT (MIT-LICENSE.txt) licenses.
 *
 * Copyright (c) 2008-2012
 * Lakshan Perera (www.laktek.com) & Daniel Lacy (daniellacy.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
(function (e) {
	var t, n, r = 0,
		i = {
			control: e('<div class="colorPicker-picker">&nbsp;</div>'),
			palette: e('<div id="colorPicker_palette" class="colorPicker-palette" />'),
			swatch: e('<div class="colorPicker-swatch">&nbsp;</div>'),
			hexLabel: e('<label for="colorPicker_hex">Hex</label>'),
			hexField: e('<input type="text" id="colorPicker_hex" />')
		},
		s = "transparent",
		o;
	e.fn.colorPicker = function (t) {
		return this.each(function () {
			var n = e(this),
				o = e.extend({}, e.fn.colorPicker.defaults, t),
				u = e.fn.colorPicker.toHex(n.val().length > 0 ? n.val() : o.pickerDefault),
				a = i.control.clone(),
				f = i.palette.clone().attr("id", "colorPicker_palette-" + r),
				l = i.hexLabel.clone(),
				c = i.hexField.clone(),
				h = f[0].id,
				p, d;
			e.each(o.colors, function (t) {
				p = i.swatch.clone();
				if (o.colors[t] === s) {
					p.addClass(s).text("X");
					e.fn.colorPicker.bindPalette(c, p, s)
				} else {
					p.css("background-color", "#" + this);
					e.fn.colorPicker.bindPalette(c, p)
				}
				p.appendTo(f)
			});
			l.attr("for", "colorPicker_hex-" + r);
			c.attr({
				id: "colorPicker_hex-" + r,
				value: u
			});
			c.bind("keydown", function (t) {
				if (t.keyCode === 13) {
					var r = e.fn.colorPicker.toHex(e(this).val());
					e.fn.colorPicker.changeColor(r ? r : n.val())
				}
				if (t.keyCode === 27) {
					e.fn.colorPicker.hidePalette()
				}
			});
			c.bind("keyup", function (t) {
				var r = e.fn.colorPicker.toHex(e(t.target).val());
				e.fn.colorPicker.previewColor(r ? r : n.val())
			});
			c.bind("blur", function (t) {
				var r = e.fn.colorPicker.toHex(e(this).val());
				e.fn.colorPicker.changeColor(r ? r : n.val())
			});
			e('<div class="colorPicker_hexWrap" />').append(l).appendTo(f);
			f.find(".colorPicker_hexWrap").append(c);
			if (o.showHexField === false) {
				c.hide();
				l.hide()
			}
			e("body").append(f);
			f.hide();
			a.css("background-color", u);
			a.bind("click", function () {
				if (n.is(":not(:disabled)")) {
					e.fn.colorPicker.togglePalette(e("#" + h), e(this))
				}
			});
			if (t && t.onColorChange) {
				a.data("onColorChange", t.onColorChange)
			} else {
				a.data("onColorChange", function () {})
			} if (d = n.data("text")) a.html(d);
			n.after(a);
			n.bind("change", function () {
				n.next(".colorPicker-picker").css("background-color", e.fn.colorPicker.toHex(e(this).val()))
			});
			n.val(u);
			if (n[0].tagName.toLowerCase() === "input") {
				try {
					n.attr("type", "hidden")
				} catch (v) {
					n.css("visibility", "hidden").css("position", "absolute")
				}
			} else {
				n.hide()
			}
			r++
		})
	};
	e.extend(true, e.fn.colorPicker, {
		toHex: function (e) {
			if (e.match(/[0-9A-F]{6}|[0-9A-F]{3}$/i)) {
				return e.charAt(0) === "#" ? e : "#" + e
			} else if (e.match(/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/)) {
				var t = [parseInt(RegExp.$1, 10), parseInt(RegExp.$2, 10), parseInt(RegExp.$3, 10)],
					n = function (e) {
						if (e.length < 2) {
							for (var t = 0, n = 2 - e.length; t < n; t++) {
								e = "0" + e
							}
						}
						return e
					};
				if (t.length === 3) {
					var r = n(t[0].toString(16)),
						i = n(t[1].toString(16)),
						s = n(t[2].toString(16));
					return "#" + r + i + s
				}
			} else {
				return false
			}
		},
		checkMouse: function (r, i) {
			var s = n,
				o = e(r.target).parents("#" + s.attr("id")).length;
			if (r.target === e(s)[0] || r.target === t[0] || o > 0) {
				return
			}
			e.fn.colorPicker.hidePalette()
		},
		hidePalette: function () {
			e(document).unbind("mousedown", e.fn.colorPicker.checkMouse);
			e(".colorPicker-palette").hide()
		},
		showPalette: function (n) {
			var r = t.prev("input").val();
			n.css({
				top: t.offset().top + t.outerHeight(),
				left: t.offset().left
			});
			e("#color_value").val(r);
			n.show();
			e(document).bind("mousedown", e.fn.colorPicker.checkMouse)
		},
		togglePalette: function (r, i) {
			if (i) {
				t = i
			}
			n = r;
			if (n.is(":visible")) {
				e.fn.colorPicker.hidePalette()
			} else {
				e.fn.colorPicker.showPalette(r)
			}
		},
		changeColor: function (n) {
			t.css("background-color", n);
			t.prev("input").val(n).change();
			e.fn.colorPicker.hidePalette();
			t.data("onColorChange").call(t, e(t).prev("input").attr("id"), n)
		},
		previewColor: function (e) {
			t.css("background-color", e)
		},
		bindPalette: function (n, r, i) {
			i = i ? i : e.fn.colorPicker.toHex(r.css("background-color"));
			r.bind({
				click: function (t) {
					o = i;
					e.fn.colorPicker.changeColor(i)
				},
				mouseover: function (t) {
					o = n.val();
					e(this).css("border-color", "#598FEF");
					n.val(i);
					e.fn.colorPicker.previewColor(i)
				},
				mouseout: function (r) {
					e(this).css("border-color", "#000");
					n.val(t.css("background-color"));
					n.val(o);
					e.fn.colorPicker.previewColor(o)
				}
			})
		}
	});
	e.fn.colorPicker.defaults = {
		pickerDefault: "FFFFFF",
		colors: ["000000", "993300", "333300", "000080", "333399", "333333", "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080", "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "999999", "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0", "FF99CC", "FFCC99", "FFFF99", "CCFFFF", "99CCFF", "FFFFFF"],
		addColors: [],
		showHexField: true
	}
})(jQuery);
/**
 * Stupid jQuery Table Sort
 * Copyright (c) 2012 Joseph McCullough
 * https://github.com/joequery/Stupid-Table-Plugin#readme
 */
(function (e) {
	e.fn.stupidtable = function (t) {
		return this.each(function () {
			var n = e(this);
			t = t || {};
			t = e.extend({}, e.fn.stupidtable.default_sort_fns, t);
			n.on("click.stupidtable", "th", function () {
				var r = e(this);
				var i = 0;
				var s = e.fn.stupidtable.dir;
				n.find("#headline > th").slice(0, r.index()).each(function () {
					var t = e(this).attr("colspan") || 1;
					i += parseInt(t, 10)
				});
				var o = r.data("sort-default") || s.ASC;
				if (r.data("sort-dir")) o = r.data("sort-dir") === s.ASC ? s.DESC : s.ASC;
				var u = r.data("sort") || null;
				if (u === null) {
					return
				}
				n.trigger("beforetablesort", {
					column: i,
					direction: o
				});
				n.css("display");
				setTimeout(function () {
					var a = [];
					var f = t[u];
					var l = n.children("tbody").children("tr");
					l.each(function (t, n) {
						var r = e(n).children().eq(i);
						var s = r.data("sort-value");
						var o = typeof s !== "undefined" ? s : r.text();
						a.push([o, n])
					});
					a.sort(function (e, t, s) {
						return f(e[0], t[0], o)
					});
					if (o != s.ASC) a.reverse();
					l = e.map(a, function (e) {
						return e[1]
					});
					n.children("tbody").append(l);
					n.find("th.sorting-desc, th.sorting-asc").data("sort-dir", null).removeClass("sorting-desc sorting-asc").addClass("sortable");
					r.data("sort-dir", o).removeClass("sortable").addClass("sorting-" + o);
					$('tr').find('td.td-sorting').removeClass('td-sorting');
					$('tr').find('td:eq(' + i + ')').addClass('td-sorting');
					n.trigger("aftertablesort", {
						column: i,
						direction: o
					});
					n.css("display")
				}, 10)
			})
		})
	};
	e.fn.stupidtable.dir = {
		ASC: "asc",
		DESC: "desc"
	};
	var convert_locale = function (c) {
		if (c == "") return 0;
		if(locale_decpoint == ",") {
			c = c.toString().replace( /\./g,"" ).replace( /,/,"." );
		}else if(locale_decpoint == "."){
			c = c.toString().replace( /,/g,"" );
		}
		return(c);
	}
	var ip2int = function dot2num(dot, s) {
		if (dot == ""  && s == "asc")  return 4300000000;
		if (dot == ""  && s == "desc") return 1;
		var d = dot.split('.');
			return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
	}
	e.fn.stupidtable.default_sort_fns = {
		"int": function (e, t, s) {
			return parseInt(convert_locale(e), 10) - parseInt(convert_locale(t), 10)
		},
		"float": function (e, t, s) {
			return parseFloat(convert_locale(e)) - parseFloat(convert_locale(t))
		},
		"ip": function (a, b, s) {
			aIP = ip2int(a, s);
			bIP = ip2int(b, s);
			return aIP - bIP;
		},
		"string": function (e, t, s) {
			if (e == "" && s == "asc") return +1;
			if (t == "" && s == "asc") return -1;
			if (e < t) return -1;
			if (e > t) return +1;
			return 0
		},
		"string-ins": function (e, t, s) {
			e = e.toString().toLowerCase();
			t = t.toString().toLowerCase();
			if (e == "" && s == "asc") return +1;
			if (t == "" && s == "asc") return -1;
			if (e < t) return -1;
			if (e > t) return +1;
			return 0
		}
	}
})(jQuery)

// Create Base64 Object
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}

/*
 * OSCam WebIf Wiki Help System
 * If wikiInternal is true (set by server when WEBIF_WIKI is compiled in),
 * show local wiki popup. Otherwise, open external wiki directly (old behavior).
 */
var wikiPopupHtml = '<div id="wikiPopup" class="wiki-popup">' +
	'<div class="wiki-popup-header">' +
		'<a class="wiki-popup-title" href="#" target="_blank"></a>' +
		'<span class="wiki-popup-reset" title="Reset position and size">&#8634;</span>' +
		'<span class="wiki-popup-close" title="Close">&times;</span>' +
	'</div>' +
	'<div class="wiki-popup-content"></div>' +
	'</div>';

var wikiDragState = { isDragging: false, startX: 0, startY: 0, startLeft: 0, startTop: 0 };
var wikiSavedLeft = localStorage.getItem('wikiPopupLeft');
var wikiSavedWidth = localStorage.getItem('wikiPopupWidth');
var wikiSavedHeight = localStorage.getItem('wikiPopupHeight');
var wikiDefaultWidth = 400;
var wikiLastLinkOffset = 0;
var wikiUserResized = !!(wikiSavedWidth || wikiSavedHeight);
var wikiCurrentLink = null;
var wikiConnectorLine = null;

/* Draw connector line between link and popup */
function updateWikiConnector() {
	if (!wikiCurrentLink || !$('#wikiPopup').is(':visible')) {
		if (wikiConnectorLine) {
			wikiConnectorLine.remove();
			wikiConnectorLine = null;
		}
		return;
	}

	var $link = wikiCurrentLink;
	var $popup = $('#wikiPopup');

	/* Calculate positions */
	var linkOffset = $link.offset();
	var linkRight = linkOffset.left + $link.outerWidth();
	var linkCenterY = linkOffset.top + $link.outerHeight() / 2;

	var popupOffset = $popup.offset();
	var popupLeft = popupOffset.left;
	var popupCenterY = popupOffset.top + 20; /* Connect to header area */

	/* Create or update SVG line */
	if (!wikiConnectorLine) {
		wikiConnectorLine = $('<svg class="wiki-connector"><line/></svg>');
		$('body').append(wikiConnectorLine);
	}

	/* Position SVG to cover the area between link and popup */
	var minX = Math.min(linkRight, popupLeft) - 5;
	var maxX = Math.max(linkRight, popupLeft) + 5;
	var minY = Math.min(linkCenterY, popupCenterY) - 5;
	var maxY = Math.max(linkCenterY, popupCenterY) + 5;

	wikiConnectorLine.css({
		position: 'absolute',
		left: minX,
		top: minY,
		width: maxX - minX,
		height: maxY - minY,
		pointerEvents: 'none',
		zIndex: 1
	});

	wikiConnectorLine.find('line').attr({
		x1: linkRight - minX,
		y1: linkCenterY - minY,
		x2: popupLeft - minX,
		y2: popupCenterY - minY,
		stroke: '#ffcc00',
		'stroke-width': 2
	});
}

function removeWikiConnector() {
	if (wikiConnectorLine) {
		wikiConnectorLine.remove();
		wikiConnectorLine = null;
	}
}

$(function() {
	if (typeof oscamconf === 'undefined') return;

	/* Check if internal wiki is enabled (WEBIF_WIKI compiled in) */
	if (typeof wikiInternal === 'undefined' || wikiInternal !== true) {
		/* No internal wiki - external wiki links are handled in document.ready above */
		return;
	}

	/* Internal wiki enabled - setup popup and override click handler */
	$('body').append(wikiPopupHtml);

	$('.wiki-popup-close').click(function() {
		$('#wikiPopup').fadeOut(200);
		removeWikiConnector();
		if (wikiCurrentLink) {
			wikiCurrentLink.removeClass('wiki-active');
			wikiCurrentLink = null;
		}
	});

	$('.wiki-popup-reset').click(function() {
		localStorage.removeItem('wikiPopupLeft');
		localStorage.removeItem('wikiPopupWidth');
		localStorage.removeItem('wikiPopupHeight');
		wikiSavedLeft = null;
		wikiSavedWidth = null;
		wikiSavedHeight = null;
		wikiUserResized = false;
		var $popup = $('#wikiPopup');
		/* Recalculate position based on current link */
		if (wikiCurrentLink) {
			var offset = wikiCurrentLink.offset();
			wikiLastLinkOffset = offset.left + wikiCurrentLink.outerWidth();
			var defaultLeft = wikiLastLinkOffset + 10;
			if (defaultLeft + 420 > $(window).width()) {
				defaultLeft = $(window).width() - 420;
			}
			$popup.css({ width: wikiDefaultWidth, height: 'auto', left: defaultLeft, top: offset.top - 10 });
		} else {
			var defaultLeft = wikiLastLinkOffset + 10;
			if (defaultLeft + 420 > $(window).width()) {
				defaultLeft = $(window).width() - 420;
			}
			$popup.css({ width: wikiDefaultWidth, height: 'auto', left: defaultLeft });
		}
		setTimeout(updateWikiConnector, 50);
	});

	$(document).click(function(e) {
		if (!$(e.target).closest('#wikiPopup').length &&
		    !$(e.target).closest('form table a').length) {
			$('#wikiPopup').fadeOut(200);
			removeWikiConnector();
			if (wikiCurrentLink) {
				wikiCurrentLink.removeClass('wiki-active');
				wikiCurrentLink = null;
			}
		}
	});

	$(document).keydown(function(e) {
		if (e.keyCode === 27) {
			$('#wikiPopup').fadeOut(200);
			removeWikiConnector();
			if (wikiCurrentLink) {
				wikiCurrentLink.removeClass('wiki-active');
				wikiCurrentLink = null;
			}
		}
		/* Arrow keys to navigate between parameters when popup is open */
		if ((e.keyCode === 38 || e.keyCode === 40) && $('#wikiPopup').is(':visible') && wikiCurrentLink) {
			var $allLinks = $('form table a').filter(function() {
				return !$(this).attr('href') && $(this).text().trim();
			});
			var currentIndex = $allLinks.index(wikiCurrentLink);
			var newIndex;
			if (e.keyCode === 38) {
				/* Arrow up - previous parameter */
				if (currentIndex > 0) {
					e.preventDefault();
					newIndex = currentIndex - 1;
					var $newLink = $allLinks.eq(newIndex);
					$newLink.click();
					/* Scroll into view if needed */
					var linkTop = $newLink.offset().top;
					var scrollTop = $(window).scrollTop();
					if (linkTop < scrollTop + 50) {
						$('html, body').animate({ scrollTop: linkTop - 100 }, 150);
					}
				}
			} else {
				/* Arrow down - next parameter */
				if (currentIndex < $allLinks.length - 1) {
					e.preventDefault();
					newIndex = currentIndex + 1;
					var $newLink = $allLinks.eq(newIndex);
					$newLink.click();
					/* Scroll into view if needed */
					var linkBottom = $newLink.offset().top + $newLink.outerHeight();
					var windowBottom = $(window).scrollTop() + $(window).height();
					if (linkBottom > windowBottom - 50) {
						$('html, body').animate({ scrollTop: $newLink.offset().top - $(window).height() + 150 }, 150);
					}
				}
			}
		}
	});

	/* Drag functionality for popup */
	$('.wiki-popup-header').css('cursor', 'move').on('mousedown', function(e) {
		if ($(e.target).hasClass('wiki-popup-close') || $(e.target).hasClass('wiki-popup-reset') || $(e.target).hasClass('wiki-popup-title')) return;
		wikiDragState.isDragging = true;
		wikiDragState.startX = e.pageX;
		wikiDragState.startY = e.pageY;
		wikiDragState.startLeft = parseInt($('#wikiPopup').css('left')) || 0;
		wikiDragState.startTop = parseInt($('#wikiPopup').css('top')) || 0;
		e.preventDefault();
	});

	/* Touch support for drag */
	$('.wiki-popup-header').on('touchstart', function(e) {
		if ($(e.target).hasClass('wiki-popup-close') || $(e.target).hasClass('wiki-popup-reset') || $(e.target).hasClass('wiki-popup-title')) return;
		var touch = e.originalEvent.touches[0];
		wikiDragState.isDragging = true;
		wikiDragState.startX = touch.pageX;
		wikiDragState.startY = touch.pageY;
		wikiDragState.startLeft = parseInt($('#wikiPopup').css('left')) || 0;
		wikiDragState.startTop = parseInt($('#wikiPopup').css('top')) || 0;
	});

	$(document).on('touchmove', function(e) {
		if (!wikiDragState.isDragging) return;
		var touch = e.originalEvent.touches[0];
		var newLeft = wikiDragState.startLeft + (touch.pageX - wikiDragState.startX);
		var newTop = wikiDragState.startTop + (touch.pageY - wikiDragState.startY);
		newLeft = Math.max(0, Math.min(newLeft, $(window).width() - 420));
		newTop = Math.max(0, newTop);
		$('#wikiPopup').css({ left: newLeft, top: newTop });
		updateWikiConnector();
		e.preventDefault();
	});

	$(document).on('touchend', function() {
		if (wikiDragState.isDragging) {
			wikiDragState.isDragging = false;
			wikiSavedLeft = $('#wikiPopup').css('left');
			localStorage.setItem('wikiPopupLeft', wikiSavedLeft);
		}
	});

	$(document).on('mousemove', function(e) {
		if (!wikiDragState.isDragging) return;
		var newLeft = wikiDragState.startLeft + (e.pageX - wikiDragState.startX);
		var newTop = wikiDragState.startTop + (e.pageY - wikiDragState.startY);
		newLeft = Math.max(0, Math.min(newLeft, $(window).width() - 420));
		newTop = Math.max(0, newTop);
		$('#wikiPopup').css({ left: newLeft, top: newTop });
		updateWikiConnector();
	});

	$(document).on('mouseup', function() {
		if (wikiDragState.isDragging) {
			wikiDragState.isDragging = false;
			wikiSavedLeft = $('#wikiPopup').css('left');
			localStorage.setItem('wikiPopupLeft', wikiSavedLeft);
		}
	});

	/* Save size after user resize */
	var wikiLastWidth = 0;
	var wikiLastHeight = 0;
	$('#wikiPopup').on('mouseup', function() {
		var w = $(this).width();
		var h = $(this).height();
		if (wikiLastWidth && wikiLastHeight && (w !== wikiLastWidth || h !== wikiLastHeight)) {
			wikiUserResized = true;
			wikiSavedWidth = w;
			wikiSavedHeight = h;
			localStorage.setItem('wikiPopupWidth', wikiSavedWidth);
			localStorage.setItem('wikiPopupHeight', wikiSavedHeight);
		}
		wikiLastWidth = w;
		wikiLastHeight = h;
	});

	$('form table a').off('click').click(function(e) {
		e.preventDefault();
		e.stopPropagation();

		/* Remove highlight from previous link */
		if (wikiCurrentLink) {
			wikiCurrentLink.removeClass('wiki-active');
		}

		/* Store current link for keyboard navigation and highlight it */
		wikiCurrentLink = $(this);
		wikiCurrentLink.addClass('wiki-active');

		/* Get real input name for internal wiki lookup */
		var $cell = $(this).parent();
		var inputName = null;

		/* Try 1: Input in next cell (standard layout) */
		var $input = $cell.next().find('input,select,textarea').first();

		/* Try 2: Input in same cell */
		if (!$input.length) {
			$input = $cell.find('input,select,textarea').first();
		}

		/* Try 3: For TH headers (like services), look in same column of next row */
		if (!$input.length && $cell.is('th')) {
			var cellIndex = $cell.index();
			var $nextRow = $cell.closest('tr').next('tr');
			if ($nextRow.length) {
				var $correspondingCell = $nextRow.find('td, th').eq(cellIndex);
				$input = $correspondingCell.find('input,select,textarea').first();
			}
		}

		if ($input.length) {
			inputName = $input.attr('name');
		}

		/* Get param for external wiki link (use data-p override if present) */
		var externalParam = $(this).data('p') || inputName;

		if (!inputName) return;

		/* Extract section from form's hidden part input */
		var section = $('input[name="part"]').val() || '';

		var $link = $(this);
		var $popup = $('#wikiPopup');

		$('.wiki-popup-title').text(inputName).attr('href',
			'https://git.streamboard.tv/common/oscam/-/wikis/pages/configuration/oscam.' + oscamconf + '#' + externalParam);
		$('.wiki-popup-content').html('<div class="wiki-loading">Loading...</div>');

		var offset = $link.offset();
		wikiLastLinkOffset = offset.left + $link.outerWidth();
		var leftPos;
		if (wikiSavedLeft) {
			leftPos = parseInt(wikiSavedLeft);
		} else {
			leftPos = offset.left + $link.outerWidth() + 10;
			if (leftPos + 420 > $(window).width()) {
				leftPos = $(window).width() - 420;
			}
		}
		$popup.css({
			top: offset.top - 10,
			left: leftPos,
			width: wikiUserResized && wikiSavedWidth ? parseInt(wikiSavedWidth) : wikiDefaultWidth,
			height: wikiUserResized && wikiSavedHeight ? parseInt(wikiSavedHeight) : 'auto',
			'max-width': $(window).width() - 20,
			'max-height': $(window).height() - 20
		}).fadeIn(200);

		/* Draw connector line */
		setTimeout(updateWikiConnector, 50);

		/* Update last size for resize detection */
		setTimeout(function() {
			wikiLastWidth = $popup.width();
			wikiLastHeight = $popup.height();
		}, 250);

		$.ajax({
			url: 'wiki.json',
			type: 'GET',
			data: { config: oscamconf, section: section, param: inputName },
			dataType: 'json',
			success: function(data) {
				if (data && data.text) {
					var html = formatWikiText(data.text);
					$('.wiki-popup-content').html(html);
				} else {
					$('.wiki-popup-content').html(
						'<div class="wiki-nohelp">No help available for this parameter.<br><br>' +
						'<a href="https://git.streamboard.tv/common/oscam/-/wikis/pages/configuration/oscam.' +
						oscamconf + '#' + externalParam + '" target="_blank">View Wiki &rarr;</a></div>'
					);
				}
			},
			error: function() {
				$('.wiki-popup-content').html(
					'<div class="wiki-error">Failed to load help.<br><br>' +
					'<a href="https://git.streamboard.tv/common/oscam/-/wikis/pages/configuration/oscam.' +
					oscamconf + '#' + externalParam + '" target="_blank">View Wiki &rarr;</a></div>'
				);
			}
		});
	});
});

function formatWikiText(text) {
	if (!text) return '';

	/* Convert escaped newlines to real newlines first */
	text = text.replace(/\\n/g, '\n');

	text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
	text = text.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre class="wiki-code">$2</pre>');
	text = text.replace(/```([\s\S]*?)```/g, '<pre class="wiki-code">$1</pre>');
	text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
	text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
	text = text.replace(/^### (.+)$/gm, '<h4>$1</h4>');
	text = text.replace(/^## (.+)$/gm, '<h3>$1</h3>');
	text = text.replace(/\n/g, '<br>');
	text = text.replace(/<\/pre><br>/g, '</pre>');

	return '<div class="wiki-text">' + text + '</div>';
}

/* Wiki documentation status toggle - shows icons for missing/review/ok documentation */
$(document).ready(function() {
	if (typeof oscamconf === 'undefined' || typeof wikiInternal === 'undefined' || wikiInternal !== true) {
		return;
	}

	var wikiStatusLoaded = false;
	var wikiStatusVisible = false;

	/* Support different table classes: config, configreader, configuser, configservices, writeemm */
	var $allTables = $('table.config, table.configreader, table.configuser, table.configservices, table.writeemm');
	if (!$allTables.length) return;

	/* Only make the FIRST table header clickable */
	var $firstHeader = $allTables.find('th[colspan]').first();
	if (!$firstHeader.length) return;

	$firstHeader.css('cursor', 'pointer').attr('title', 'Click to toggle documentation status icons');

	$firstHeader.click(function() {
		if (!wikiStatusLoaded) {
			/* Load status for all parameters */
			$.ajax({
				url: 'wiki_status.json',
				type: 'GET',
				data: { config: oscamconf },
				dataType: 'json',
				success: function(data) {
					if (data) {
						/* Method 1: Find all <A> tags that are parameter labels */
						$allTables.find('a').each(function() {
							var $a = $(this);

							/* Skip if already has icon */
							if ($a.find('.wiki-status-icon').length) return;

							/* Skip links with href (real links, not labels) */
							if ($a.attr('href')) return;

							/* Skip if no text */
							var labelText = $a.text().trim();
							if (!labelText) return;

							/* Find associated input name */
							var paramName = null;
							var $cell = $a.closest('td, th');

							/* Try 1: Input in same cell */
							var $input = $cell.find('input,select,textarea').first();

							/* Try 2: Input in next cell */
							if (!$input.length) {
								$input = $cell.next('td, th').find('input,select,textarea').first();
							}

							/* Try 3: For TH headers, look in same column of next row */
							if (!$input.length && $cell.is('th')) {
								var cellIndex = $cell.index();
								var $nextRow = $cell.closest('tr').next('tr');
								if ($nextRow.length) {
									var $correspondingCell = $nextRow.find('td, th').eq(cellIndex);
									$input = $correspondingCell.find('input,select,textarea').first();
								}
							}

							if ($input.length) {
								paramName = $input.attr('name');
							}

							if (!paramName) return;

							var status = data[paramName];
							var icon = '';
							var tooltip = '';
							if (status === 'missing') { icon = '❗ '; tooltip = 'Documentation missing'; }
							else if (status === 'review') { icon = '⚠️ '; tooltip = 'Documentation needs review'; }
							else if (status === 'ok') { icon = '✅ '; tooltip = 'Documentation complete'; }

							if (icon) {
								$a.prepend('<span class="wiki-status-icon" title="' + tooltip + '">' + icon + '</span>');
							}
						});

						wikiStatusLoaded = true;
						wikiStatusVisible = true;
						$('.wiki-status-icon').addClass('visible');
					}
				}
			});
		} else {
			/* Toggle visibility for ALL icons */
			wikiStatusVisible = !wikiStatusVisible;
			if (wikiStatusVisible) {
				$('.wiki-status-icon').addClass('visible');
			} else {
				$('.wiki-status-icon').removeClass('visible');
			}
		}
	});
});
