/* Begin NodeView */

function NodeView (kBase, docMngr) {
	this.kBase = kBase;
	
	this.collapsed = true;
	docMngr.addDocStatusListener(this, 'updateDocumentList');
	kBase.addURIListener(this, 'redrawView');
	
	document.getElementById('nodeView').callback = this;
	document.getElementById('nodeView:title').getElementsByTagName('h3')[0].addEventListener('click', this.toggle, false);
	document.getElementById('nodeView:title:toggle').addEventListener('click', this.toggle, false);
	document.getElementById('nodeView:title:options:graph').addEventListener('change', this.listChangeCallback, false);
	document.getElementById('nodeView:title:options:document').addEventListener('change', this.listChangeCallback, false);
	document.getElementById('nodeView:title:options:text').addEventListener('keypress',this.textInputKeyCallback,false);
	document.getElementById('nodeView:title:options:textsubmit').addEventListener('click',this.textSubmitCallback,false);
	
	this.viewQueue = [];
	this.viewMap = [];
	this.viewMax = 8;
	this.viewPrev = null;
	this.currentURI = null;
	
	// References to the context menus
	this.context = {pred: [], obj: null};
	
	return this;
}

NodeView.prototype.type = 'NodeView';

NodeView.prototype.textInputKeyCallback = function(event) {
	if (event.keyCode==13){ // enter key
		event.currentTarget.parentNode.parentNode.parentNode.callback.showURI(event.currentTarget.value);
	}
};

NodeView.prototype.textSubmitCallback = function(event) {
	var cell = document.getElementById('nodeView:title:options:text');
	if (cell.value != '')
		event.currentTarget.parentNode.parentNode.parentNode.callback.showURI(cell.value);
	cell.value = '';
};

NodeView.prototype.listChangeCallback = function(event) {
	var select = event.currentTarget;
	var uri = select.options[select.selectedIndex].value.substring(1);
	select.selectedIndex = 0;
	select.parentNode.parentNode.parentNode.callback.showURI(uri);
};

NodeView.prototype.setVis = function(vis) {
	var nodeContent = document.getElementById('nodeView:content');
	var viewToggle = document.getElementById('nodeView:title:toggle');
	
	if (vis == true) {
		nodeContent.style.removeProperty('display');
		viewToggle.firstChild.nodeValue = '[-]';
	} else {
		nodeContent.style.setProperty('display','none', null);
		viewToggle.firstChild.nodeValue = '[+]';
		this.currentURI = null;
	}
	this.collapsed = ! vis;
};

NodeView.prototype.toggle = function(event) {
	var nodeView = event.currentTarget.parentNode.parentNode.callback;
	
	nodeView.setVis(nodeView.collapsed);
};

