var CURRENT_PAGE = null;
var COMMAND_DISPATCHER = null;
var SEARCH_SHOWING = false;
var SEARCH_RESULTS = false;

CommandDispatcher = function() {

	var commandMap = new Map();
	var requestNo = 0;

	this.execute = function(command) {
		var no = requestNo++;
		// map the command
		commandMap.put(new String(no), command);
		var topicMessage = command.getTopicMessage(no);
		DiffusionClient.sendTopicMessage(topicMessage);
	}

	this.listener = function(webClientMessage) {
		var no = webClientMessage.getUserHeader(0);

		// get command
		var command = commandMap.get(new String(no));
		commandMap.remove(new String(no))
		command.handleResponse(webClientMessage);
	}
}

DiffusionConnector = new function() {

	this.tryingAReconnect = false;

	this.onLostConnectionFunction = function() {
		DiffusionConnector.tryingAReconnect = true;
		DiffusionConnector.connectToDiffusion();
		DiffusionClient.trace("Connection lost trying to reconnect.");
	}

	this.onAbortFunction = function() {
		alert('Your session has been terminated.');
	}

	this.onInvalidClientFunction = function() {
		DiffusionClient.trace("Invalid client function occured");
	}

	this.onCallbackFunction = function(connected) {
		if (!connected) {
			if (DiffusionConnector.tryingAReconnect == true) {
				alert("Your connection to Diffusion has been lost.")
			} else {
				alert('Unable to connect the Diffusion server.');
			}
		} else {
			if (COMMAND_DISPATCHER == null) {
				COMMAND_DISPATCHER = new CommandDispatcher();
				DiffusionClient.addTopicListener("^COMMAND$",
						COMMAND_DISPATCHER.listener);

			}
			DiffusionConnector.tryingAReconnect = false;
		}
	}

	this.connectToDiffusion = function() {
		
		DiffusionClient.addTopicListener("^brc-page$", loadCalc);
		DiffusionClient.addTopicListener("^MiniTrade$", processMiniTrade);
		DiffusionClient.addTopicListener("page", processPageLoad);
		DiffusionClient.addTopicListener("^News$", processNewsLoad);
		
		// DiffusionClient.setDebugging(true);
		
		// If you are interested on how this works, then why not drop me an
		// email
		// dhudson@pushtechnology.com
		DiffusionClient
				.connect( {
					topic : "COMMAND,News," + CURRENT_PAGE,
					onDataFunction : DiffusionConnector.onDataEvent,
					flashPort : 443,
					onLostConnectionFunction : DiffusionConnector.onLostConnectionFunction,
					onAbortFunction : DiffusionConnector.onAbortFunction,
					onInvalidClientFunction : DiffusionConnector.onInvalidClientFunction,
					onCallbackFunction : DiffusionConnector.onCallbackFunction,
					libPath : "/js/lib/DIFFUSION"
				});
	}

	this.onDataEvent = function(webClientMessage) {
		// Empty due to topic listeners
	}
}

// JavaScript Document
function resetRows() {
	// Reset row background colours
	for ( var i = 0; i < 8; i++) {
		var tr = document.getElementById(i);
		if (tr) {
			tr.style.backgroundColor = 'transparent';
			tr.cells[2].style.backgroundColor = 'transparent';
		}
	}
}

function processNewsLoad(webClientMessage) {
	var _news = document.getElementById("news");
	var data = webClientMessage.getFields(0);
	_news.innerHTML = data;
}

