/* Filename: menu.js
 * This file is part of the gRaDF Semantic Web browsing tool.
 * Copyright (C) 2006  Marcus Cobden
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * (or see the file gpl.txt)
 * 
 * 	Description:
 * This file contains the backend to the menus on the GUI.
 * 
 *	Classes:
 * DocMenuMngr
 * URIMenu
 * EdgeForces
 * OptionMenu
 * DebugMenu
 * SpeedMenu
 * GreetingMenu
 * MenuMngr
 * 
 * 	Version information:
 * $HeadURL: svn+ssh://mc1204@svn.ugforge.ecs.soton.ac.uk/projects/grdf/code/branches/serverside/js/menu.js $
 * $Date: 2007-06-30 08:07:34 +0100 (Sat, 30 Jun 2007) $
 * $Author: mc1204 $
 * $Rev: 139 $
 */

/* Begin DocMenuMngr */

function DocMenuMngr()
{
	this.type = 'Document Menu';
	this.count = 0;
	
	this.checkPlaceholder();
	
	dMngr.addDocStatusListener(this, 'update');
	return this;
}

/**
 * Catches the Click event intended to remove a document.
 * Then actually does the work, and removes the row in the table
 */
DocMenuMngr.prototype.deleteDocumentEvent = function(e)
{
	var uri = e.currentTarget.parentNode.getAttribute('id').substring(8);
	// Delete the document
	dMngr.remove(uri);
};


/**
 * Add a document to the list
 *
 * @param record = [uri, status, uris, triples] 
 */
DocMenuMngr.prototype.add = function(doc){
	var table = document.getElementById('menu:body:DocMenu').tBodies[0];
	
	var row = document.createElement('tr');
	row.setAttribute('id', 'doc_row_' + doc.uri); //NB Fix for WebKit
	// row.id = 'doc_row_' + doc.uri;

	// URI
	var uriCell = document.createElement('td');
	uriCell.setAttribute('class', 'uri');
	
	var uriText = doc.uri;
	/* if(record.redirected != null){
		uriText += ' (redir. from '+ record.source + ')';
	} */
	uriCell.appendChild(document.createTextNode(uriText));
	row.appendChild(uriCell);

	// Triples
	var triplesCell = document.createElement('td');
	triplesCell.setAttribute('class', 'triples');
	triplesCell.appendChild(document.createTextNode('-'));
	row.appendChild(triplesCell);

	// Status
	var statusCell = document.createElement('td');
	statusCell.setAttribute('class', 'status');
	statusCell.appendChild(document.createTextNode(doc.status));
	row.appendChild(statusCell);

	var trashCell = document.createElement('td');
	trashCell.setAttribute('class', 'remove');
	
	var tickBox = document.createElement('input');
	tickBox.setAttribute('type','checkbox');
	trashCell.appendChild(tickBox);
	
	trashCell.addEventListener('click',MenuHandler.docMenu.deleteDocumentEvent, false);
	trashCell['callback'] = this;
	row.appendChild(trashCell);

	table.appendChild(row);

	this.count++;
	
	this.checkPlaceholder();
};

/**
 * Load a document
 * @param doc document URI
 */
DocMenuMngr.prototype.loadDocument = function(doc){
	// Already Loaded?
	if(dMngr.check(doc) != null)
		return;
		
	// Add the document
	dMngr.add(doc);
};

/**
 * Remove a document from the list
 * 
 * @param record = [uri, status, uris, triples] 
 */
DocMenuMngr.prototype.remove = function(){
	return;
	// Placeholder: removing documents comes through this class initially anyway. Do we want to handle it differently? TODO
};

/**
 * Update a document in the list
 * 
 * 
 */
DocMenuMngr.prototype.update = function(type, doc){

	if (type == 'add') {
		this.add(doc);
	} else {
		var row = document.getElementById('doc_row_' + doc.uri);
		if (type == 'update') {
			if(doc.redirected == false) {
				if(doc.triples != null)
					row.cells[1].firstChild.nodeValue = doc.triples;
				row.cells[2].firstChild.nodeValue = doc.getStatus();
			} else {
				this.count--;
				row.parentNode.removeChild(row);
				this.checkPlaceholder();
			}
		} else if (type == 'remove') {
			this.count--;
			row.parentNode.removeChild(row);
			this.checkPlaceholder();
		}
	}
};