NodeView.prototype.showURI = function(uri) {
	var div;
	var partial = false;
	if(this.currentURI == null) {
		document.getElementById('nodeView:content-placeholder').style.setProperty('display','none', null);
	}
	this.currentURI = uri;
	if (this.viewMap[uri] == null){
		var len = this.viewQueue.length;
		if(len > this.viewMax){
			var temp = this.viewQueue.shift();
			document.getElementById('nodeView:content').removeChild(temp);
			delete this.viewMap[temp.uri];
			delete temp;
		}
		div = document.createElement('div');
		div.setAttribute('class','nodeView:content:itemBody');
		div.uri = uri;
		
		this.viewMap[uri] = div;
		this.viewQueue.push(div);
	} else {
		div = this.viewMap[uri];
		partial = true;
	};

	if(this.viewPrev != null)
		this.viewPrev.style.setProperty('display', 'none', null);
	this.viewPrev = div;
	div.style.removeProperty('display');
	document.getElementById('nodeView:title:options:text').value = uri;
	
	var stmts = kBase.getByURI(uri);
	var litList = [];
	var resList = [];

	var createRow = function(row, predicate, resource, subobj, isRes) {
		// Predicate Cell
		var predCell = document.createElement('td');
		predCell.setAttribute('class','predicate');
		predCell.uri = predicate;
		
		// Either subject or object. Depending on the 'subobj' flag.
		var resCell = document.createElement('td');
		resCell.setAttribute('class','resource');
		resCell.uri = resource;
		
		var temp = Utils.predicateSplit(predicate);
		var uriString = temp[1];
		var prefix = this.kBase.getURIPrefix(temp[0]);
		if (prefix != null)
			uriString = prefix + ':' + uriString;
		
		if(subobj){ // resource is the subject
			predCell.appendChild(document.createTextNode('is ' + uriString + ' of'));
		} else { // resource is the object
			predCell.appendChild(document.createTextNode(uriString));
		}
		// if(regEvents){
			// predCell.addEventListener('click', nodeView.predCallback, false);
			predCell.addEventListener('contextmenu', nodeView.predCallback, false);
		// }
		predCell.type = (isRes) ? 'resource' : 'literal';
		
		temp = Utils.predicateSplit(resource);
		uriString = resource;
		prefix = this.kBase.getURIPrefix(temp[0]);
		if (prefix != null)
			uriString = prefix + ':' + temp[1];
		
		resCell.appendChild(document.createTextNode(uriString));
		if(isRes){
			resCell.addEventListener('click', nodeView.resCallback, false);
			resCell.addEventListener('contextmenu', nodeView.resCallback, false);
		}
		
		row.appendChild(predCell);
		row.appendChild(resCell);
	};

	var tr = null;
	for(i in stmts){
		if(stmts[i].subject.value == uri){
			tr = document.createElement('tr');		
			if(stmts[i].object.type != 'RDFLiteral'){
				if(resList[stmts[i].predicate.value] == null)
					resList[stmts[i].predicate.value] = {sub: [], obj: []};
				createRow(tr, stmts[i].predicate.value, stmts[i].object.value, false, true);
				resList[stmts[i].predicate.value].sub.push(tr);
			} else {
				if(litList[stmts[i].predicate.value] == null)
					litList[stmts[i].predicate.value] = {sub: [], obj: []};
				createRow(tr, stmts[i].predicate.value, stmts[i].object.value, false, false);
				litList[stmts[i].predicate.value].sub.push(tr);
			}
		} else if(stmts[i].object.value == uri){
			tr = document.createElement('tr');
						
			if(stmts[i].subject.type != 'RDFLiteral'){
				if(resList[stmts[i].predicate.value] == null)
					resList[stmts[i].predicate.value] = {sub: [], obj: []};
				createRow(tr, stmts[i].predicate.value, stmts[i].subject.value, true, true);
				resList[stmts[i].predicate.value].obj.push(tr);
			} else {
				if(litList[stmts[i].predicate.value] == null)
					litList[stmts[i].predicate.value] = {sub: [], obj: []};
				createRow(tr, stmts[i].predicate.value, stmts[i].subject.value, true, false);
				litList[stmts[i].predicate.value].obj.push(tr);
			}
		}
	}
	delete tr;

	var tbLit = document.createElement('tbody');
	var tbRes = document.createElement('tbody');

	var addPlaceholder = function(tbody, message){
		var row = document.createElement('tr');
		row.setAttribute('class', 'odd placeholder');
		
		var cell = document.createElement('td');
		cell.setAttribute('colspan', '2');
		cell.appendChild(document.createTextNode(message));
		
		row.appendChild(cell);
		tbody.appendChild(row);
	};

	var litCount = 0;
	var count = 0;
	// Callback function for map.
	var append = function(item,index){
		this.appendChild(item);
	};
	for (i in litList){
		litList[i].sub.map(append, tbLit);
		litList[i].obj.map(append, tbLit);
		litCount ++;
	}

	var resCount = 0;
	for (i in resList){
		resList[i].sub.map(append, tbRes);
		resList[i].obj.map(append, tbRes);
		resCount ++;
	}
	
	if(litCount == 0)
		addPlaceholder(tbLit, 'No Literal Data');
	if(resCount == 0)
		addPlaceholder(tbRes, 'No Resource Data');
	
	var box = document.createElement('div');
	box.setAttribute('class','status');
	
	var proto = Util.uri.protocol(uri);
	var type = null;
	var resolved = null;
	var triples = null;
	if (proto == 'http' || proto == 'https') {
		var rec = dMngr.check(uri);
		if (rec == null) {
			resolved = false;
		} else {
			resolved = true;
			if (rec.status >= 200 && rec.status < 300 || rec.triples != null) { //(uri.indexOf('#') != -1 || rec.redirected != null) {
				type = 'Document';
				if (rec.triples)
					triples = rec.triples;
			}
		}
	} else {
		if (uri.substr(0,6) == 'bNode-') {
			type = 'Blank Node';
		}
	}
	var makeRow = function(body, cell1, cell2) {
		var tr = document.createElement('tr');
		var td = document.createElement('td');
		td.setAttribute('class','label');
		for (i in cell1)
			td.appendChild(cell1[i]);
		tr.appendChild(td);
		td = document.createElement('td');
		td.setAttribute('class','value');
		for (i in cell2)
			td.appendChild(cell2[i]);
		tr.appendChild(td);
		body.appendChild(tr);
	};
	var table = document.createElement('table');
	var tbody = document.createElement('tbody');
	if (resolved == true) {
		makeRow(tbody,{0: document.createTextNode('Status:')}, {0: document.createTextNode('Resolved')});
	} else if (resolved == false) {
		var button = document.createElement('input');
		button.setAttribute('type','button');
		button.setAttribute('value','Resolve');
		button.addEventListener('click',this.resolveCallback, false);
		
		makeRow(tbody,{0: document.createTextNode('Status')}, {0: document.createTextNode('Unresolved'), 1: document.createElement('br'), 2: button});
	}
	if (type != null) {
		makeRow(tbody,{0: document.createTextNode('Type:')}, {0: document.createTextNode(type)});
	}
	if (triples != null) {
		makeRow(tbody,{0: document.createTextNode('Triples:')}, {0: document.createTextNode(triples)});
	}
	table.appendChild(tbody);
	box.appendChild(table);
	
	var titleStr = uri;
	var stmts = kBase.getStmtsMatching(uri,RDFConst.abbr['rdfs:label'],null);
	if (stmts.length != 0)
		titleStr = stmts[0].object.value + ' (' + uri+ ')';
	
	if (partial == false){
		div.appendChild(box);
		
		var title = document.createElement('h3');
		title.appendChild(document.createTextNode(titleStr));
		div.appendChild(title);
		
		var tLit = document.createElement('table');
		tLit.setAttribute('class','nodeView:content:literal');
		var tRes = document.createElement('table');
		tRes.setAttribute('class','nodeView:content:resource');
		
		tLit.appendChild(tbLit);
		tRes.appendChild(tbRes);
	
		var h4 = document.createElement('h4');
		h4.appendChild(document.createTextNode('Literal Data'));
	
		div.appendChild(h4);
		div.appendChild(tLit);
	
		h4 = document.createElement('h4');
		h4.appendChild(document.createTextNode('Resource Data'));
	
		div.appendChild(h4);
		div.appendChild(tRes);
		document.getElementById('nodeView:content').appendChild(div);
	} else {
		div.getElementsByTagName('h3')[0].firstChild.nodeValue = titleStr;
		div.replaceChild(box, div.getElementsByTagName('div')[0]);
		var tLit = div.getElementsByTagName('table');
		var tRes = tLit[2];
		tLit = tLit[1];
		
		tLit.replaceChild(tbLit, tLit.tBodies[0]);
		tRes.replaceChild(tbRes, tRes.tBodies[0]);
	}
	this.setVis(true);
};

