
var ujamServerSelector = function()
{

	var	loader,
	req,
	t,
	count = 10,
	currentCount = 0,
	pingURLs = [],
	serverURLs = [],
	currentPingURLKey,
	currentPingURLIndex,
	pingRegions = [],
	pingSum = [],
	pingAvg = [],
	bestServerURL,
	skipFirstPing,
	sampleFile = "latencycheck.js",
	availableServerURLs = clientVars.audioServers,
	COOKIE_NAME = "server_selection",
	debug_mode = 0,
	open_pings = [],
	mode,
	currentCountSCT = 0,
	open_pingsSCT = [],
	availableServers = [],
	availability_ping_timeout = 3000;


	return {

		init : function(testing_mode, _debug_mode)
		{
			jQuery("body").bind("SERVER_PING_COMPLETE", onServerPingComplete);
			jQuery("body").bind("ALL_PINGS_COMPLETE", onAllPingsComplete);
			jQuery("body").bind("SERVER_SELECTION_COMPLETE", onServerSelectionComplete);
			jQuery("body").bind("SERVER_SELECTION_ALL_DOWN", onAllServersDown);
			setTestingMode(testing_mode);
			debug_mode = _debug_mode;

			var serverURL;
			var key;
			var index = 0;
			for(key in availableServerURLs) {
				serverURL = availableServerURLs[key];
				if (serverURL) { // mj: skip empty entries (to avoid IE-SOP error)
					var domain = serverURL.split("/")[0].split(":")[0];
					pingURL = clientVars.protocol + "://" + domain + "/" + sampleFile;
					pingURLs[key] = pingURL;
					serverURLs[key] = serverURL;
					pingRegions[index] = key;
					index++;
				}

			}
		},
		performServerSelection : performServerSelection,
		getCookieName: function()
		{
			return COOKIE_NAME;
		},
		getAvailableServers : function() {
			return availableServers;
		},
		tryLogging : tryLogging,
		setBestServerURL : setBestServerURL,
		checkForTimeout : checkForTimeout,
		onSinglePingComplete : onSinglePingComplete,
		setOpenServerSelectPopupAllServersDown : setOpenServerSelectPopupAllServersDown,
		checkConnectionToServer : checkConnectionToServer,
		checkForTimeoutSCT : checkForTimeoutSCT,
		checkAvailableServers : checkAvailableServers,
		checkForTimeoutAvailability : checkForTimeoutAvailability
	};

	function setTestingMode(testing_mode)
	{
		if(testing_mode) {
			COOKIE_NAME = "server_selection_testing_" + clientVars.revision;
		} else {
			COOKIE_NAME = "server_selection_" + clientVars.revision;
		}
	}

	function performServerSelection(_mode)
	{
		currentCount = 0;
		currentPingURLIndex = 0;
		pingSum = [];
		pingAvg = [];
		mode = "server_selection" + _mode;
		open_pings = [];
		//always ping servers (even if only one available) to check if servers are down
		performNextPing();

	}

	function performNextPing()
	{
		//only ping currentURL if availability check has not been done or server has been collected in availableServers during availabilityCheck
		if(Object.size(availableServers) == 0 || availableServers[pingRegions[currentPingURLIndex]]) {
			dt = new Date();
			var pingUrl = pingURLs[pingRegions[currentPingURLIndex]];
			if(!pingUrl) { // skip empty entries (to avoid IE-SOP error)
				tryLogging("Skip pinging empty entry, marking as timed out instead.");
				onServerPingTimedOut();
			} else {
				var requestURL = pingURLs[pingRegions[currentPingURLIndex]] + "?" + dt.getTime();
				tryLogging("Pinging file " + requestURL);
				t = new Date();
				var ping_id = pingURLs[pingRegions[currentPingURLIndex]] + "_" + currentCount;
				open_pings[ping_id] = true;
				jQuery.getScript(requestURL, onSinglePingCompleteVoid);

				window.setTimeout("ujamServerSelector.checkForTimeout('" + ping_id + "')", 10000);
			}
		} else {
			//server has not been collected in availableServers during availabilityCheck
			//therefore skip pinging and treat ping as timed out
			var requestURL = pingURLs[pingRegions[currentPingURLIndex]];
			tryLogging("Skip pinging file " + requestURL + ", marking as timed out instead.");
			onServerPingTimedOut();
		}

	}

	function checkForTimeout(_ping_id) {
		if(open_pings[_ping_id]) {
			tryLogging("Ping for " + _ping_id + " timed out.");
			onServerPingTimedOut();
		}
	}

	function onSinglePingComplete()
	{
		var test = mode;
		if (mode == "server_selection" || mode == "server_selection_after_connection_test") {
			var dt = new Date();
			var timeElapsed = dt - t;
			open_pings[pingURLs[pingRegions[currentPingURLIndex]] + "_" + currentCount] = false;
			tryLogging("Server: " + pingURLs[pingRegions[currentPingURLIndex]] + "-" + timeElapsed / 1000 + 'ms');
			if(currentCount > 0) {
				pingSum[pingRegions[currentPingURLIndex]] = (null != pingSum[pingRegions[currentPingURLIndex]]) ? pingSum[pingRegions[currentPingURLIndex]] + timeElapsed : 0;
			}
			else {
				tryLogging("First server ping was skipped");
			}
			currentCount++;

			if (currentCount < count) {
				performNextPing();
			} else {
				currentCount = 0;
				jQuery("body").trigger(jQuery.Event("SERVER_PING_COMPLETE"));
			}
		} else if(mode == "server_connection_test") {
			//pinging for sct was successfull
			open_pingsSCT["sct_" + currentCountSCT] = false;
			onServerConnectionTestSuccess();
		} else if(mode == "availability_test") {
			//availability ping was successfull
			onAvailabilityPingSuccess();
		}
	}
	/**
	 * Use this void function as success-callback to performNextPing()
	 * when a call to onSinglePingComplete() is included in "latencycheck.js",
	 * the requested script from the server that has been pinged
	 */
	function onSinglePingCompleteVoid()
	{
		var test = 'foo';
	}

	function onServerPingComplete()
	{
		var avgCount = count - 1;
		pingAvg[pingRegions[currentPingURLIndex]] = pingSum[pingRegions[currentPingURLIndex]] / avgCount;
		tryLogging("Avg for " + pingURLs[pingRegions[currentPingURLIndex]] + ":" + pingAvg[pingRegions[currentPingURLIndex]]);
		if (currentPingURLIndex < Object.size(pingURLs) - 1) {
			currentPingURLIndex++;
			performNextPing();
		} else {
			jQuery("body").trigger(jQuery.Event("ALL_PINGS_COMPLETE"));
		}
	}

	function onServerPingTimedOut()
	{
		pingAvg[pingRegions[currentPingURLIndex]] = 1000000;
		tryLogging("Avg for " + pingURLs[pingRegions[currentPingURLIndex]] + ":" + pingAvg[pingRegions[currentPingURLIndex]]);
		if (currentPingURLIndex < Object.size(pingURLs.length) - 1) {
			currentPingURLIndex++;
			currentCount = 0;
			performNextPing();
		} else {
			jQuery("body").trigger(jQuery.Event("ALL_PINGS_COMPLETE"));
		}
	}

	function onAllPingsComplete()
	{
		var min = 1000000;
		var minIndex = 0;
		var allServersDown = true;
		var index = 0;
		for(var key in pingAvg) {
			var avg = pingAvg[key];
			if(avg < min) {
				min = avg;
				minIndex = index;
				allServersDown = false;
			}
			index++;
		}

		if(allServersDown)
			jQuery("body").trigger(jQuery.Event("SERVER_SELECTION_ALL_DOWN"));
		else {
			bestServerURL = serverURLs[pingRegions[minIndex]];
			jQuery("body").trigger(jQuery.Event("SERVER_SELECTION_COMPLETE"));
		}
	}

	function onServerSelectionComplete()
	{
		tryLogging("Best server is: " + bestServerURL);
		// store bestServerURL in cookie
		jQuery.cookie(COOKIE_NAME, bestServerURL, {path: '/', expires: 7});
		if(mode == "server_selection_after_connection_test") {
			//page reload
			location.reload();
		}
	}

	function setBestServerURL(_bestServerURL)
	{
		bestServerURL = _bestServerURL;
		tryLogging("Manually set best server to: " + bestServerURL);
		// store bestServerURL in cookie
		jQuery.cookie(COOKIE_NAME, bestServerURL, {path: '/', expires: 7});
	}

	function tryLogging(message) {
		if(debug_mode && window.console && console.log) {
			console.log(message);
		}
	}

	function onAllServersDown() {
		if(debug_mode && window.console && console.log) {
			console.log('All servers down.');
		}
		jQuery.cookie(COOKIE_NAME, 'all_servers_down', {path: '/', expires: 1});
		if(mode == "server_selection_after_connection_test") {
			//page reload
			location.reload();
		}
	}

	function setOpenServerSelectPopupAllServersDown() {
		var link = jQuery('#openServerSelectPopup');
		if(link.length) {
			link.html('MORE INFO');
		}
	}

	/*--------------- functions for ServerConnectionTest (SCT) -------------------*/

	function checkConnectionToServer() {
		if(jQuery.cookie(COOKIE_NAME) && jQuery.cookie(COOKIE_NAME) != 'all_servers_down') {
			jQuery('#ujamApplication').remove();
			performServerConnectionTest();
		}
	}

	function performServerConnectionTest() {
		currentCountSCT = 0;
		open_pingsSCT = [];
		mode = "server_connection_test";
		bestServerURL = jQuery.cookie(COOKIE_NAME);
		var connectionInProgressMessage = jQuery("#testingServerConnectionInProgress");
		if(connectionInProgressMessage) {
			connectionInProgressMessage.find("span").append(bestServerURL);
			jQuery("#testingServerConnectionInProgress").show();
		}
		performNextPingSCT();
	}

	function performNextPingSCT()
	{
		dt = new Date();
		var domain = bestServerURL.split("/")[0].split(":")[0];
		var pingURL = clientVars.protocol + "://" + domain + "/" + sampleFile;
		var requestURL = pingURL + "?" + dt.getTime();
		tryLogging("Pinging file " + requestURL);
		var ping_id = "sct_" + currentCountSCT;
		open_pingsSCT[ping_id] = true;
		jQuery.getScript(requestURL, onSinglePingCompleteVoid);

		window.setTimeout("ujamServerSelector.checkForTimeoutSCT('" + ping_id + "')", clientVars.sctPingTimeout);

	}

	function checkForTimeoutSCT(_ping_id) {
		if(open_pingsSCT[_ping_id]) {
			tryLogging("Ping for " + _ping_id + " timed out.");
			onSCTPingTimedOut();
		}
	}

	function onSCTPingTimedOut()
	{
		if (currentCountSCT < clientVars.sctPingRetries) {
			currentCountSCT++;
			performNextPingSCT();
		} else {
			// all pings timed out,
			onServerConnectionTestError();
		}
	}

	function onServerConnectionTestSuccess() {
		jQuery("#testingServerConnectionInProgress").hide();
		//display message "RTMP port unavailable or unknown network problem"
		showMessageBox('rtmp_port_unavailable');
	}

	function onServerConnectionTestError() {
		jQuery("#testingServerConnectionInProgress").hide();
		//trigger auto-location (ServerSelection)
		jQuery("body").trigger(jQuery.Event("SET_LOADING"));
		jQuery("#relocatingInProgress").show();
		performServerSelection('_after_connection_test');
	}

	/* ------------- functions for Server Availability Check ----------------- */

	function checkAvailableServers() {
		availableServers = [];
		currentPingURLIndex = 0;
		open_pings = [];
		mode = "availability_test";
		performNextAvailabilityPing();
	}

	function performNextAvailabilityPing() {
		dt = new Date();
		var pingUrl = pingURLs[pingRegions[currentPingURLIndex]];
		if(pingUrl.length == 0) { // skip empty entries (to avoid IE-SOP error)
			tryLogging("Skip pinging empty entry for availability, marking as timed out instead.");
			onAvailabilityPingTimedOut();
		} else {
			var requestURL = pingURLs[pingRegions[currentPingURLIndex]] + "?" + dt.getTime();
			tryLogging("Pinging file " + requestURL);
			var ping_id = pingURLs[pingRegions[currentPingURLIndex]];
			open_pings[ping_id] = true;
			jQuery.getScript(requestURL, onSinglePingCompleteVoid);

			window.setTimeout("ujamServerSelector.checkForTimeoutAvailability('" + ping_id + "')", availability_ping_timeout);
		}
	}

	function checkForTimeoutAvailability(_ping_id) {
		if(open_pings[_ping_id]) {
			tryLogging("Ping for " + _ping_id + " timed out.");
			onAvailabilityPingTimedOut();
		}
	}

	function onAvailabilityPingTimedOut() {
		if(currentPingURLIndex < Object.size(pingURLs) - 1) {
			currentPingURLIndex++;
			performNextAvailabilityPing();
		} else {
			onAllAvailabilityPingsComplete();
		}
	}

	function onAvailabilityPingSuccess() {
		var ping_id = pingURLs[pingRegions[currentPingURLIndex]];
		open_pings[ping_id] = false;
		availableServers[pingRegions[currentPingURLIndex]] = ping_id;
		if(currentPingURLIndex < Object.size(pingURLs) - 1) {
			currentPingURLIndex++;
			performNextAvailabilityPing();
		} else {
			onAllAvailabilityPingsComplete();
		}
	}

	function onAllAvailabilityPingsComplete() {

		if(Object.size(availableServers) == 0) {
			jQuery("body").trigger(jQuery.Event("SERVER_SELECTION_ALL_DOWN"));
		}
		jQuery("body").trigger(jQuery.Event("CHECK_AVAILABLE_SERVERS_COMPLETE"));
	}

}();

