﻿function attachToTabPanel(tabContainer) {
	var childElements = getChildElements(tabContainer);
	var tabs = getChildElements(childElements[0]);

	for (var i = 0; tabs[i]; i++)
		attachToTab(tabContainer, tabs[i], i);

	selectTab(tabContainer, 0);
}

function attachToTab(tabContainer, tab, index) {
	tab.onclick = function () { selectTab(tabContainer, index); };
}

function selectTab(tabContainer, index) {
	var childElements = getChildElements(tabContainer);
	var tabs = getChildElements(childElements[0]);
	var panels = getChildElements(childElements[1]);
	var i;

	for (i = 0; tabs[i]; i++)
		tabs[i].className = (i == index ? "Selected" : "");

	for (i = 0; panels[i]; i++)
		panels[i].style.display = (i == index ? "block" : "none");
}

function getChildElements(element) {
	var index = 0;
	var elementArray = new Array(element.childNodes.length);

	for (var i = 0; element.childNodes[i]; i++)
		if (element.childNodes[i].nodeType == 1)
			elementArray[index++] = element.childNodes[i];

	elementArray.length = index;

	return elementArray;
}

function setElementText(element, text) {
	window.clearElement(element);
	element.appendChild(element.ownerDocument.createTextNode(text));
}

function discardElement(element) {
	var leakBin = document.getElementById('leakBin');

	if (!leakBin)
		leakBin = this.addElement(document.body, "DIV", { id: "leakBin" }, "display: none;");

	leakBin.appendChild(element);
	window.clearElement(leakBin);
}

function clearElement(element) {
	if (element.innerHTML)
		element.innerHTML = "";
}

function addWindowLoadHandler(handler) {
	if (window.attachEvent)
		window.attachEvent("onload", handler);
	else
		window.addEventListener("load", handler, false);
}

function showModalActivityBox(activityImageUrl, message, title) {
	var panel = this.createElement("DIV", null, "text-align: center; font-style: italic; font-size: 18px; font-weight: bold; padding-top: 25px;");
	this.addElement(panel, "IMG", { src: activityImageUrl }, "vertical-align: middle;");
	this.addNonBreakingSpace(panel);
	this.addTextNode(panel, message);
	this.showModalDialog(panel, 300, 150, title);
}

function showModalMessageBox(message, width, height, title, closeText, closeCallback) {
	var paragraph = this.createElement("P", null, "padding: 15px; margin: 0px;", message);
	this.showModalDialog(paragraph, width, height, title, closeText, closeCallback);
}

function showModalPrompt(message, buttonText, width, height, title, closeText, closeCallback, buttonCallback) {
	var panel = this.createElement("DIV", null, "padding: 15px;");
	this.addElement(panel, "P", null, "margin: 0px;", message);
	var buttonParagraph = this.addElement(panel, "P", null, "margin: 20px 0px 0px 0px; text-align: center;");
	var button = this.addElement(buttonParagraph, "INPUT", { type: "button", onclick: buttonCallback, value: buttonText }, "font-size: 15px;");
	this.showModalDialog(panel, width, height, title, closeText, closeCallback);
	button.focus();
}

function showModalPage(url, width, height, title, closeText, closeCallback) {
	var frame = this.createElement("IFRAME", { src: url }, "border-width: 0px; height: 100%;");
	this.showModalDialog(frame, width, height, title, closeText, closeCallback);
}