NodeView.prototype.updateGraphList = function(list) {
	var select = document.getElementById('nodeView:title:options:graph');
	var placeholder = document.getElementById('nodeView:title:options:graphPlaceholder');
	for (var i =  select.childNodes.length - 1; i >= 0; i--){
		select.removeChild(select.childNodes[i]);
	};
	select.appendChild(placeholder);
	
	var option;
	for(i in list){	
		option = document.getElementById('nodeView:title:options:graph:' + list[i].uri);
		if (option != null) {
			select.appendChild(option);
		} else {
			option = document.createElement('option');
			option.appendChild(document.createTextNode(list[i].uri));
			option.setAttribute('id', 'nodeView:title:options:graph:' + list[i].uri);
			option.setAttribute('value', ':' + list[i].uri);
			select.appendChild(option);
		}
	}
};

NodeView.prototype.updateDocumentList = function(type, doc) {
	var prefix = 'nodeView:title:options:document';
	
	var select = document.getElementById(prefix);
	var option = document.getElementById(prefix + ':' + doc.uri);
	if (type == 'add' && option == null) {
		option = document.createElement('option');
		option.appendChild(document.createTextNode(doc.uri));
		option.setAttribute('id', 'nodeView:title:options:document:' + doc.uri);
		option.setAttribute('value', ':' + doc.uri);
		
		if (doc.redirSrc.length == 1) {
			var prev = null;
			for (index in doc.redirSrc) {	
				prev = document.getElementById(prefix + ':' + doc.redirSrc[index].uri);
			}
			if (prev != null) {
				select.insertBefore(option, prev);
			} else {
				select.appendChild(option);
			}
		} else {
			select.appendChild(option);
		}
	} else if (type == 'update') {
		if(doc.redirected == true) {
			select.removeChild(option);
		}
	} else if (type == 'remove'){
		select.removeChild(option);
	}
};

NodeView.prototype.redrawView = function(list) {
	if (nodeView.currentURI == null) return;
	
	for (i in list){
		if (i == nodeView.currentURI){
			nodeView.showURI(i);
			return;
		}
	}
};

NodeView.prototype.resolveCallback = function(event) {
	MenuHandler.docMenu.loadDocument(nodeView.currentURI);
};

NodeView.prototype.predCallback = function(event) {
	if (event.type == 'click'){
		
	} else if (event.type == 'contextmenu'){
		nodeView.predContext(event);
	}
};