function getBestServerURL() {
	return jQuery.cookie(ujamServerSelector.getCookieName()) ? jQuery.cookie(ujamServerSelector.getCookieName()) : "";
}

function onClientConnectionFailed() {
	ujamServerSelector.checkConnectionToServer();
}

function arrayContains(_array, item) {
	for(var i=0; i < _array.length; i++) {
		if (_array[i] == item) {
			return true;
		}
	}
	return false;
}

Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

Object.contains = function(obj, needle) {
    var key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)){
        	if(obj[key] == needle) return true;
        }
    }
    return false;
};



jQuery(document).ready(function() {
	ujamServerSelector.init(clientVars.testingMode, clientVars.debugMode);

	if(jQuery.cookie(ujamServerSelector.getCookieName()) && Object.contains(clientVars.audioServers, jQuery.cookie(ujamServerSelector.getCookieName()))) {
		var bestServerURL = jQuery.cookie(ujamServerSelector.getCookieName());
		if(bestServerURL == 'all_servers_down') {
			ujamServerSelector.setOpenServerSelectPopupAllServersDown();
			//retry pinging servers
			ujamServerSelector.performServerSelection('');
		} else {
			ujamServerSelector.tryLogging("Tada! Cookie found. Use Server '" + bestServerURL + "' from cookie.");
			// renew cookie expires timestamp
			jQuery.cookie(ujamServerSelector.getCookieName(), bestServerURL, {path: '/', expires: 7});
		}
	} else {
		ujamServerSelector.tryLogging("No Cookie found. Ping for selection of best server.");
		ujamServerSelector.performServerSelection('');
	}
});