/**
 * Add a placeholder to the list when empty
 *
 */
DocMenuMngr.prototype.checkPlaceholder = function()
{
	var row;
	if (this.count > 0){
		row = document.getElementById('doc_placeholder');
		if (row != null)
			row.parentNode.removeChild(row);
	} else {
		var table = document.getElementById('menu:body:DocMenu').tBodies[0];
		row = document.createElement('tr');
		row.setAttribute('id','doc_placeholder');
		row.setAttribute('class','placeholder');

		var cell = document.createElement('td');
		cell.setAttribute('colspan', '4');
		cell.appendChild(document.createTextNode('No current Documents'));

		row.appendChild(cell);
		table.appendChild(row);
	}
};

/* End DocMenuMngr */

/* Begin URIMenu */
function URIMenu () {
	this.count = 0;
	
	this.checkPlaceholder();
	
	return this;
}

URIMenu.prototype.add = function(uri, refURI, flag) {
	// Subscribe the graphing to the URI
	URIMngr.add(uri, refURI, flag);
};

URIMenu.prototype.remove = function(uri) {
	URIMngr.remove(uri);
};

URIMenu.prototype.removeCallback = function(event) {
	MenuHandler.uriMenu.remove(event.currentTarget.parentNode.id.substring(12));
};

URIMenu.prototype.update = function(subs) {
	subs.sort(function (a, b) {
		return (a.uri < b.uri) - (a.uri > b.uri);
	});
	
	var newTBody = document.createElement('tbody');
	this.count = 0;
	
	var row = null;
	for(index in subs){
		row = document.getElementById('GraphStatus:' + subs[index].uri);
		if (row == null){
			row = document.createElement('tr');
			row.setAttribute('id', 'GraphStatus:' + subs[index].uri);
			
			var uriCell = document.createElement('td');
			uriCell.setAttribute('class','uri');
			uriCell.appendChild(document.createTextNode(subs[index].uri));
			row.appendChild(uriCell);
			
			var delCell = document.createElement('td');
			delCell.setAttribute('class','remove');
			var img = document.createElement('img');
			img.setAttribute('src','images/silk/greydelete.png');
			img.setAttribute('alt','Remove');
			
			delCell.appendChild(img);
			delCell.addEventListener('click', this.removeCallback, false);
			row.appendChild(delCell);
			
			newTBody.appendChild(row);
		} else {
			newTBody.appendChild(row);
		}
		this.count++;
	}
	
	var oldTBody = document.getElementById('menu:body:GraphStatus').tBodies[0];
	document.getElementById('menu:body:GraphStatus').replaceChild(newTBody, oldTBody);

	this.checkPlaceholder();
};

URIMenu.prototype.checkPlaceholder = function()
{
	if (this.count > 0){
		var row = document.getElementById('GraphStatus-placeholder');
		if (row != null)
			row.parentNode.removeChild(row);
	} else {
		var table = document.getElementById('menu:body:GraphStatus').tBodies[0];
		var row = document.createElement('tr');
		row.setAttribute('id','Graph-Status-placeholder');
		row.setAttribute('class','placeholder');

		var cell = document.createElement('td');
		cell.setAttribute('colspan', '2');
		cell.appendChild(document.createTextNode('No subscribed Nodes'));

		row.appendChild(cell);
		table.appendChild(row);
	}
};
/* End URIMenu */

/* Begin EdgeForces */
function EdgeForces () {
	document.getElementById('menu:body:EdgeForces:edgeForce:entryForm').addEventListener('submit', this.addCallback, false);
	
	this.update();
}