function processMiniTrade(webClientMessage) {

	if (webClientMessage.isInitialTopicLoad()) {
		resetRows();
		for ( var i = 0; i < webClientMessage.getNumberOfRecords(); i++) {
			var data = webClientMessage.getFields(i);
			var tr = document.getElementById(i);
			tr.cells[0].innerHTML = data[0];
			tr.cells[2].innerHTML = data[1];
			tr.cells[3].innerHTML = data[2];
			tr.cells[4].innerHTML = data[3];
			tr.cells[6].innerHTML = data[4];
			tr.cells[7].innerHTML = data[5];

			if (data[3] > 0) {
				tr.cells[5].className = 'priceUp';
			} else {
				tr.cells[5].className = 'priceDown';
			}

		}
	} else {
		for ( var i = 0; i < webClientMessage.getNumberOfRecords(); i++) {
			var data = webClientMessage.getFields(i);
			var tr = document.getElementById(data[0]);
			var netChange = data[3];
			var oldValue = parseInt(tr.cells[2].innerHTML);

			// Process row change
			tr.cells[2].innerHTML = data[1];
			tr.cells[3].innerHTML = data[2];
			tr.cells[4].innerHTML = netChange;
			tr.cells[6].innerHTML = data[4];
			tr.cells[7].innerHTML = data[5];

			var imageCell = tr.cells[5];

			if (oldValue > data[1]) {
				tr.cells[2].style.backgroundColor = 'red';
				imageCell.className = 'priceDown';
			} else {
				tr.cells[2].style.backgroundColor = '#00B5EF';
				imageCell.className = 'priceUp';
			}
		}
		setTimeout("resetRows()", 1500);
	}
}

function processPageLoad(webClientMessage) {
	var fields = webClientMessage.getFields(0);

	var divToShow = webClientMessage.getTopic() == "home-page" ? "home-page-content"
			: "content";
	var divToUse = webClientMessage.getTopic() == "home-page" ? "home-page-content"
			: "copySub";
	var divToHide = webClientMessage.getTopic() == "home-page" ? "content"
			: "home-page-content";

	if (webClientMessage.getTopic() != CURRENT_PAGE || SEARCH_SHOWING == true) {
		// change the html of the content div to field one

		document.getElementById(divToUse).innerHTML = fields[0];

		if (divToUse == "copySub") {
			// we need to set the titles and title image
			document.getElementById("pageTitle").innerHTML = fields[3];
			document.getElementById("pageHead").style.backgroundImage = "url("
					+ fields[4] + ")";
			document.getElementById("subMenu").innerHTML = fields[5];
		}

		if (SEARCH_SHOWING == true) {
			document.getElementById("searchResultsContent").style.display = "none";
			SEARCH_SHOWING = false;
		}
		document.getElementById(divToShow).style.display = "block";
		document.getElementById(divToHide).style.display = "none";

		if (fields[1] == "true") {
			// show news footer
			document.getElementById("latestNews").style.display = "block";
		} else {
			// hide footer
			document.getElementById("latestNews").style.display = "none";

		}

		document.getElementById("breadCrumb").innerHTML = fields[2];
	}

	CURRENT_PAGE = webClientMessage.getTopic();

	if (CURRENT_PAGE == "home-page") {
		// subscribe to mini trader demo
		DiffusionClient.subscribe("MiniTrade");
	}
}

function changePage(pageName, aObject) {

	try {
		if (aObject == null) {
			alert('You must pass in the anchor for this to work');
		}

		// unsubscribe from current page's topic
		if (CURRENT_PAGE) {
			DiffusionClient.unsubscribe(CURRENT_PAGE);
			if (CURRENT_PAGE == "home-page") {
				// unsubscribe to mini trader demo
				DiffusionClient.unsubscribe("MiniTrade");
			}

		}
		DiffusionClient.subscribe(pageName);
	} catch (e) {
		alert(e);
	}

	return false;
}

// menu functions
function showHide(id, show) {
	identity = document.getElementById(id);
	aIdentity = document.getElementById(id + "_a");
	if (document.getElementById("sub_1_a") != null) {
		document.getElementById("sub_1_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_1") != null) {
		document.getElementById("sub_1").style.display = "none";
	}
	if (document.getElementById("sub_2_a") != null) {
		document.getElementById("sub_2_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_2") != null) {
		document.getElementById("sub_2").style.display = "none";
	}
	if (document.getElementById("sub_3_a") != null) {
		document.getElementById("sub_3_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_3") != null) {
		document.getElementById("sub_3").style.display = "none";
	}
	if (document.getElementById("sub_4_a") != null) {
		document.getElementById("sub_4_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_4") != null) {
		document.getElementById("sub_4").style.display = "none";
	}
	if (document.getElementById("sub_5_a") != null) {
		document.getElementById("sub_5_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_5") != null) {
		document.getElementById("sub_5").style.display = "none";
	}
	if (document.getElementById("sub_6_a") != null) {
		document.getElementById("sub_6_a").style.backgroundColor = "#b7b8b8";
	}
	if (document.getElementById("sub_6") != null) {
		document.getElementById("sub_6").style.display = "none";
	}
	if (show) {
		if (identity != null) {
			identity.style.display = "block";
		}
		if (aIdentity != null) {
			aIdentity.style.backgroundColor = "#3c2415";
		}
	}
}