function showModalDialog(element, width, height, title, closeText, closeCallback) {
	hideModalDialog();

	var modalDialog = this.addElement(document.body, "DIV", { id: "dialog" }, "position: fixed; z-index: 1000; top: 0px; left: 0px; right: 0px; bottom: 0px; margin: 0px;");
	var backgroundElement = this.addElement(modalDialog, "DIV", null, "position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; margin: 0px; opacity: 0.5; filter: alpha(opacity=50); background-color: #666;");
	var panelElement = this.addElement(modalDialog, "DIV", null, "position: absolute; opacity: 1.0; cursor: move;");
	var titleElement = this.addElement(panelElement, "DIV", null, "position: absolute; top: 10px; left: 20px; color: #FFF; font-weight: bold;", title);
	var contentElement = this.addElement(panelElement, "DIV", null, "position: absolute; top: 35px; left: 20px; margin: 0px; padding: 0px; color: #000; overflow: auto; cursor: default;", element);

	var panelWidth = width + 40;
	var panelHeight = height + 55;

	panelElement.style.left = Math.max(0, (document.documentElement.clientWidth / 2) - (panelWidth / 2)) + "px";
	panelElement.style.top = Math.max(0, (document.documentElement.clientHeight / 2) - (panelHeight / 2)) + "px";
	panelElement.style.width = panelWidth + "px";
	panelElement.style.height = panelHeight + "px";
	this.addBackgroundRadiusCss(panelElement, 10, "444444");

	contentElement.style.width = width + "px";
	contentElement.style.height = height + "px";
	this.addBackgroundRadiusCss(contentElement, 5, "FFFFFF");

	if (closeText) {
		var closeElement = this.addElement(panelElement, "A", { href: "#" }, "position: absolute; top: 10px; right: 20px; color: #FFF; text-decoration: none; font-weight: bold;", closeText + " [X]");
		closeElement.onclick = function () { window.discardElement(modalDialog); if (closeCallback) closeCallback(); return false; };
	}

	var dragOffset;
	contentElement.onmousedown = function (e) { var ea = window.getEventArgs(e); window.cancelBubble(ea); };
	panelElement.onmousedown = function (e) { var ea = window.getEventArgs(e); var l = Sys.UI.DomElement.getLocation(panelElement); var ml = window.getMouseLocation(ea); dragOffset = { x: l.x - ml.x, y: l.y - ml.y }; };
	panelElement.onmouseup = function (e) { dragOffset = null; };
	modalDialog.onmousemove = function (e) { if (dragOffset) { var ea = window.getEventArgs(e); var ml = window.getMouseLocation(ea); Sys.UI.DomElement.setLocation(panelElement, dragOffset.x + ml.x, dragOffset.y + ml.y); } };
}

function hideModalDialog() {
	var dialog = $get("dialog");

	if (dialog)
		this.discardElement(dialog);
}

function addCell(row, properties, styles, content) {
	var cell = row.insertCell(-1);
	this.initializeElement(cell, properties, styles, content);
	return cell;
}

function createElement(tagName, properties, styles, content) {
	var element = document.createElement(tagName);
	this.initializeElement(element, properties, styles, content);
	return element;
}

function addElement(container, tagName, properties, styles, content) {
	var element = this.createElement(tagName, properties, styles, content);
	container.appendChild(element);
	return element;
}

function initializeElement(element, properties, styles, content) {
	if (properties)
		for (var propertyName in properties)
			element[propertyName] = properties[propertyName];

	if (typeof styles == "string")
		element.style.cssText = styles;
	else if (styles)
		for (var styleName in styles)
			element.style[styleName] = styles[styleName];

	if (typeof content == "string")
		this.setElementText(element, content);
	else if (content && content.length)
		for (var i = 0; content[i]; i++)
			element.appendChild(content[i]);
	else if (content)
		element.appendChild(content);
}

function addTextNode(container, text) {
	var textNode = document.createTextNode(text);
	container.appendChild(textNode);
}

function addNonBreakingSpace(container) {
	this.addTextNode(container, "\u00a0");
}

function getCookieValue(name) {
	var cookieStrings = document.cookie.split(";");

	for (var i = 0; cookieStrings[i]; i++) {
		var cookieParts = cookieStrings[i].split("=");

		if (decodeURIComponent(cookieParts[0]).trim() == name)
			return decodeURIComponent(cookieParts[1]);
	}

	return null;
}

function setCookieValue(name, value, days) {
	var date = new Date();
	date.setDate(date.getDate() + days);
	var encodedValue = encodeURIComponent(value);
	document.cookie = String.format("{0}={1}; expires={2:F}", name, encodedValue, date);
}

function loadSettings() {
	var stringValue = this.getCookieValue("settings");

	if (stringValue == null)
		return new Object();

	return Sys.Serialization.JavaScriptSerializer.deserialize(stringValue);
}

function saveSettings(settings) {
	var stringValue = Sys.Serialization.JavaScriptSerializer.serialize(settings);
	this.setCookieValue("settings", stringValue, 3650);
}

function convertToBase64String(bytes) {
	var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = "", tmp_arr = [];

	do { // pack three octets into four hexets        
		o1 = bytes[i++];
		o2 = bytes[i++];
		o3 = bytes[i++];

		bits = o1 << 16 | o2 << 8 | o3;
		h1 = bits >> 18 & 0x3f;
		h2 = bits >> 12 & 0x3f;
		h3 = bits >> 6 & 0x3f;
		h4 = bits & 0x3f;
		tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
	} while (i < bytes.length);

	enc = tmp_arr.join("");

	switch (bytes.length % 3) {
		case 1:
			enc = enc.slice(0, -2) + "=="; break;
		case 2:
			enc = enc.slice(0, -1) + "=";
			break;
	}

	return enc;
}