EdgeForces.prototype.edit = function(uri) {
	var uriCell = document.getElementById('menu:body:EdgeForces:edgeForce:uriField');
	
	var record;
	if (uri != null){
		// Normal case
		record = gOptions.edge.list[uri];
		uriCell.value = uri;
		uriCell.uri = 'uri-' + uri;
	} else {
		// Editing Default
		record = gOptions.edge.def;
		uriCell.value = 'default';
		uriCell.uri = 'default';
	}
	
	if (record != null){
		var scaleCell = document.getElementById('menu:body:EdgeForces:edgeForce:scaleField');
		var natLenCell = document.getElementById('menu:body:EdgeForces:edgeForce:natLenField');
		
		if (record.k != null)
			scaleCell.value = record.k;
		if (record.l != null)
			natLenCell.value = record.l;
	}
	MenuHandler.openTab('EdgeForces');
	document.getElementById('menu:body:EdgeForces:edgeForce:entryForm').scrollIntoView(true);
};

EdgeForces.prototype.addCallback = function(event) {
	if(window.gOptions == null)
		return;
	
	var uriCell = document.getElementById('menu:body:EdgeForces:edgeForce:uriField');
	var uri = uriCell.value;
	var scaleCell = document.getElementById('menu:body:EdgeForces:edgeForce:scaleField');
	var scale = scaleCell.value;
	var natLenCell = document.getElementById('menu:body:EdgeForces:edgeForce:natLenField');
	var natLen = natLenCell.value;
	var valid = true;
	
	if(isNaN(natLen) || (natLen == '' && uriCell.uri == 'default' && uri == 'default')) {
		natLenCell.setAttribute('class', 'error');
		valid = false;
	} else {
		natLenCell.removeAttribute('class');
	}
	if(isNaN(scale) || (scale == '' && uriCell.uri == 'default' && uri == 'default')) {
		scaleCell.setAttribute('class', 'error');
		valid = false;
	} else {
		scaleCell.removeAttribute('class');
	}	
	if (scale == '' && natLen == '' && uri != ''){
		valid = false;
		natLenCell.setAttribute('class', 'error');
		scaleCell.setAttribute('class', 'error');
	}
	if (uri == ''){
		valid = false;
		if (scale != '' || natLen != '')
			uriCell.setAttribute('class', 'error');
		else
			uriCell.removeAttribute('class');
	}
	
	if (valid == true){
		if (scale == '') scale = null;
		if (natLen == '') natLen = null;
		
		if (uriCell.uri == 'default' && uri == 'default') {
			gOptions.edge.def.k = scale;
			gOptions.edge.def.l = natLen;
		} else {
			gOptions.edge.list[uri] = {uri: uri, k: scale, l: natLen};
		}
		event.currentTarget.reset();
		uriCell.uri = null;
		MenuHandler.gOptMenu.update();
	}
	event.preventDefault();
	event.returnValue = false;
	event.stopPropagation();

	return false;
};

EdgeForces.prototype.editCallback = function(event) {
	event.currentTarget.callback.edit(event.currentTarget.uri);
};