var HOME_MENU_ITEM = null;

function drawBreadcrumbs(pageTopic) {

	var breadcrumbHtml = '<img src="/images/homeWhite.gif" alt="Home" width="27" height="16" border="0" longdesc="/images/homeWhite.gif" />';

	// always add home
	breadcrumbHtml += "<a class='breadHome' href='" + homeMenuItem.url
			+ "' onclick=\"return changePage('" + HOME_MENU_ITEM.pageTopic
			+ "', this);\">" + HOME_MENU_ITEM.displayTitle + "</a>"

	if (pageTopic != 'home-page') {
		var breadcrumbs = new Array();
		for ( var i = 0; i < HOME_MENU_ITEM.children.length; i++) {
			var menuItem = HOME_MENU_ITEM.children[i];
			if (menuItem.pageTopic == pageTopic) {
				breadcrumbs[0] = menuItem;
			} else {
				if (menuItem.hasChildren) {
					for ( var j = 0; j < menuItem.children.length; j++) {
						var childMenuItem = menuItem.children[j];
						if (childMenuItem.pageTopic == pageTopic) {
							breadcrumbs[0] = menuItem;
							breadcrumbs[1] = childMenuItem;
							break;
						}
					}
				}
			}
			if (breadcrumbs.length > 0) {
				break;
			}
		}

		// add the breadcrumbs
		for ( var i = 0; i < breadcrumbs.length; i++) {
			var menuItem = breadcrumbs[i];
			breadcrumbHtml += "&gt;&nbsp;<a href='" + menuItem.url
					+ "' onclick=\"return changePage('" + menuItem.pageTopic
					+ "', this);\">" + menuItem.displayTitle + "</a>"
		}
	}

	document.getElementById("breadCrumb").innerHTML = breadcrumbHtml;
}

MenuItem = function(displayTitle, pageTopic, url, children) {
	this.displayTitle = displayTitle;
	this.pageTopic = pageTopic;
	this.url = url;
	this.children = children;

	this.hasChildren = function() {
		return (children != null && children.length > 0);
	}
}

function submitTrailForm() {

	// get the work email address
	var firstName = document.getElementById("trialFirstName").value;
	var lastName = document.getElementById("trialLastName").value;
	var workEmailAddress = document.getElementById("trialWorkEmail").value;
	var companyName = document.getElementById("companyName").value;
	if (!assert(firstName, "First Name") || !assert(lastName, "Last Name")
			|| !assert(workEmailAddress, "Work Email Addres")
			|| !assert(companyName, "Company Name")) {
		return;
	} else {

		var wantsMB = document.getElementById("messageBrokerProductCheck").checked;
		var wantsIMB = document
				.getElementById("internetMessageBrokerProductCheck").checked;
		var wantsAJE = document.getElementById("ajaxEngineBrokerProductCheck").checked;

		if (!wantsMB && !wantsIMB && !wantsAJE) {
			alert('Please select one or more products you would like a licence for');
		} else {
			var command = new RequestTrialKeyCommand(firstName, lastName,
					workEmailAddress, wantsMB, wantsIMB, wantsAJE, companyName);

			COMMAND_DISPATCHER.execute(command);
		}
	}
}

function submitDownloadDocument() {

	var firstName = document.getElementById("docDownloadFirstName").value;
	var lastName = document.getElementById("docDownloadLastName").value;
	var workEmailAddress = document.getElementById("docDownloadWorkEmail").value;

	if (!assert(firstName, "First Name") || !assert(lastName, "Last Name")
			|| !assert(workEmailAddress, "Work Email Addres")) {
		return;
	} else {
		var documentType = document.getElementById("docDownloadDocument").value;
		var command = new RequestDocumentDownloadCommand(firstName, lastName,
				workEmailAddress, documentType);
		COMMAND_DISPATCHER.execute(command);
	}
}