NodeView.prototype.predContext = function(event) {
	var m = this.context.pred;
	if (m.con == null){
		m.edge = new ContextMenuList({
			0: new ContextMenuItem('Customise edge', this.predCustomEdge)
			});
		m.obj = new ContextMenuList({
			0: new ContextMenuItem('Add Objects from this property', this.predAddObjectsCallback),
			1: new ContextMenuItem('Add & Resolve Objects from this property', this.predAddResolveObjectsCallback)
			});
		m.add = new ContextMenuList({
			0: new ContextMenuItem('Add this property', this.predAddCallback),
			1: new ContextMenuItem('Add & Resolve this property', this.predAddResolveCallback)
			});
		m.con = new ContextMenu({
			0: m.edge,
			1: m.obj,
			2: m.add
			});

	}
	if (event.currentTarget.type == 'literal') {
		m.edge.setVisible(false);
		m.obj.setVisible(false);
	} else {
		m.edge.setVisible(true);
		m.obj.setVisible(true);
	}
	return m.con.show(event);
};

NodeView.prototype.predCustomEdge = function(event) {
	var uri = nodeView.context.pred.con.target.uri;
	nodeView.setVis(false);
	MenuHandler.gOptMenu.edit(uri);
};

NodeView.prototype.predAddCallback = function(event) {
	var uri = nodeView.context.pred.con.target.uri;
	MenuHandler.uriMenu.add(uri, nodeView.currentURI);
};

NodeView.prototype.predAddResolveCallback = function(event) {
	var uri = nodeView.context.pred.con.target.uri;
	MenuHandler.uriMenu.add(uri, nodeView.currentURI);
	MenuHandler.docMenu.loadDocument(uri);
};

NodeView.prototype.predAddObjectsCallback = function(event) {
	var uri = nodeView.currentURI;
	var pred = nodeView.context.pred.con.target.uri;
	window.setTimeout(function(){nodeView.addFromPred(uri, pred, false);},0);
};

NodeView.prototype.predAddResolveObjectsCallback = function(first_argument) {
	var uri = nodeView.currentURI;
	var pred = nodeView.context.pred.con.target.uri;
	window.setTimeout(function(){nodeView.addFromPred(uri, pred, true);},0);
};

NodeView.prototype.addFromPred = function(uri, pred, resolve) {
	var stmts = [];
	stmts = stmts.concat(kBase.getStmtsMatching(uri, pred));
	stmts = stmts.concat(kBase.getStmtsMatching(null, pred, uri));
	var fun = function(stmt){
		var newURI;
		if (stmt.subject.value == uri){
			newURI = stmt.object.value;				
		} else {
			newURI = stmt.subject.value;			
		}
		URIMngr.add(newURI, uri, false);
		return newURI;
	};
	var affected = stmts.map(fun, this);
	URIMngr.computeEdges(affected);
	if(resolve == true)
		affected.map(MenuHandler.docMenu.loadDocument,MenuHandler.docMenu);
};

NodeView.prototype.resCallback = function(event) {
	if (event.type == 'click'){
		nodeView.showURI(event.currentTarget.uri);
	} else if (event.type == 'contextmenu'){
		nodeView.resContext(event);
	}
};

NodeView.prototype.resContext = function(event) {
	var m = this.context.res;
	if (m == null){
		m = new ContextMenu({
			0: new ContextMenuList({
				0: new ContextMenuItem('Inspect', this.resInspectCallback, 'default')
				}),
			1: new ContextMenuList({
				0: new ContextMenuItem('Add', this.resAddCallback),
				1: new ContextMenuItem('Add & Resolve', this.resAddResolveCallback)
				})
			});

		this.context.res = m;
	}

	return m.show(event);
};

NodeView.prototype.resInspectCallback = function(event) {
	var uri = nodeView.context.res.target.uri;
	nodeView.showURI(uri);
};

NodeView.prototype.resAddCallback = function(event) {
	var uri = nodeView.context.res.target.uri;
	MenuHandler.uriMenu.add(uri, nodeView.currentURI);
};

NodeView.prototype.resAddResolveCallback = function(event) {
	var uri = nodeView.context.res.target.uri;
	MenuHandler.uriMenu.add(uri, nodeView.currentURI);
	MenuHandler.docMenu.loadDocument(uri);
};

// NodeView.prototype.placeholderCallback = function(event) {
// 	alert('This isn\'t implemented yet');
// };

/* End NodeView */

/* Begin Utils */

// Static class
window.Utils = {
	/**
	 * Splits a predicate of either a hash or slash namespace into two components
	 */
	predicateSplit: function(predicate){
		var hash = predicate.indexOf('#');
		if (hash != -1){
			// Hash Namespace
			hash ++;
			return {0: predicate.slice(0,hash), 1: predicate.slice(hash) };
		} else {
			// Slash namespace
			var slash = predicate.lastIndexOf('/') +1;
			return {0: predicate.slice(0,slash), 1: predicate.slice(slash) };
		}
	}
};
/* End Utils */