EdgeForces.prototype.update = function() {
	var table = document.getElementById('menu:body:EdgeForces:edgeForce');
	var tbody = document.createElement('tbody');

	var makeRow = function(uri, scale, natLen, def){
		var row = document.createElement('tr');
		row.uri = uri;
		row.callback = this;
		row.addEventListener('click', this.editCallback, false);
		
		var uriCell = document.createElement('td');
		uriCell.setAttribute('class', 'uri');
		uriCell.appendChild(document.createTextNode(uri));
		row.appendChild(uriCell);			
		
		var scaleCell = document.createElement('td');
		scaleCell.setAttribute('class', 'scale');
		scaleCell.appendChild(document.createTextNode(scale));
		row.appendChild(scaleCell);
		
		var lenCell = document.createElement('td');
		lenCell.setAttribute('class', 'natLen');
		lenCell.appendChild(document.createTextNode(natLen));
		row.appendChild(lenCell);
		
		var delCell = document.createElement('td');
		delCell.setAttribute('class', 'remove');
		
		if (!def) {
			row.setAttribute('id', 'EdgeForces:edgeForce:row:' + uri);
			var delImg = document.createElement('img');
			delImg.setAttribute('src', 'images/silk/cross.png');
			delImg.setAttribute('alt', 'Remove edge property');
			delCell.appendChild(delImg);
		} else {
			row.setAttribute('id', 'EdgeForces:edgeForce:default');
			row.uri = null;
			row.setAttribute('class','default');
		}
		row.appendChild(delCell);
		
		return row;
	};

	var scale = document.getElementById('menu:body:EdgeForces:edgeForce:scaleField');
	if (scale!= null)
		scale.defaultValue = gOptions.edge.def.k;

	var natLen = document.getElementById('menu:body:EdgeForces:edgeForce:natLenField');
	if (natLen != null)
		natLen.defaultValue = gOptions.edge.def.l;

	var form = document.getElementById('menu:body:EdgeForces:edgeForce:entryForm');
	if (form != null){
		tbody.appendChild(form);
		form.reset();
	}
	
	// Defaults row
	var def = document.getElementById('menu:body:EdgeForces:edgeForce:row:default');
	if (def == null){
		def = makeRow.call(this, 'default', gOptions.edge.def.k, gOptions.edge.def.l, true);
		def.setAttribute('class', 'default');
	}
	tbody.appendChild(def);
	
	for(index in gOptions.edge.list){
		var item = gOptions.edge.list[index];
		var row = document.getElementById('EdgeForces:edgeForce:row:' + item.uri);
		if (row == null){
			row = makeRow.call(this, item.uri, item.k, item.l);
		} else {
			row.childNodes[1].firstChild.nodeValue = item.k;
			row.childNodes[2].firstChild.nodeValue = item.l;
		}
		
		tbody.appendChild(row);
	}
	
	table.replaceChild(tbody, table.tBodies[0]);
};

/* End EdgeForces */

/* Begin OptionMenu */
function OptionMenu () {
	// Graph options
	document.getElementById('menu:body:OptionMenu:Graph:treeRects').addEventListener('change',this.checkboxEvent,false);
	// Debug Options
	document.getElementById('menu:body:OptionMenu:Debug:LogLevel').addEventListener('change',this.logLevelEvent,false);
}

OptionMenu.prototype.checkboxEvent = function(event) {
	gOptions.nonedge.showTree = event.currentTarget.checked == true;	
};

OptionMenu.prototype.logLevelEvent = function(event) {
	MenuHandler.debugMenu.logLevel = event.target.value;
};

/* End OptionMenu */
/* Begin DebugMenu */

function DebugMenu(){
	this.logLevel = 0;
	
	this.ERROR = 8;
	this.WARN = 4;
	this.LOG = 1;
	
	return this;
}

DebugMenu.prototype.postLog = function(message, mesagetype)
{
	var list = document.getElementById('menu:body:DebugMenu:Debug_log');
	if(list != null){
		var item = document.createElement('li');
		item.appendChild(document.createTextNode(message));
		if(mesagetype != null)
			item.setAttribute('class',mesagetype);

		list.insertBefore(item, list.childNodes[0]);
	}
};

DebugMenu.prototype.gLOG = function(message, section) {
	if(this.LOG < this.logLevel)
		return;
	
	var out = this.formatMessage(message, section);
	this.postLog(out,'log');
};

DebugMenu.prototype.gWARN = function(message, section) {
	if(this.WARN < this.logLevel)
		return;

	var out = this.formatMessage(message, section);
	this.postLog(out,'warn');
};

DebugMenu.prototype.gERROR = function(message, section) {
	if(this.ERROR < this.logLevel)
		return;
		
	var out = this.formatMessage(message, section);
	this.postLog(out,'error');
	window.setTimeout(function() {alert(section + ': ' + message);}, 10);
};

DebugMenu.prototype.formatMessage = function(message, section) {
	var out = '';
	var now = new Date();
	out += this.formatDate(now);

	if(section != null )
		out += section + ': ';
	
	out += message;
	
	return out;
};