function getDotNetMajorMinorVersion() {
	var version = 0.0;

	try {
		var matches = navigator.userAgent.match(/\.NET CLR [0-9.]+/g);

		for (var i = 0; matches[i]; i++) {
			var versionString = matches[i].match(/[0-9]\.[0-9]/);
			var versionInt = parseFloat(versionString);
			version = Math.max(versionInt, version);
		}
	} catch (ex) {
		// don't care
	}

	return version;
}

function getProcessTypeString(processType) {
	if (processType == 1)
		return "Host";
	else if (processType == 2)
		return "Guest";
	else
		return "Unknown";
}

function getClientLaunchParametersString(clientLaunchParameters) {
	var parameters = new Object();
	parameters.y = getProcessTypeString(clientLaunchParameters.ProcessType);
	parameters.h = clientLaunchParameters.Host;
	parameters.p = clientLaunchParameters.Port;
	parameters.s = clientLaunchParameters.SessionID;
	parameters.k = convertToBase64String(clientLaunchParameters.EncryptionKey);
	parameters.a = clientLaunchParameters.ApplicationTitle;
	parameters.t = clientLaunchParameters.SessionTitle;
	if (clientLaunchParameters.CanEndSession) parameters.e = "1";
	return getQueryString(parameters);
}

function getAbsoluteUrl(relativeUrl) {
	return window.location.href.slice(0, window.location.href.lastIndexOf("/") + 1) + relativeUrl;
}

function parseQueryString(queryString) {
	var map = new Object();

	if (queryString.length != 0) {
		if (queryString.charAt(0) == "?")
			queryString = queryString.slice(1);

		queryString = queryString.replace(/\+/g, ' ');

		var parts = queryString.split("&");

		for (var i = 0; parts[i]; i++) {
			var subParts = parts[i].split("=");
			var name = decodeURIComponent(subParts[0]);
			var value = decodeURIComponent(subParts[1]);
			map[name] = value;
		}
	}

	return map;
}

function getQueryString(map) {
	var queryString = new Sys.StringBuilder();
	var first = true;

	for (var key in map) {
		var value = map[key];
		var valueArray;

		if (value instanceof Array) {
			valueArray = value;
		} else {
			// watch out, in one JS version Array constructor with integer
			// will create that many elements
			valueArray = new Array();
			valueArray.push(value);
		}

		for (var i = 0; i < valueArray.length; i++) {
			queryString.append(first ? "?" : "&");
			queryString.append(encodeURIComponent(key));
			queryString.append("=");
			queryString.append(encodeURIComponent(valueArray[i]));
			first = false;
		}
	}

	return queryString.toString();
}

function launchDownload(url, downlevel) {
	if (downlevel)
		window.location.href = url;
	else
		this.addElement(document.body, "IFRAME", { src: url }, "display: none;");
}

function findArrayElement(array, predicate) {
	for (var i = 0; array[i]; i++)
		if (predicate(array[i]))
			return array[i];

	return null;
}

function filterArray(array, predicate) {
	var newArray = new Array();

	for (var i = 0; array[i]; i++)
		if (predicate(array[i]))
			newArray.push(array[i]);

	return newArray;
}

function coalesce(x, y) {
	return (x == null || x == undefined ? y : x);
}

function ClickOnceDirectLauncher() {
	this.name = ".NET ClickOnce Direct";

	if (getDotNetMajorMinorVersion() > 2.0)
		this.compatibility = 1.0;
	else if (navigator.userAgent.match("Windows"))
		this.compatibility = 0.2;
	else
		this.compatibility = 0.0;

	this.efficiency = 1.0; // solid user experience, instant start

	this.launch = function (clientLaunchParameters) {
		launchDownload(String.format("Bin/Elsinore.ScreenConnect.{0}Client.application{1}", getProcessTypeString(clientLaunchParameters.ProcessType), getClientLaunchParametersString(clientLaunchParameters)));
	};
}

