/*
 * $Header: /Engine/session.js   12   2004-07-27 08:47:24+02:00   eruis $
 * Created on:      24-November-2003
 * Original author: Eric Ruis
 *
 * Description:
 * 	Manages the storing and retrieving of named variables in a session cookie. The names of individual variables
 * 	are hashed. The resulting hash is then encoded using a 62 entry encoding table which results in a variable name
 * 	with a maximum length of about 4 to 5 characters.
 */
// Shorten a variable name by hashing it to a maximum of 4 to 5 digits.
function session_hashName(name) {
	if (name == null) return name;

	// the calculated hash strings are cached in this.name2HashList
	if (this.name2HashList[name] != null)
		return this.name2HashList[name];

	// PJW hash. Takes about 4,5 karakters per name when encoded using the ENCTABLE alpanumeric character set.
	var h = 0;
	for (var j = 0; j < name.length; j++) {
		h = (h << 4) + name.charCodeAt(j);
		g = h & 0xf0000000;
		if (g != 0) {
			h = h ^ (g >> 24);
			h = h ^ g;
		}
	}
	h = h % 101483; // the number of buckets to use
	// separate the negative and positive parts
	var pn = Math.abs(h)/h;
	h = Math.abs(h);
	var hn = String(pn);

	// calculate the highest factor required for the encoding of the hash
	var p = h, fmax = 0;
	while (p > 0) { p = parseInt(p / this.ENCTABLE.length); if (p > 0) fmax++; }

	// convert the hash number to our custom number system with 'this.ENCTABLE.length' different characters
	// (the hexadecimal system for example has 16 characters)
	var fp = h + 1; // guarantees that the first % operation delivers h
	for (var i = fmax; i >= 0; i--) {
		var fn = Math.pow(this.ENCTABLE.length, i);
		c = parseInt((h % fp) / fn);
		fp = fn;
		hn += this.ENCTABLE.charAt(c);
	}

	// Find possible duplicate hashes within a page
	var listName = this.hash2NameList[hn];
	if (listName != null && listName != name) alert("hash failure on " + name + ". Clash with " + listName);
	this.hash2NameList[hn] = name;

	// make sure that we always use the shortest string to identify the variable and cache the calculated hash string
	var result = hn;
	if (name.length < hn.length)
		result = name;
	this.name2HashList[name] = result;

	debugWindow.writeln("session_hashName: h(" + name + ")=" + result);

	return result;
}

function session_getCookieContents() {
	var search = this.nameCookie;
	var returnvalue = "";

	var stateContents = window.top.frames.item(0).document.getElementById( "bodyState" );

	if (stateContents.innerHTML.length > 0) {
		offset = stateContents.innerHTML.indexOf(search);
		// if cookie exists
		if (offset != -1) {
    			offset += search.length;
	      		// set index of beginning of value
    	  		end = stateContents.innerHTML.indexOf(";", offset);
	      		// set index of end of cookie value
    	  		if (end == -1)
    	  			end = stateContents.innerHTML.length;

	      		returnvalue = stateContents.innerHTML.substring(offset, end);
      		}
   	}
 	return returnvalue;
}

function session_getVariable(name) {
	var content = unescape(this.getCookieContents());
	debugWindow.writeln("session_getVariable: getting '" + name + "'");

	// get the hashed name
	name = 	this.hashName(name);
	var search = name + "&";
	var returnvalue = "";

	if (content.length > 0) {
		offset = content.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = content.indexOf(this.varEndChar, offset);
			if (end == -1)
				end = content.length;
			returnvalue = session_unescape(content.substr(offset, end - offset));
		}
	}
	return returnvalue;
}

function session_unescape(value) {
	debugWindow.writeln("session_unescape: unescaping value '" + value + "'");

	var escapeStr = "%35";
	var searchEndChar = this.varEndChar;

	// make sure that we're dealing with a string
	value = String(value);

	offset = value.indexOf(escapeStr);
	while (offset != -1) {
		value = value.substr(0, offset) + this.varEndChar + value.substr(offset + escapeStr.length, value.length);
		offset = value.indexOf(escapeStr, offset + searchEndChar.length);
	}

	return value;
}

function session_escape(value) {
	debugWindow.writeln("session_escape: escaping value = '" + value + "'");

	var escapeStr = "%35";
	var searchEndChar = this.varEndChar;

	// make sure that we're dealing with a string
	value = String(value);

	offset = value.indexOf(searchEndChar);
	while (offset != -1) {
		// escape the character
		value = value.substr(0, offset) + escapeStr + value.substr(offset + searchEndChar.length, value.length);
		offset = value.indexOf(searchEndChar, offset + escapeStr.length);
	}

	return value;
}