function submitSearchQuery() {
	var searchQuery = document.getElementById("searchText").value;
	if (!assert(searchQuery, "Search Query")) {
		return;
	} else {
		var command = new SearchCommand(searchQuery);
		COMMAND_DISPATCHER.execute(command);
	}
}
function assert(value, fieldName) {
	if (value == null || value.length == 0) {
		alert(fieldName + ' is a mandatory field and must be entered.');
		return false;
	} else {
		return true;
	}
}

SearchCommand = function(searchQuery) {

	var commandName = "SEARCH";
	var searchQuery = searchQuery;

	this.getTopicMessage = function(requestNo) {
		var message = new TopicMessage("COMMAND", searchQuery);
		message.addUserHeader(requestNo);
		message.addUserHeader(commandName);

		return message;
	}

	this.handleResponse = function(webClientMessage) {

		var state = webClientMessage.getFields(0)[0];

		var divToHide = (CURRENT_PAGE == "home-page") ? "home-page-content"
				: "content";

		if (state == "OK") {
			document.getElementById("searchResultsCopySub").innerHTML = "";

			var html = "";

			if (webClientMessage.getNumberOfRecords() > 1) {
				for ( var i = 1; i < webClientMessage.getNumberOfRecords(); i++) {
					var title = webClientMessage.getFields(i)[0];
					var topic = webClientMessage.getFields(i)[1];

					html += "<a href='#' onclick=\"return changePage('" + topic
							+ "',this)\">" + title + "</a>";
					html += "<br>";
					html += webClientMessage.getFields(i)[2];
					html += "<br>";
					html += "<br>";
				}

				document.getElementById("searchResultsCopySub").innerHTML = html;

			} else {
				document.getElementById("searchResultsCopySub").innerHTML = "No results, please try again";
			}

		} else {
			document.getElementById("searchResultsCopySub").innerHTML = "An error has occured ["
					+ webClientMessage.getFields(0)[1] + "], please try again";
		}
		document.getElementById(divToHide).style.display = "none";
		document.getElementById("searchResultsContent").style.display = "block";
		SEARCH_SHOWING = true;
	}
}

RequestDocumentDownloadCommand = function(firstName, lastName,
		workEmailAddress, documentName) {
	var commandName = "REQUEST_DOC_DOWNLOAD"
	var firstName = firstName;
	var lastName = lastName;
	var workEmailAddress = workEmailAddress;
	var documentName = documentName;

	this.getTopicMessage = function(requestNo) {
		var message = new TopicMessage("COMMAND", firstName + '#' + lastName
				+ '#' + workEmailAddress + '#' + documentName);
		message.addUserHeader(requestNo);
		message.addUserHeader(commandName);

		return message;
	}

	this.handleResponse = function(webClientMessage) {
		document.getElementById("docDownloadFormDiv").style.display = "none";
		document.getElementById("docDownloadDivResultMessage").style.display = "block";
	}

}

RequestTrialKeyCommand = function(firstName, lastName, workEmailAddress,
		wantsMB, wantsIMB, wantsAJE, companyName) {
	var commandName = "REQUEST_TRIAL_KEY";
	var firstName = firstName;
	var lastName = lastName;
	var workEmailAddress = workEmailAddress;
	var wantsMB = wantsMB;
	var wantsIMB = wantsIMB;
	var wantsAJE = wantsAJE;
	var companyName = companyName;

	this.getTopicMessage = function(requestNo) {
		var message = new TopicMessage("COMMAND", firstName + '#' + lastName
				+ '#' + workEmailAddress + '#' + companyName + '#'
				+ createProductInterestString());
		message.addUserHeader(requestNo);
		message.addUserHeader(commandName);

		return message;
	}

	this.handleResponse = function(webClientMessage) {
		// first field is the state
		var state = webClientMessage.getFields(0)[0];

		document.getElementById("trailFormDiv").style.display = "none";

		if (state == "OK") {
			document.getElementById("trailFormDivResultMessage").style.display = "block";
		} else {
			document.getElementById("trailFormDivResultMessageError").style.display = "block";
		}
	}

	var createProductInterestString = function() {
		var string = "";

		var moreThanZero = false;

		if (wantsMB == true) {
			string += "DIFFUSION_MESSAGE_BROKER";
			moreThanZero = true;
		}

		if (wantsIMB == true) {

			if (moreThanZero) {
				string += ',';
			}

			string += "DIFFUSION_INTERNET_MESSAGE_BROKER";
			moreThanZero = true;
		}

		if (wantsAJE == true) {

			if (moreThanZero) {
				string += ',';
			}

			string += "DIFFUSION_AJAX_ENGINE";
			moreThanZero = true;
		}

		return string;
	}
}

