/**********************************************************

	Browser Independent Object Library

	Version: 0.4 (Beta)
	Author: Fred Snyder
	Company: Castwide Technologies
	URL: http://castwide.com
	Date Created: May 3, 2005
	Date Modified: March 28, 2006
	
	Updates:
	06/11/2005 - Fixed BIOSelection selectNode() function
	03/28/2006 - Added range selection functions

	This application is free for use, modification, and
	and distribution.  This header, including the above
	notices and credits, must remain intact and unchanged.

**********************************************************/

function BIOEvent(e) {
	if (window.event) {
		this._event = window.event;
	} else {
		this._event = e;
	}
	this.keyCode = function() {
		if (this._event.keyCode) {
			return this._event.keyCode;
		}
		return this._event.which;
	}
	this.setKeyCode = function(i) {
		if (this._event.keyCode) {
			//this._event.keyCode = i;
		} else {
			this._event.which = i;
		}
	}
	this.target = function() {
		if (this._event.target) {
			return this._event.target;
		}
		return this._event.srcElement;
	}
	this.stopPropagation = function() {
		if (this._event.stopPropagation) {
			this._event.stopPropagation();
		} else {
			this._event.cancelBubble = true;
		}
	}
	this.preventDefault = function(b) {
		if (this._event.preventDefault) {
			this._event.preventDefault(b);
		}
	}
}