function session_addVariable(name, value) {
	debugWindow.writeln("session_addVariable: adding " + name + " with value " + value);

	var stateContents = window.top.frames.item(0).document.getElementById( "bodyState" );

	// Do not store empty values to conserve space
	if (value == null || String(value) == "")
		return;

	// convert to a string
	value = "" + value;

	if (value != "") {
		var content = unescape(this.getCookieContents());

		// shorten the name by hashing it
		var namevaluepair = this.hashName(name) + "&" + session_escape(value);
		if (content == "")
			content = namevaluepair;
		else
			content = content + this.varEndChar + namevaluepair;

		var newcontents = this.nameCookie + escape(content);
		//if (newcontents.length > 4050)
		//	alert("maximum session storage capacity reached. Please delete some information from the pages.");
		//else
			stateContents.innerHTML = this.nameCookie + escape(content);
	}
}

function session_updateVariable(name, value) {

    var stateContents = window.top.frames.item(0).document.getElementById( "bodyState" );

	// Do not store empty values to conserve space
	if (value == null || String(value) == "") {
		this.removeVariable(name);
		return;
	}
	//alert("updating " + name + " with value " + value + ". Size of the hashed name " + this.hashName(name).length);

	var content = unescape(this.getCookieContents());
	debugWindow.writeln("session_updateVariable: search name '" + name + "'");

	// shorten the name by hashing it
	var search = this.hashName(name) + "&";

	if (content.length > 0) {
		offset = content.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = content.indexOf(this.varEndChar, offset);
			if (end == -1)
				end = content.length;
			content = content.substr(0, offset) + session_escape(value) + content.substr(end, content.length);

			var newcontents = this.nameCookie + escape(content);
			//if (newcontents.length > 4050)
			//	alert("maximum session storage capacity reached. Please delete some information from the pages.");
			//else
				stateContents.innerHTML = this.nameCookie + escape(content);
		}
		else {
			debugWindow.writeln("session_updateVariable: variable not found in cookie content");
			this.addVariable(name, value);
		}
	}
	else {
		debugWindow.writeln("session_updateVariable: cookie contents are still empty");
		this.addVariable(name, value);
	}
}

function session_removeVariable(name) {
	var content = unescape(this.getCookieContents());

	debugWindow.writeln("session_removeVariable: search name '" + name + "'");

	var stateContents = window.top.frames.item(0).document.getElementById( "bodyState" );

	// shorten the name by hashing it
	var search = this.hashName(name) + "&";

	if (content.length > 0) {
		offset = content.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = content.indexOf(this.varEndChar, offset);
			if (end == -1)
				end = content.length;
			offset -= search.length;
			content = content.substr(0, offset) + content.substr(end + 1, content.length);

			// remove the end-of-variable character when it is the last character in the string.
			if (content.indexOf(this.varEndChar, content.length - 1) == content.length - 1)
				content = content.substr(0, content.length - 1);
			stateContents.innerHTML = this.nameCookie + escape(content);
		}
		else {
			debugWindow.writeln("session_removeVariable: variable not found in cookie contents");
		}
	}
	else {
		debugWindow.writeln("session_removeVariable: Nothing to do. Cookie contents are empty.");
	}
}

function session_reset() {
	var stateContents = window.top.frames.item(0).document.getElementById( "bodyState" );

	stateContents.innerHTML = this.nameCookie;
}

function session_areCookiesEnabled() {
	var testname = "testcookie";
	var testvalue = "value";

	this.addVariable(testname, testvalue);
	if (this.getVariable(testname) != testvalue)
		return false;
	this.removeVariable(testname);
	return true;
}

function session_setCookieName(currencySymbol) {
	this.nameCookie = "rc" + currencySymbol.trim() + "=";
	debugWindow.writeln("session_setCookieName: cookie name is '" + this.nameCookie + "'");
}

function session_initialize(currencySymbol) {
	// loose the white space in the currency symbol
	session_setCookieName(currencySymbol);
}

function session_initializeFromURL(URL) {
	var search = "cs="
	offset = URL.indexOf(search);
	if (offset != -1) {
		// currency symbol defined
		offset += search.length;
		end = URL.indexOf("&", offset);
		if (end == -1)
			end = URL.length;
		session_setCookieName(URL.substr(offset, end));
		return true;
	}

	return false;
}

function session_setup() {
	this.hash2NameList = {};
	this.ENCTABLE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	this.name2HashList = {};
	this.varEndChar = "#";
	this.nameVarSeparatorChar = "&";

	this.getVariable = session_getVariable;
	this.addVariable = session_addVariable;
	this.removeVariable = session_removeVariable;
	this.updateVariable = session_updateVariable;
	this.areCookiesEnabled = session_areCookiesEnabled;
	this.getCookieContents = session_getCookieContents;
	this.initializeFromURL = session_initializeFromURL;
	this.initialize = session_initialize;
	this.reset = session_reset;
	this.hashName = session_hashName;

	return this;
}


var calcSession = new Object();
calcSession = session_setup();