// MARKKIT
// Copyright 2007 (c) Slim Amamou <slim.amamou@gmail.com>

if (!window['Node']) {
    window.Node = new Object();
	Node.ELEMENT_NODE = 1;
	Node.ATTRIBUTE_NODE = 2;
	Node.TEXT_NODE = 3;
	Node.CDATA_SECTION_NODE = 4;
	Node.ENTITY_REFERENCE_NODE = 5;
	Node.ENTITY_NODE = 6;
	Node.PROCESSING_INSTRUCTION_NODE = 7;
	Node.COMMENT_NODE = 8;
	Node.DOCUMENT_NODE = 9;
	Node.DOCUMENT_TYPE_NODE = 10;
	Node.DOCUMENT_FRAGMENT_NODE = 11;
	Node.NOTATION_NODE = 12;
}

MARKKIT = { me: "incongnito", 
		    markid: 0,
			defaultLinkURL: "http://markkit.net/search/?cx=004024948312479226434%3Ax7cycutkoxy&cof=FORID%3A9&sa=Search&q=",
			setuser: function(xhr) { MARKKIT.me = xhr.responseText || 'anonymous'; }
		   }

function NodePath(root) {
	var rootNode = root || document.body,
		nodeNumbers = [];
	
	this.toString = function() {
		var s, i;
		
		s = ' [ ' + nodeNumbers[0];
		for (i=1; i < nodeNumbers.length; i++) {
			s += ', '+ nodeNumbers[i];
		}
		s += ' ] ';
		
		return s;
	}

	this.addParent = function(nodeNumber) {
		var oldNumbers = nodeNumbers, i;
		
		nodeNumbers = [nodeNumber]; // FIXME this should be a method of Array
		for (i=0; i < oldNumbers.length; i++) {
			nodeNumbers[i+1] = oldNumbers[i];
		}
		
		return this;
	}
	
	this.addChild = function(nodeNumber) {
		nodeNumbers[nodeNumbers.length] = nodeNumber;
		
		return this;
	}
	
	this.getNode = function() {
		var i, n;
		
		n = rootNode;
		for (i=0; i <nodeNumbers.length; i++) {
			n = n.getChild(nodeNumbers[i]);
		}
		
		return n;
	}
	
	this.getNumbers = function() {
		return nodeNumbers;
	}

	this.setNumbers = function(numbers) {
		nodeNumbers = numbers;
		return this;
	}
	
	this.length = function() {
		return nodeNumbers.length;
	}
	
	this.last = function() {
		return nodeNumbers[nodeNumbers.length - 1];
	}
	
	this.eq = function(otherNodePath) {
		var i;
		
		if (! (otherNodePath instanceof NodePath)) {
			return false;
		}
		
		othersNodeNumbers = otherNodePath.getNumbers();
		if (othersNodeNumbers.length != nodeNumbers.length) {
			return false;
		}
		
		for (i=0; i < nodeNumbers; i++) {
			if (nodeNumbers[i] != othersNodeNumbers[i]) {
				return false;
			}
		}
		
		return true;
	}
}

Node.prototype.siblingNumber = function () {
	var e = this
		i = 0; 
	while (e = e.previousSibling) {
		if (e.isNotOriginal) {
			continue;
		}
		i++;
	}
	
	return i;
}

Node.prototype.getChild = function (number) {
	var e, i; 
	
	e = this.firstChild;
	for ( i=1; i <= number; i++) {
		e = e.nextSibling;
		while (e.isNotOriginal) {
			e = e.nextSibling;
		}
	}
	
	return e;
}

Node.prototype.getNodePath = function(root) {
	var np = new NodePath(root),
		e = this;
	
	while (e != root) {
		np.addParent(e.siblingNumber());
		e = e.parentNode;
	}
	
	return np;
}

Range.prototype.getMark = function(root) {
	var location = new Mark;
	
	if (! root) {
		root = document.body;
	}
	location.startNodePath = this.startContainer.getNodePath(root);
	location.endNodePath = this.endContainer.getNodePath(root);
	location.startOffset = this.startOffset;
	location.endOffset = this.endOffset;
	
	return location;
}

Range.prototype.setMark = function(location) {
	var startNode, startOffset, endNode, endOffset;

	startNode   = location.startNodePath.getNode();
	endNode     = location.endNodePath.getNode();
	startOffset = location.startOffset;
	endOffset   = location.endOffset;
		
	this.setStart(startNode, startOffset);
	this.setEnd(endNode, endOffset);
} 


function textSelected() {
	selection = window.getSelection();
	textRange = document.createRange();
	if ( ! selection.isCollapsed) {
		textRange = selection.getRangeAt(0);
	}
	selection.removeAllRanges();
	
	return textRange;
}

function unmark(markId) {
	markElement = document.getElementById(markId);
	markElement.parentNode.replaceChild(markElement.firstChild, markElement);
}