DebugMenu.prototype.formatDate = function(time) {
	lz = function(num){
		num = num.toString();
		return (num.length ==1) ? '0' + num : num;
	};
	return '[' + lz(time.getHours()) + ':' + lz(time.getMinutes()) + ':' + lz(time.getSeconds()) + '] ';
};

/* End DebugMenu*/
/* Begin SpeedMenu */

function SpeedMenu() {
	// Initial state
	this.speedMode = 2;
	this.timeStep = 300;
	this.timer = null;
	this.timerFunc = function(interval){ gPlotter.timeStep(interval); };

	var image = document.getElementById('menu:tabs:Speed' + this.speedMode).firstChild;
	image.setAttribute('src',image.src.substring(0, image.src.lastIndexOf('-')) + '-flat.png');
	
	// Register the listeners
	for (var id = 0; id < 4; id ++){
		document.getElementById('menu:tabs:Speed' + id).addEventListener('click',this.handleEvent,false);
	}
	
	if(this.timer == null && this.speedMode >= 2){
		this.launchTicks();
	}
	
	return this;
}

SpeedMenu.prototype.handleEvent = function(event) {
	var speed = event.currentTarget.id.substring(15);
	var oldSpeed = MenuHandler.speedMenu.speedMode;
	if(speed == oldSpeed)
		return;
	
	MenuHandler.speedMenu.updateImages(speed, oldSpeed);
	MenuHandler.speedMenu.speedMode = speed;
	
	if (MenuHandler.speedMenu.timer != null){
		window.clearInterval(MenuHandler.speedMenu.timer);
		MenuHandler.speedMenu.timer = null;
	}
	
	if (speed >= 2){
		MenuHandler.speedMenu.timer = window.setInterval(MenuHandler.speedMenu.timerFunc, MenuHandler.speedMenu.timeStep / (speed -1));
	} else if (speed == 1) {
		window.setTimeout(MenuHandler.speedMenu.timerFunc, MenuHandler.speedMenu.timerStep);
		window.setTimeout(function () {
			MenuHandler.speedMenu.speedMode = 0;
			MenuHandler.speedMenu.updateImages(0,1); }, 300);
	}
	
};

SpeedMenu.prototype.updateImages = function(speed, oldSpeed) {	
	var oldImage = document.getElementById('menu:tabs:Speed' + oldSpeed).firstChild;
	var newImage = document.getElementById('menu:tabs:Speed' + speed).firstChild;
	
	var oldSrc = oldImage.getAttribute('src');
	oldSrc = oldSrc.substring(0, oldSrc.lastIndexOf('-')) + '-emboss.png';
	var newSrc = newImage.getAttribute('src');
	newSrc = newSrc.substring(0, newSrc.lastIndexOf('-')) + '-flat.png';
	
	oldImage.setAttribute('src', oldSrc);
	newImage.setAttribute('src', newSrc);
};

SpeedMenu.prototype.launchTicks = function() {
	if(window.gPlotter != null) {
		var i = this.timeStep / (this.speedMode -1);
		this.timer = window.setInterval(this.timerFunc, i, i);
	} else {
		var callback = this;
		window.setTimeout(function() { callback.launchTicks(); }, 1000);
	}
};

/* End SpeedMenu */

/* Begin MenuMngr */

function MenuMngr(){
	this.debugMenu	= new DebugMenu();
	this.optMenu	= new OptionMenu();
	this.uriMenu	= new URIMenu();
	this.gOptMenu	= new EdgeForces();
	this.docMenu	= new DocMenuMngr();
	this.speedMenu	= new SpeedMenu();
	
	this.tabs = [];
	this.currentTab = null;
		
	// Submenu toggles
	callback = this;
	var regSubToggle = function(name, obj){
		callback.tabs[name] = {name: name, obj: obj };
		document.getElementById('menu:tabs:' + name).addEventListener('click', callback.tabClickCallback, false);
		document.getElementById('menu:body:' + name).style.display = 'none';
	};
	regSubToggle('MainMenu', this);
	regSubToggle('DocMenu', this.docMenu);
	regSubToggle('GraphStatus', this.uriMenu);
	regSubToggle('EdgeForces');
	regSubToggle('OptionMenu', this.optMenu);
	regSubToggle('DebugMenu', this.debugMenu);
	
	this.tabChangeEvent(null,'MainMenu');
	
	// Register for events
	document.getElementById('uriForm').addEventListener('submit',this.formSubmitEvent,false);
	document.getElementById('uriForm').callback = this;
	document.getElementById('menu:body:MainMenu:quickMenu:demoView').addEventListener('click',this.demoView,false);
	return this;
}