function ClickOnceBootstrapLauncher() {
	this.name = ".NET ClickOnce Bootstrap";

	if (navigator.userAgent.match("Windows"))
		this.compatibility = 1.0;
	else
		this.compatibility = 0.0;

	if (getDotNetMajorMinorVersion() > 2.0)
		this.efficiency = 0.9; // solid user experience, not instant start
	else
		this.efficiency = 0.8; // solid user experience, not instant start, could have to install framework

	this.launch = function (clientLaunchParameters) {
		var urlParameters = new Object();
		urlParameters.ApplicationFile = String.format("Elsinore.ScreenConnect.{0}Client.application{1}", getProcessTypeString(clientLaunchParameters.ProcessType), getClientLaunchParametersString(clientLaunchParameters));
		urlParameters.ApplicationUrl = getAbsoluteUrl("Bin");
		urlParameters.ApplicationName = clientLaunchParameters.ApplicationTitle;
		urlParameters.OutputFileName = String.format("Elsinore.ScreenConnect.{0}Client.exe", getProcessTypeString(clientLaunchParameters.ProcessType));
		urlParameters.PrerequisiteCode = "Microsoft.Net.Framework.2.0";
		launchDownload(String.format("Bootstrapper.axd{0}", getQueryString(urlParameters)));
	};
}

function WebStartLauncher() {
	this.name = "Java Web Start";

	this.compatibility = 0.0;

	if (window.ActiveXObject) {
		try {
			var obj = new ActiveXObject('JavaWebStart.isInstalled');

			if (obj != null)
				this.compatibility = 1.0;
		} catch (e) {
			// don't care
		}
	} else if (navigator.mimeTypes['application/x-java-jnlp-file'] != null || navigator.mimeTypes['application/x-java-applet;version=1.5'] != null) {
		this.compatibility = 1.0;
	}

	if (navigator.userAgent.match("Chrome"))
		this.efficiency = 0.6; // weaker user experience, not instant start, as of 7/2010 chrome required save then run
	else
		this.efficiency = 0.7; // weaker user experience, instant start

	this.launch = function (clientLaunchParameters) {
		var urlParameters = new Object();
		urlParameters.Title = String.format("{0} Guest Client", clientLaunchParameters.ApplicationTitle);
		urlParameters.Vendor = "Elsinore Technologies Inc.";
		urlParameters.JavaVersion = "1.5+";
		urlParameters.OutputFileName = "Elsinore.ScreenConnect.Client.jnlp";
		urlParameters.JarFileUrl = new Array(getAbsoluteUrl("Bin/Elsinore.ScreenConnect.Client.jar"), getAbsoluteUrl("Bin/Elsinore.ScreenConnect.Core.jar"));
		urlParameters.Argument = new Array(clientLaunchParameters.ApplicationTitle, clientLaunchParameters.Host, clientLaunchParameters.Port, clientLaunchParameters.SessionID, convertToBase64String(clientLaunchParameters.EncryptionKey), getProcessTypeString(clientLaunchParameters.ProcessType), clientLaunchParameters.SessionTitle, clientLaunchParameters.CanEndSession);
		launchDownload(String.format("JavaWebStart.axd{0}", getQueryString(urlParameters)));
	};
}

function AndroidLauncher() {
	this.name = "Java Android";

	if (navigator.userAgent.match("Android"))
		this.compatibility = 1.0;
	else
		this.compatibility = 0.0;

	this.efficiency = 1.0;

	this.launch = function (clientLaunchParameters) {
		window.launchMobileClient(clientLaunchParameters, "Launcher.AndroidPrompt", "AndroidConfirmVersion", "Launcher.AndroidInstallUrl");
	};
}

function iOSLauncher() {
	this.name = ".NET iOS";

	if (navigator.userAgent.match("iPhone") || navigator.userAgent.match("iPad") || navigator.userAgent.match("iPod") || navigator.userAgent.match("iOS"))
		this.compatibility = 1.0;
	else
		this.compatibility = 0.0;

	this.efficiency = 1.0;

	this.launch = function (clientLaunchParameters) {
		window.launchMobileClient(clientLaunchParameters, "Launcher.iOSPrompt", "iOSConfirmVersion", "Launcher.iOSInstallUrl");
	};
}

function getSortedLaunchers() {
	var launchers = new Array();
	launchers.push(new ClickOnceDirectLauncher());
	launchers.push(new ClickOnceBootstrapLauncher());
	launchers.push(new WebStartLauncher());
	launchers.push(new AndroidLauncher());
	launchers.push(new iOSLauncher());

	launchers = this.filterArray(launchers, function (launcher) { return launcher.compatibility != 0.0; });
	launchers.sort(function (a, b) { var cd = b.compatibility - a.compatibility; return (cd != 0 ? cd : b.efficiency - a.efficiency); });

	return launchers;
}