// linking the key-value-pairs is optional
// if no argument is provided, linkItems === undefined, i.e. !== false
// --> linking will be enabled
function Map(linkItems) {
	this.current = undefined;
	this.size = 0;

	if (linkItems === false)
		this.disableLinking();
}

Map.noop = function() {
	return this;
};

Map.illegal = function() {
	throw new Error("illegal operation for maps without linking");
};

// map initialisation from existing object
// doesn't add inherited properties if not explicitly instructed to:
// omitting foreignKeys means foreignKeys === undefined, i.e. == false
// --> inherited properties won't be added
Map.from = function(obj, foreignKeys) {
	var map = new Map;

	for ( var prop in obj) {
		if (foreignKeys || obj.hasOwnProperty(prop))
			map.put(prop, obj[prop]);
	}

	return map;
};

Map.prototype.disableLinking = function() {
	this.link = Map.noop;
	this.unlink = Map.noop;
	this.disableLinking = Map.noop;
	this.next = Map.illegal;
	this.key = Map.illegal;
	this.value = Map.illegal;
	this.removeAll = Map.illegal;

	return this;
};

// overwrite in Map instance if necessary
Map.prototype.hash = function(value) {
	return value;
	/*
	 * return (typeof value) + ' ' + (value instanceof Object ? (value.__hash ||
	 * (value.__hash = ++arguments.callee.current)) : value.toString());
	 */
};

Map.prototype.hash.current = 0;

// --- mapping functions

Map.prototype.get = function(key) {
	var item = this[this.hash(key)];
	return item === undefined ? undefined : item.value;
};

Map.prototype.put = function(key, value) {
	var hash = this.hash(key);
	if (this[hash] === undefined) {
		var item = {
			key : key,
			value : value
		};
		this[hash] = item;

		this.link(item);
		++this.size;
	} else
		this[hash].value = value;

	return this;
};

Map.prototype.remove = function(key) {
	var hash = this.hash(key);
	var item = this[hash];
	if (item !== undefined) {
		--this.size;
		this.unlink(item);

		delete this[hash];
	}

	return this;
};

// only works if linked
Map.prototype.removeAll = function() {
	while (this.size)
		this.remove(this.key());

	return this;
};

// --- linked list helper functions

Map.prototype.link = function(item) {
	if (this.size == 0) {
		item.prev = item;
		item.next = item;
		this.current = item;
	} else {
		item.prev = this.current.prev;
		item.prev.next = item;
		item.next = this.current;
		this.current.prev = item;
	}
};

Map.prototype.unlink = function(item) {
	if (this.size == 0)
		this.current = undefined;
	else {
		item.prev.next = item.next;
		item.next.prev = item.prev;
		if (item === this.current)
			this.current = item.next;
	}
};

// --- iterator functions - only work if map is linked
Map.prototype.next = function() {
	this.current = this.current.next;
};

Map.prototype.key = function() {
	return this.current.key;
};

Map.prototype.value = function() {
	return this.current.value;
};