function Mark(location) {
	
	var id = 'mark_' + MARKKIT.markid++;
	this.text = '';
	
	this.pageUrl = document.location.href;
	this.owner = MARKKIT.me;
	this.startNodePath = new NodePath(document.body);
	this.startOffset = 0;
	this.endNodePath = new NodePath(document.body);
	this.endOffset = 0;

	this.showLinkOptions = function (event) {
	overlib('<a class=\'marked\' onclick=\'unmark("' + id + '")\' >unmark</a>', STICKY, MOUSEOFF, TIMEOUT, 2000, WRAP, CELLPAD, 5, FGCOLOR, 'white', BGCOLOR, 'red');
	}
	
	this.toString = function () {
		return this.text;
	}
	
	this.save = function(markServer) {
		markServer.saveMark(this);
	}
	
	this.eq = function (other, noCheckBack) {
		var startsAreEqual = false, 
			endsAreEqual = false;
		
		noCheckBack = noCheckBack || false;

		if (! (other instanceof Mark)) {
			return false;
		}

		if (this.pageUrl != other.pageUrl) {
			return false;
		}
		
		if ( this.startNodePath.eq(other.startNodePath) ) {
			startsAreEqual = true;
		} else {
			if ( this.startOffset === 0 ) {
				if (this.startNodePath.length() === other.startNodePath.length() + 1) {
					if ((this.startNodePath.last() + 1) === other.startOffset) {
						startsAreEqual = true;
					}
				} 
			}
		}
		
		if ( this.endNodePath.eq(other.endNodePath) ) {
			endsAreEqual = true;
		} else {
			if ( this.endOffset === 0 ) {
				if (this.endNodePath.length() === other.endNodePath.length() + 1) {
					if ((this.endNodePath.last() + 1) == other.endOffset) {
						endsAreEqual = true;
					}
				}
			}
		}
		
		if (startsAreEqual && endsAreEqual) {
			return true;
		} else {
			if (noCheckBack) {
				return false;
			} else {
				if (other.eq(this, true)) {
					return true; 
				} else {
					return false;
				}
			}
		}
		return false;
	}

	this.createLink = function() {
		var range = document.createRange();

		range.setMark(this);
		this.link = document.createElement("a");
		this.link.isNotOriginal = true;
		this.link.id = id;
		this.link.href = MARKKIT.defaultLinkURL + encodeURIComponent(range);
		this.link.style.background = "yellow";
		this.link.style.color = "blue";
		this.link.addEventListener( "mouseover", this.showLinkOptions, false);
		range.surroundContents(this.link);
		this.text = range.toString();
	}

	if (location instanceof Range) {
		this.startNodePath = location.getMark().startNodePath;
		this.startOffset = location.getMark().startOffset;
		this.endNodePath = location.getMark().endNodePath;
		this.endOffset = location.getMark().endOffset;
		this.createLink();
	} 

}

parseJSONmarks = function(json) {
	var marks = [];

	eval("locations="+json);
	for (mn=0; mn < locations.length; mn++ ) {
		marks[mn] = new Mark();
		marks[mn].pageUrl = locations[mn].pageUrl;
		marks[mn].startNodePath = new NodePath().setNumbers(locations[mn].startNodePath);
		marks[mn].startOffset = locations[mn].startOffset;
		marks[mn].endNodePath = new NodePath().setNumbers(locations[mn].endNodePath);
		marks[mn].endOffset = locations[mn].endOffset;
		marks[mn].createLink();
	}

	return marks;
}

function MarkServer(saveUrl, loadUrl) {
	var saveUrl = saveUrl,
		loadUrl = loadUrl;
		
		
	this.loading = false;
	MarkServer.prototype.marks = [];

	this.handleRequest = function(transport) {
		MarkServer.prototype.marks = parseJSONmarks(transport.responseText);
		this.loading = false;
	}
	
	this.loadMarks = function (pageUrl) {
		var pageUrl = pageUrl || document.location.href;
		this.loading = true;
		handleRequest = this.handleRequest;
		request = new Ajax.Request(loadUrl, {
			method: "GET",
			onSuccess: handleRequest
		});

		return MarkServer.marks;
	}
	
	this.saveMark = function (mark) {
		var serverMark = { pageUrl: mark.pageUrl,
						   startNodePath: mark.startNodePath.toString(),
						   endNodePath: mark.endNodePath.toString(),
						   startOffset: mark.startOffset,
						   endOffset: mark.endOffset,
						   text: mark.toString(),
						   owner: mark.owner };

		new Ajax.Request(saveUrl, {
			method: "POST",
			parameters: serverMark
		});
	}
}

function markSelected(event) {
	selection = textSelected();
	if ( ! selection.collapsed) {
		mark = new Mark(selection);
		mark.save(pageMarkServer);
	}
}

function showRange(event) {
	selection = textSelected();
	alert("start : " + selection.startContainer.parentNode + "/" + selection.startOffset + " end : " + selection.endContainer + "/" + selection.endOffset);
}

function gup( name ) {
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

function getCookie( name ) {
	var start = document.cookie.indexOf( name + "=" );
	var len = start + name.length + 1;
	if ((!start) && (name != document.cookie.substring(0, name.length))) {
		return null;
	}
	if ( start == -1 ) return null;
	var end = document.cookie.indexOf( ';', len );
	if ( end == -1 ) end = document.cookie.length;
	return unescape( document.cookie.substring( len, end ) );
}