function launchMobileClient(clientLaunchParameters, promptTextResourceKey, installedSettingsKey, installUrlResourceKey) {
	if (clientLaunchParameters.ProcessType == 1) {
		var url;
		var settings = window.loadSettings();
		var alreadyInstalled = (settings[installedSettingsKey] == window.productVersion);

		if (alreadyInstalled || window.confirm(Resources[promptTextResourceKey])) {
			url = String.format("relay://{0}:{1}/{2}/{3}", clientLaunchParameters.Host, clientLaunchParameters.Port, clientLaunchParameters.SessionID, encodeURIComponent(convertToBase64String(clientLaunchParameters.EncryptionKey)));

			if (!alreadyInstalled) {
				settings[installedSettingsKey] = window.productVersion;
				window.saveSettings(settings);
			}
		} else {
			url = Resources[installUrlResourceKey];
		}

		window.launchDownload(url, true);
	}
}

function rebuildTable(tableBodyID, dataArray, dataRowBuilder, emptyRowBuilder) {
	var tableBody = $get(tableBodyID);

	while (tableBody.rows.length != 0)
		tableBody.deleteRow(0);

	if (dataArray.length == 0) {
		if (emptyRowBuilder) {
			var emptyRow = tableBody.insertRow(-1);
			emptyRowBuilder(emptyRow);
		}
	}
	else {
		for (var i = 0; dataArray[i]; i++) {
			var dataRow = tableBody.insertRow(-1);
			dataRow.dataItem = dataArray[i];
			dataRowBuilder(dataRow, i);
		}
	}
}

function getPropertyFromLineage(element, propertyName) {
	while (element) {
		var value = element[propertyName];

		if (value)
			return value;

		element = element.parentNode;
	}

	return null;
}

function getAncestorByTagName(element, ancestorTagName) {
	while (element) {
		if (element.tagName == ancestorTagName)
			return element;

		element = element.parentNode;
	}

	return null;
}

function getEventArgs(event) {
	return event || window.event;
}

function getMouseLocation(eventArgs) {
	if (eventArgs.pageX || eventArgs.pageY)
		return { x: eventArgs.pageX, y: eventArgs.pageY };

	return {
		x: eventArgs.clientX + document.body.scrollLeft - document.body.clientLeft,
		y: eventArgs.clientY + document.body.scrollTop - document.body.clientTop
	};
}

function getEventDataCommand(event) {
	var eventArgs = this.getEventArgs(event);
	var clickedElement = eventArgs.target ? eventArgs.target : eventArgs.srcElement;
	return { dataItem: getPropertyFromLineage(clickedElement, "dataItem"), commandName: getPropertyFromLineage(clickedElement, "commandName") };
}

function getRandomChar(minCharCode, maxCharCode) {
	var charCode = minCharCode + Math.floor(Math.random() * (maxCharCode - minCharCode));
	return String.fromCharCode(charCode);
}

function isEnterKey(eventArgs) {
	return eventArgs && eventArgs.keyCode == 13;
}

function handleKeyPressForSubmit(event, buttonID) {
	var eventArgs = this.getEventArgs(event);

	if (window.isEnterKey(eventArgs)) {
		$get(buttonID).click();
		return false;
	}

	return true;
}

function cancelBubble(eventArgs) {
	if (eventArgs.stopPropagation)
		eventArgs.stopPropagation();
	else
		eventArgs.cancelBubble = true;
}

function isIE(minVersion, maxVersion) {
	var matches = navigator.userAgent.match(/\MSIE ([0-9.]+)/);

	if (matches == null)
		return false;
	else if (minVersion == 0 && maxVersion == 0)
		return true;

	var version = parseFloat(matches[1]);

	if (minVersion != 0 && version < minVersion)
		return false;
	else if (maxVersion != 0 && version > maxVersion)
		return false;

	return true;
}

function canBrowserAutoDownload() {
	return !this.isIE();
}

function addBackgroundRadiusCss(element, radius, color) {
	if (element.style.borderRadius !== undefined || element.style.WebkitBorderRadius !== undefined || element.style.MozBorderRadius !== undefined) {
		element.style.backgroundColor = "#" + color;
		element.style.borderRadius = element.style.WebkitBorderRadius = element.style.MozBorderRadius = radius + "px";
	} else {
		var bounds = Sys.UI.DomElement.getBounds(element);
		element.style.backgroundImage = "url(RoundedRectangle.axd?Width=" + bounds.width + "&Height=" + bounds.height + "&Radius=" + radius + "&FillColor=" + color + ")";
		element.style.backgroundRepeat = "no-repeat";
	}
}
