/*******************************************************************************
 * 
 * Author: Justin Samuel <justin /at/ justinsamuel /dot/ com>
 * Date: 2008-04-25
 * License: GPL
 * 
 * Provides communication with the server to obtain and displaystatistics on the
 * distributed key search.
 * 
 * This file relies on:
 * + descrack_util.js
 * + descrack_ui.js
 * 
 ******************************************************************************/

var overallHttpRequest; // the current XMLoverallHttpRequest object
var overallClientVersion = '1.0'; // the communication api version of this client
var overallServerUrl; // url of directory on server where descrack application resides
var overallResponse; // parsed response from server

var overallStatsRefreshRate = 15; // how often to refresh stats, in seconds

/*
 * Make a request for stats.
 */
function requestStats() {
	try {
		if (overallHttpRequest) {
			overallHttpRequest.abort();
		}
        if (overallServerUrl == undefined) {
            overallServerUrl = dirname(location.href);
        }
        overallCommStatus(true);
		queryString = 'clientVersion=' + overallClientVersion;
		overallHttpRequest = createXHR(handleStatsResponse);
		overallHttpRequest.open('GET', overallServerUrl + '/stats/all?'
				+ queryString, true);
		overallHttpRequest.send(null);
	} catch (e) {
		handleException(e);
	}
}

/*
 * Handles the response received from a request for stats.
 */
function handleStatsResponse() {
	try {
		if (overallHttpRequest.readyState == 4) {
			setTimeout('requestStats()', 1000 * overallStatsRefreshRate);
			// the response has been received
			overallCommStatus(true);
			if (overallHttpRequest.status == 200) {
				overallResponse = JSON.parse(overallHttpRequest.responseText);
				if (typeof overallResponse === 'string') {
					// we got a message string back rather than a response that
					// tells us what keys to check, so we stop and display the
					// message.
					overallStatus("Server said: " + overallResponse);
					clearOverallStats();
					overallCommStatus(false);
				} else {
					log("Raw overall stats response from server: " + overallHttpRequest.responseText);
					overallCommStatus(false);
					updateOverallStats();
				}
			} else {
				overallStatus("Did not understand response from server. Trying again.");
				overallCommStatus(false);
				clearOverallStats();
				log("Server status: " + overallHttpRequest.status);
				log("Server response: " + overallHttpRequest.response);
			}
		}
	} catch (e) {
		overallStatus("Communication error. Trying again.");
		overallCommStatus(false);
		clearOverallStats();
		if (DOMException && e.code == DOMException.INVALID_STATE_ERR) {
			// pass. Opera is wacky. And IE doesn't even have a DOMException, it
			// seems. This is exactly why one isn't supposed to code one's own
			// xhr communication, but use an ajax library instead.
		} else {
			handleException(e);
		}
	}
}

function overallStatus(text) {
    overallStatusDiv.innerHTML = text;
}

function overallCommStatus(isCommunicating) {
    if (isCommunicating) {
        overallCommStatusDiv.innerHTML = 'Communicating...';
    } else {
        overallCommStatusDiv.innerHTML = '<br />';
    }
}

function clearOverallStats() {
	overallStatsDiv.innerHTML = '';
}

function updateOverallStats() {
	var currentSessions = overallResponse.currentSessions;
	var expiredSessions = overallResponse.expiredSessions;
	
    var text = '';
	text += 'Plaintext: ' + overallResponse.plaintext + " (<tt>"
	     + decByteToHexString(overallResponse.plaintext) + "</tt>)<br />";
    text += 'Ciphertext: ' + overallResponse.ciphertext + " (<tt>"
         + decByteToHexString(overallResponse.ciphertext) + "</tt>)<br />";
    text += 'Number of possible keys: 2<sup>56</sup> = 72057594037927936<br />';
    var keysPerRange = overallResponse.byteRange / 2 * 128;
	text += 'Number of keys in each range clients test: ' + keysPerRange + "<br />";
	overallStatus(text);

	text = '';
	if (overallResponse.keyFound) {
		text += '<b>Key has been found: ' + overallResponse.key + "</b><br />";
		des_setparity(overallResponse.key);
		text += 'Key in hex with parity bits set: <tt>' + decByteToHexString(overallResponse.key) + "</tt><br />";
		text += 'Key was found at: ' + overallResponse.keyFoundTime + "<br />";
	} else {
		text += 'Key has not been found.' + "<br />";
	}
	
    text += 'Current unique IP addresses: '
         + overallResponse.currentUniqueAddressCount + "<br />";
    text += 'Past unique IP addresses: '
         + overallResponse.expiredUniqueAddressCount + "<br />"; 
         
    text += 'Current browser sessions: '
         + currentSessions.length + "<br />";
    text += 'Past browser sessions: '
         + expiredSessions.length + "<br />"; 
         
    var totalCurrentRangesTested = 0;
    for (i = 0; i < currentSessions.length; i++) {
    	totalCurrentRangesTested += parseInt(currentSessions[i]['rangesProcessed']);
    }
    avgKeysPerCurrentSession = currentSessions.length > 0 ? 
        totalCurrentRangesTested * keysPerRange / currentSessions.length : 0;
    var totalPastRangesTested = 0;
    for (i = 0; i < expiredSessions.length; i++) {
        totalPastRangesTested +=parseInt(expiredSessions[i]['rangesProcessed']);
    }
    avgKeysPerPastSession = expiredSessions.length > 0 ? 
        totalPastRangesTested * keysPerRange / expiredSessions.length : 0;
    text += 'Current avg. keys tested per session: '
         + Math.floor(avgKeysPerCurrentSession) + "<br />";
    text += 'Past avg. keys tested per session: '
         + Math.floor(avgKeysPerPastSession) + "<br />";
    
    overallStatsDiv.innerHTML = text;
}