function BIOSelection(w) {
	// Assume win is parent window if not specified
	if (!w) {
		//alert('Default window!');
		this.win = window;
	} else {
		this.win = w;
	}
	if (this.win.document.selection) {
		//this.win.focus();
		this._IERange = this.win.document.selection.createRange();
	} else if (this.win.getSelection) {
		//this.win.document.execCommand("useCSS", false, true);
		var tmp = this.win.getSelection();
		if (tmp.rangeCount == null) {
			// This is an attempt at a Safari workaround
			this._FFRange = tmp.createRange();
		} else if (tmp.rangeCount == 0) {
			// Default Firefox range creation when no range exists
			this._FFRange = this.win.document.createRange();
			this._FFRange.selectNodeContents(this.win.document.body);
			this._FFRange.collapse(false);
		} else {
			// Select current range in Firefox
			this._FFRange = tmp.getRangeAt(0);
		}
	} else {
		alert('Error: unable to get selection');
	}
	
	this.collapse = function(dir) {
		if (this._IERange) {
			this._IERange.collapse(dir);
		} else if (this._FFRange) {
			this._FFRange.collapse(dir);
		}
	}
	
	this.pasteHTML = function(sHTML) {
		if (this._IERange) {
			this._IERange.pasteHTML(sHTML);
		} else if (this._FFRange) {
			var node = this._FFRange.createContextualFragment(sHTML);
			this._FFRange.deleteContents();
			this._FFRange.insertNode(node);
		}
	}

	this.surround = function(n) {
		if (this._IERange) {
			var sHTML = this._IERange.htmlText;
			if (sHTML == '') sHTML = '&nbsp;';
			n.innerHTML = sHTML;
			this._IERange.pasteHTML(n.outerHTML);
			if (sHTML == '&nbsp;') {
				this._IERange.findText(' ', -1);
				this._IERange.select();
				this.win.focus();
			}
		} else if (this._FFRange) {
			if (this._FFRange.toString() == "") {
				n.innerHTML = '';
				this._FFRange.deleteContents();
				this._FFRange.insertNode(n);
				this._FFRange.setEnd(n, 0);
			} else {
				n.appendChild(this._FFRange.extractContents());
				this._FFRange.insertNode(n);
				this._FFRange.collapse(false);
			}
		} else {
			alert('No selection for surround');
		}
	}
	
	this.format = function() {
		if (this._IERange) {
			this._IERange.execCommand("bold", null, null);
		} else if (this._FFRange) {
			var node = this._FFRange.startContainer;
			if (node == this._FFRange.endContainer) {
				// All in one container, so surround() is safe
				this.surround(document.createElement('B'));
				return;
			}
			while (node) {
				if (node.nodeType == 3) {
					var fmt = document.createElement('B');
					//alert(this._FFRange.startOffset);
					if ( (node == this._FFRange.startContainer) && (node == this._FFRange.endContainer) ) {
						fmt.innerHTML = node.nodeValue.substring(this._FFRange.startOffset, this._FFRange.endOffset);
					} else if (node == this._FFRange.startContainer) {
						fmt.innerHTML = node.nodeValue.substr(this._FFRange.startOffset);
					} else if (node == this._FFRange.endContainer) {
						fmt.innerHTML = node.nodeValue.substr(0, this._FFRange.endOffset);
					} else {
						fmt.innerHTML = node.nodeValue;
					}
					this._FFRange.insertNode(fmt);
					fmt.parentNode.removeChild(fmt.nextSibling);
					node = fmt;
					if (node.nextSibling) {
						node = node.nextSibling;
					} else {
						node = node.parentNode.nextSibling;
					}
					if (!isInsideID(node, 'editor')) {
						node = null;
					}
				} else {
					//if (node.firstChild) {
					//	node = node.firstChild;
					//} else {
						if ( (node == this._FFRange.endContainer) || (this._FFRange.endContainer.parentNode == node) ) {
							node.innerHTML = '<b>' + node.innerHTML.substr(0, this._FFRange.endOffset) + '</b>' + node.innerHTML.substr(this._FFRange.endOffset);
							node = null;
						} else {
							node.innerHTML = '<b>' + node.innerHTML + '</b>';
							node = node.nextSibling;
						}
					//}
				}
			}
		}
	}
	
	this.insertNode = function(n) {
		if (this._IERange) {
			//if (n.innerHTML == '') {
			//	n.innerHTML = '&nbsp;';
			//}
			this._IERange.pasteHTML(n.outerHTML + this._IERange.htmlText);
		} else if (this._FFRange) {
			this._FFRange.insertNode(n);
		} else {
			alert('No selection for insertNode');
		}
	}

	this.parentElement = function() {
		var n;
		if (this._IERange) {
			n = this._IERange.parentElement();
		} else if (this._FFRange) {
			n =  this._FFRange.commonAncestorContainer;
		} else {
			alert('nah');
		}
		while (n) {
			if (n.nodeType == 1) return n;
			n = n.parentNode;
		}
		return n;
	}
	
	this.innerHTML = function() {
		if (this._IERange) {
			return this._IERange.htmlText;
		} else if (this._FFRange) {
			return this._FFRange.toString();
		} else {
			alert('No selection');
		}
	}
	
	this.selectNode = function(n) {
		if (!n) {
			return null;
		}
		if (this._IERange) {
			// TODO: This method will not work for IE
			// if n is a text node (nodeType 3)
			return this._IERange.moveToElementText(n);
		} else if (this._FFRange) {
			return this._FFRange.selectNode(n);
		}
	}
	
	this.pasteNode = function(n) {
		if (this._IERange) {
			this._IERange.pasteHTML(n.outerHTML);
		} else if (this._FFRange) {
			this._FFRange.deleteContents();
			this.pasteHTML('&nbsp;');
			this._FFRange.insertNode(n);
		} else {
			alert('No selection for pasting node');
		}
	}

	this.setSelectionRange = function(node, start, end) {
		if (!this._IERange) {
			node.setSelectionRange(start, end);
		} else {
			this._IERange = node.createTextRange();
			this._IERange.collapse(true);
			this._IERange.moveStart("character", start);
			this._IERange.moveEnd("character", end - start);
			this._IERange.select();
		}
	}

	this.getSelectionRangeStart = function(node) {
		if (!this._IERange) {
			return node.selectionStart;
		}
		this._IERange = document.selection.createRange();
		var isCollapsed = this._IERange.compareEndPoints("StartToEnd", this._IERange) == 0;
		if (!isCollapsed)
			this._IERange.collapse(true);
		var b = this._IERange.getBookmark();
		return b.charCodeAt(2) - 2;
	}

	this.getSelectionRangeEnd = function(node) {
		if (!this._IERange) {
			return node.selectionEnd;
		}
		this._IERange = document.selection.createRange();
		var isCollapsed = range.compareEndPoints("StartToEnd", this._IERange) == 0;
		if (!isCollapsed) {
			range.collapse(false);
		}
		var b = range.getBookmark();
		return b.charCodeAt(2) - 2;
	}

}