/**
 * Catch the key pressed events on the URI input field.
 * If the return is pressed, then do something.
 */
MenuMngr.prototype.formSubmitEvent = function(event) {
	var menu = event.currentTarget.callback;
	var uri = event.currentTarget.uri.value;
	if(uri != '') {
		if(document.getElementById('uriMode:both').checked == true) {
			menu.uriMenu.add(event.currentTarget.uri.value);
			menu.docMenu.loadDocument(uri);
		} else if (document.getElementById('uriMode:graph').checked == true) {
			menu.uriMenu.add(event.currentTarget.uri.value);
		} else if (document.getElementById('uriMode:kBase').checked == true) {
			menu.docMenu.loadDocument(uri);
		}
		event.currentTarget.reset();
	}
	
	event.preventDefault();
	event.returnValue = false;
	event.stopPropagation();
	return false;	
};

MenuMngr.prototype.demoView = function(event) {
	URIMngr.autoAddRules.push({
		prop: 'http://rdf.ecs.soton.ac.uk/ontology/ecs#hasRole',
		cond: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
		value: 'http://rdf.ecs.soton.ac.uk/ontology/ecs#Role'
	});
	URIMngr.autoAddRules.push({
		prop: 'http://rdf.ecs.soton.ac.uk/ontology/ecs#hasRole',
		cond: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
		value: 'http://rdf.ecs.soton.ac.uk/ontology/ecs#Person'
	});
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/UoS');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/UoS/ECS');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/group/iam');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/project/smarttea');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/project/RobocupRescue');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/project/OntoMedia');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/seminar/100');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/cohort/csMEngCs/3/2006-2007');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/role/6386');
	MenuHandler.uriMenu.add('http://id.ecs.soton.ac.uk/person/6386');
	MenuHandler.docMenu.loadDocument('data/demoData.rdf');
	MenuHandler.docMenu.loadDocument('data/doap.rdf');
	MenuHandler.docMenu.loadDocument('http://rdf.ecs.soton.ac.uk/ontology/ecs');
};

MenuMngr.prototype.tabClickCallback = function(event){
	var name = event.currentTarget.getAttribute('id');
	name = name.substring(name.lastIndexOf(':') +1);

	MenuHandler.tabChangeEvent(MenuHandler.currentTab,name);
};

MenuMngr.prototype.openTab = function(name) {
	if(this.tabs[name]) {
		if(this.currentTab != name)
			this.tabChangeEvent(this.currentTab,name);
	} else {
		gERROR('Cannot open a tab which doesn\'t exist: ' + name,this.type);
	}
};

MenuMngr.prototype.tabChangeEvent = function(oldTab, newTab) {
	if(oldTab == newTab){
		// Collapse the whole menu
		document.getElementById('menu:body:' + oldTab).style.display = 'none';
		document.getElementById('menu:tabs:' + oldTab).removeAttribute('class');
		document.getElementById('menu:body').style.display = 'none';
		this.currentTab = null;
	} else {
		if(oldTab == null){
			document.getElementById('menu:body').style.display = '';
		} else {
			document.getElementById('menu:body:' + oldTab).style.display = 'none';
			document.getElementById('menu:tabs:' + oldTab).removeAttribute('class');
		}
		document.getElementById('menu:tabs:' + newTab).setAttribute('class','active');
		document.getElementById('menu:body:' + newTab).style.display = '';
		this.currentTab = newTab;
	}
};


/* End MenuMngr */