function loadCalc(webClientMessage) {
    var g_amsSlider;
    
        var amsSlider = $('amsSlider');
        var amsValue = $('amsValue');
        
        g_amsSlider = new Slider(amsSlider, amsSlider.getElement('.knob'), {
            range: [20, 50500],
            step: 10,
            wheel: true,
            onChange: function(value){
                amsValue.value = value;
            },
            onComplete: function(step){
                calculateResult();
            }
        }).set(1024);
        
        var mpsSlider = $('mpsSlider');
        var mpsValue = $('mpsValue');
        
        new Slider(mpsSlider, mpsSlider.getElement('.knob'), {
            steps: 35, // There are 35 steps
            range: [1, 60], // Minimum value is 8
            wheel: true,
            onChange: function(value){
                mpsValue.value = value;
                x = this;
                y = x;
            },
            onComplete: function(step){
                calculateResult();
            }
        }).set(10);
        
        var ncuSlider = $('ncuSlider');
        var ncuValue = $('ncuValue');
        
        new Slider(ncuSlider, ncuSlider.getElement('.knob'), {
            steps: 9, // There are 100 steps
            range: [1000, 100000],
            wheel: true,
            snap: true,
            onChange: function(value){
                ncuValue.value = value;
            },
            onComplete: function(step){
                calculateResult();
            }
        }).set(1000);
        
        new Slider($('viewSlider'), $('viewKnob'), {
            steps: 3,
            range: [0, 2],
            wheel: true,
            snap: true,
            onComplete: function(step){
                calculateResult();
            }
        })
        var deltaSlider = $('deltaSlider');
        var deltaValue = $('deltaValue');
        var deltaKnob = $('deltaKnob');
        
        new Slider(deltaSlider, deltaKnob, {
            mode: 'vertical',
            steps: 35,
            range: [2048, 10],
            wheel: true,
            onChange: function(value){
                deltaValue.value = value;
                if (value > 500 && value < 1080) {
                	$('deltaKnob').className = "yellowvKnob";
                }
                else {
                    if (value >= 1080) {
                    	$('deltaKnob').className = "redvKnob";
                    }
                    else {
                    	$('deltaKnob').className = "bluevKnob";
                    }
                }
            },
            onComplete: function(step){
                calculateResult();
            }
        }).set(32);
        
        var itlSlider = $('itlSlider');
        var itlValue = $('itlValue');
        var itlKnob = $('itlKnob');
        new Slider(itlSlider, itlKnob, {
            mode: 'vertical',
            steps: 35, // There are 35 steps
            range: [50500, 20],
            wheel: true,
            onChange: function(value){
                itlValue.value = value;
            },
            onComplete: function(step){
                calculateResult();
            }
        }).set(1024);
        
        new Tips($$('.tips'), {
            fixed: true,
            hideDelay: 400
        });
        
        $('deltaTitleTip').store('tip:title', 'Delta size in bytes');
        $('deltaTitleTip').store('tip:text', 'This is the size in bytes of the delta message that would be published from Diffusion');
        
        $('itlTitleTip').store('tip:title', 'Initial Topic Load size in bytes');
        $('itlTitleTip').store('tip:text', 'This is the size in bytes of the state message for a topic that would be published from Diffusion');
}

function format(nStr){
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}

function changeValue(box, slider){
    slider.set(box.value);
}

function calculateResult(){
    
    var result = document.getElementById('result');
    // Get all of the values...
    var ams = $('amsValue').value;
    var mps = $('mpsValue').value;
    var ncu = $('ncuValue').value;
    var delta = $('deltaValue').value;
    var itl = $('itlValue').value;
    
    var messagePerSecond = mps * ncu;
    var currentBytesPerSecond = ams * messagePerSecond;
    $('cbps').innerHTML = format(currentBytesPerSecond);
    
    var deltaBytes = (messagePerSecond - ncu) * delta;
    var itlBytes = ncu * itl;
    
    var diffusionBytesPerSecond = (deltaBytes + itlBytes);
    $('dbps').innerHTML = format(diffusionBytesPerSecond);
    
    $('result').innerHTML = format(currentBytesPerSecond - diffusionBytesPerSecond);
    
    var pr = (currentBytesPerSecond - diffusionBytesPerSecond) / currentBytesPerSecond * 100;
    var prc = pr.toFixed(2);
    $('pr').innerHTML = prc + " %";
    
    var nds = Math.ceil(ncu / 7000);
    $('nds').innerHTML = nds.toFixed(0);
}