wmp.provide("wmp.dom");

wmp.dom.ELEMENT_NODE                = 1;
wmp.dom.ATTRIBUTE_NODE              = 2;
wmp.dom.TEXT_NODE                   = 3;
wmp.dom.CDATA_SECTION_NODE          = 4;
wmp.dom.ENTITY_REFERENCE_NODE       = 5;
wmp.dom.ENTITY_NODE                 = 6;
wmp.dom.PROCESSING_INSTRUCTION_NODE = 7;
wmp.dom.COMMENT_NODE                = 8;
wmp.dom.DOCUMENT_NODE               = 9;
wmp.dom.DOCUMENT_TYPE_NODE          = 10;
wmp.dom.DOCUMENT_FRAGMENT_NODE      = 11;
wmp.dom.NOTATION_NODE               = 12;


/**
 * Determines whether the ancestorNode is an ancestor of the descendantNode. If the ancestorNode is the descendantNode, the method returns true.
 * @param {Node} ancestorNode 
 * @param {Node} descendantNode 
 * @param {Node} limitNode Optional. The search will stop at this node, no matter what happens. 
 * @type Boolean
 */
wmp.dom.isAncestorOf = function(ancestorNode, descendantNode, limitNode) {
	var checkNode = descendantNode;
	while(checkNode) {
		if(checkNode == ancestorNode) return true;
		else if(checkNode == limitNode) return false;
		else checkNode = checkNode.parentNode;
	}
	return false;
}

/**
 * Gets the index of this node among all its parent's child nodes.
 * @param {Node} node The node to check.
 * @type Integer
 */
wmp.dom.getIndex = function(node) {
	if(!node.parentNode) return null;
	for(var c=0; c < node.parentNode.childNodes.length; c++) {
		if(node.parentNode.childNodes[c] == node) return c;
	}
	return c;
}

/**
 * Returns the first node which is an ancestor of both given nodes.
 * @param {Node} firstNode 
 * @param {Node} secondNode
 * @type Node
 */
wmp.dom.getCommonAncestor = function(firstNode, secondNode) {
	var ancestor = firstNode;
	while(ancestor) {
		if(wmp.dom.isAncestorOf(ancestor, secondNode)) return ancestor;
		else ancestor = ancestor.parentNode;
	}
	return null;
}


wmp.dom.selection = {};
// JSDoc hack

/**
 * Get the global selection object. Initiate it if necessary.
 * @type Selection
 */
wmp.dom.selection.get = function(doc) {
	if (!doc)
		var doc = document;
	//return new wmp.dom.Selection();
	if(!doc._wmp_selection) doc._wmp_selection = new wmp.dom.Selection(doc);
	else if(Browser.Engine.trident) doc._wmp_selection._init();
	return doc._wmp_selection;
}



wmp.dom.Selection = function(doc) {
  if (window.getSelection) {
  	var selection = doc.defaultView.getSelection();
  	for(var field in wmp.dom.Selection.prototype) 
  		selection[field] = wmp.dom.Selection.prototype[field];
  	return selection;
  } else {
    return new wmp.dom.InternetExplorerSelection(doc);
  }
}

wmp.dom.Range = function(selectRange) {
  if (document.createRange) {
  	var range;
  	if(selectRange) range = selectRange.cloneRange();
  	else range = document.createRange();
  	for(var field in wmp.dom.Range.prototype) 
  		range[field] = wmp.dom.Range.prototype[field];
  	return range;
  } else {
  	if(selectRange && selectRange._range) {
  		var range = new wmp.dom.InternetExplorerRange(selectRange._range.duplicate());
  		range._init();
  		return range;
  	}
  	else return new wmp.dom.InternetExplorerRange();
  }
}



/* ***** BEGIN LICENSE BLOCK *****
 * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1
 * Full Terms at http://mozile.mozdev.org/0.8/LICENSE
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Jorgen Horstink and David Kingma's code.
 *
 * The Initial Developers of the Original Code are Jorgen Horstink and David Kingma.
 * Portions created by the Initial Developer are Copyright (C) 2005-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *	James A. Overton <james@overton.ca>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * @fileoverview Provides a W3C Range implementation under Internet Explorer.
 * <p>History: The original code was written by Jorgen Horstink (http://jorgenhorstink.nl/2006/03/11/w3c-range-in-internet-explorer/).
 * It was extensively modified by David Kingma.
 * This version has been adapted for use with Mozile by James A. Overton.
 * Key changes include wrapping the objects in the Mozile namespace, so as to minimize the impact on other scripts in the same page.
 *
 * Thomas Changes: replaced document with this.doc
 *
 * @link http://mozile.mozdev.org 
 * @author James A. Overton <james@overton.ca>
 * @version 0.8
 * $Id: InternetExplorerRange.js,v 1.2 2006/08/23 16:47:54 jameso Exp $
 */

wmp.provide("wmp.dom.InternetExplorerRange");

/**
 * Range object, see http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
 * @constructor
 */
wmp.dom.InternetExplorerRange = function(range, doc) {
	/**
	 * A reference to an IE native TextRange object.
	 * @private
	 * @type TextRange
	 */
	if (doc)
		this.doc = doc;
	else
		this.doc = document;
	
	this._range = null;

	if(range)
		this._range = range;
	else {
		this._range = this.doc.body.createTextRange();
	}

	/**
	 * A boolean indicating whether the range's start and end points are at the same position.
	 * @type Boolean
	 */
	this.collapsed = null;

	/**
	 * The deepest Node that contains the startContainer and endContainer Nodes.
	 * @type Node
	 */
	this.commonAncestorContainer = null;
	
	/**
	 * The Node within which the Range starts.
	 * @type Node
	 */
	this.startContainer = null;

	/**
	 * A number representing where in the endContainer the Range starts.
	 * @type Integer
	 */
	this.startOffset = null;

	/**
	 * The Node within which the Range ends.
	 * @type Node
	 */
	this.endContainer = null;

	/**
	 * A number representing where in the endContainer the Range ends.
	 * @type Integer
	 */
	this.endOffset = null;
}


/**
 * Initializes the properties of this range according to the internal
 * IE range (_range).
 * @private
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype._init = function () {
	
	//startPoint
	var beginRange = this._range.duplicate();
	beginRange.collapse(true);
	var position = this._getPosition(beginRange);
	this.startContainer = position.node;
	this.startOffset = position.offset;

	//endPoint
	var endRange = this._range.duplicate();
	endRange.collapse(false);
	position = this._getPosition(endRange);
	this.endContainer = position.node;
	this.endOffset = position.offset;
	
	this._commonAncestorContainer();
	this._collapsed();
	
}


/**
 * Takes an Internet Explorer TextRange object and returns a W3C node and offset pair.
 * <p>The basic method is as follows:
 * <ul><li>Create a new range with its start at the beginning of the element and its end at the target position. Set the rangeLength to the length of the range's text.
 * <li>Starting with the first child, for each child:
 * <ul><li>If the child is a text node, and its length is less than the rangeLength, then move the range's start by the text node's length.
 * <li>If the child is a text node and its length is less than the rangeLength then we've found the target. Return the node and use the remaining rangeLength as the offset.
 * <li>If the child is an element, move the range's start by the length of the element's innerText.
 * </ul></ul>
 * <p>This algorithm works fastest when the target is close to the beginning of the parent element.
 * The current implementation is smart enough pick the closest end point of the parent element (i.e. the start or the end), and work forward or backward from there.
 * @private
 * @param {TextRange} textRange A TextRange object. Its start position will be found.
 * @type Object
 * @return An object with "node" and "offset" properties.
 */
wmp.dom.InternetExplorerRange.prototype._getPosition = function(textRange) {
	var element = textRange.parentElement();
	var range = this.doc.body.createTextRange();
	try {
		range.moveToElementText(element);
	}
	catch (e)
	{
		return {node: element, offset: 0};
	}
	
	range.setEndPoint("EndToStart", textRange);
	var rangeLength = range.text.length;

	// Choose Direction
	if(rangeLength < element.innerText.length / 2) {
		var direction = 1;
		var node = element.firstChild;
	}
	else {
		direction = -1;
		node = element.lastChild;
		range.moveToElementText(element);
		range.setEndPoint("StartToStart", textRange);
		rangeLength = range.text.length;
	}

	// Loop through child nodes
	while(node) {
		switch(node.nodeType) {
			case wmp.dom.TEXT_NODE:
				nodeLength = node.data.length;
				if(nodeLength < rangeLength) {
					var difference = rangeLength - nodeLength;
					if(direction == 1) range.moveStart("character", difference);
					else range.moveEnd("character", -difference);
					rangeLength = difference;
				}
				else {
					if(direction == 1) return {node: node, offset: rangeLength};
					else return {node: node, offset: nodeLength - rangeLength};
				}
				break;

			case wmp.dom.ELEMENT_NODE:
				nodeLength = node.innerText.length;
				if(direction == 1) range.moveStart("character", nodeLength);
				else range.moveEnd("character", -nodeLength);
				rangeLength = rangeLength - nodeLength;
				break;
		}
	
		if(direction == 1) node = node.nextSibling;
		else node = node.previousSibling;
	}


	// TODO: This should throw a warning.
	//throw("Error in wmp.dom.InternetExplorerRange._getPosition: Ran out of child nodes before the range '"+ textRange.text +"' inside '"+ mozile.xpath.getXPath(element) +"' was found.");
	
	// The TextRange was not found. Return a reasonable value instead.
	return {node: element, offset: 0};
	
}


/**
 * Find the TextRange offset for a given text node and offset. Effectively the opposite of getPosition().
 * The method used is to count the innerText length for elements and the data length for text nodes.
 * @private
 * @param {Text} startNode The target text node.
 * @param {Integer} startOffset
 * @type Integer
 */
wmp.dom.InternetExplorerRange.prototype._getOffset = function (startNode, startOffset) {
	var node, moveCharacters;
	if(startNode.nodeType == wmp.dom.TEXT_NODE) {
		moveCharacters = startOffset;
		node = startNode.previousSibling;
	}
	else if(startNode.nodeType == wmp.dom.ELEMENT_NODE) {
		moveCharacters = 0;
		if(startOffset > 0) node = startNode.childNodes[startOffset - 1];
		else return 0;
	}
	else {
		mozile.debug.inform("wmp.dom.InternetExplorerRange.prototype._getOffset", "Bad node given: "/*+ mozile.xpath.getXPath(startNode)*/);
		return 0;
	}

	while (node) {
		var nodeLength = 0;
		if(node.nodeType == wmp.dom.ELEMENT_NODE) {
			nodeLength = node.innerText.length;
			if(this._isChildless(node)) nodeLength = 1; // Tweak childless nodes.
			if(this._isBlock(node)) nodeLength++; // Tweak block level elements.
			//if(nodeLength == 0) nodeLength++; // minimum length is 1
		}
		else if(node.nodeType == wmp.dom.TEXT_NODE) {
			 nodeLength = node.data.length;
		}
		moveCharacters += nodeLength;
		node = node.previousSibling;
	}
	
	return moveCharacters;
}

/**
 * Internet Explorer pads certain elements with an extra space at the end. This method detects those elements.
 * TODO: This method should be smarter about detecting non-HTML or using CSS.
 * @param {Node} node The node to check.
 * @type Boolean
 */
wmp.dom.InternetExplorerRange.prototype._isBlock = function(node) {
	switch (node.nodeName.toLowerCase()) {
		case 'p':
		case 'div':
		case 'h1':
		case 'h2':
		case 'h3':
		case 'h4':
		case 'h5':
		case 'h6':
		case 'pre':
			return true;
	}
	return false;
}

/**
 * Internet Explorer sets the length of certain elements which cannot have child nodes to 1.
 * TODO: Complete this list.
 * @param {Node} node The node to check.
 * @type Boolean
 */
wmp.dom.InternetExplorerRange.prototype._isChildless = function(node) {
	switch (node.nodeName.toLowerCase()) {
		case 'img':
		case 'br':
		case 'hr':
			return true;
	}
	return false;
}


// == positioning ==
/**
 * Sets the start position of a Range
 * If the startNode is a Node of type Text, Comment, or CDATASection, then startOffset 
 * is the number of characters from the start of startNode. For other Node types, 
 * startOffset is the number of child nodes between the start of the startNode.
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setStart = function (startNode, startOffset) {
	var container = startNode;
	if(startNode.nodeType == wmp.dom.TEXT_NODE || 
		startNode.nodeType == wmp.dom.COMMENT_NODE || 
		startNode.nodeType == wmp.dom.CDATA_SECTION_NODE) {
		container = container.parentNode;
	}

	var copyRange = this._range.duplicate();
	copyRange.moveToElementText(container);
	copyRange.collapse(true);
	copyRange.move('Character', this._getOffset(startNode, startOffset));
	this._range.setEndPoint('StartToStart', copyRange);

	//update object properties
	this.startContainer = startNode;
	this.startOffset    = startOffset;
	if (this.endContainer == null && this.endOffset == null) {
		this.endContainer = startNode;
		this.endOffset    = startOffset;
	}
	this._commonAncestorContainer();
	this._collapsed();
}


/**
 * Sets the end position of a Range.
 * Creates a clone of the current range, moves it to the desired spot
 * and the we move the endPoint of the current range to the clones endpoint
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setEnd = function (endNode, endOffset) {
	// Store the start of the range
	var copyRange = this._range.duplicate();
	copyRange.collapse(true);
	
	var container = endNode;
	if(endNode.nodeType == wmp.dom.TEXT_NODE || 
		endNode.nodeType == wmp.dom.COMMENT_NODE || 
		endNode.nodeType == wmp.dom.CDATA_SECTION_NODE) {
		container = container.parentNode;
	}

	var copyRange = this._range.duplicate();
	copyRange.moveToElementText(container);
	copyRange.collapse(true);
	copyRange.move('Character', this._getOffset(endNode, endOffset));
	this._range.setEndPoint('EndToEnd', copyRange);
	
	//update object properties
	this.endContainer = endNode;
	this.endOffset    = endOffset;
	if (this.startContainer == null && this.startOffset == null) {
		this.startContainer = endNode;
		this.startOffset    = endOffset;
	}
	this._commonAncestorContainer();
	this._collapsed();
}


/**
 * Sets the start position of a Range relative to another Node.
 * The parent Node of the start of the Range will be the same as 
 * that for the referenceNode.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setStartBefore = function (referenceNode) {
	this.setStart(referenceNode.parentNode, wmp.dom.getIndex(referenceNode));
};

/**
 * Sets the start position of a Range relative to another Node.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setStartAfter = function (referenceNode) {
	this.setStart(referenceNode.parentNode, wmp.dom.getIndex(referenceNode) + 1);
};

/**
 * Sets the end position of a Range relative to another Node.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setEndBefore = function (referenceNode) {
	this.setEnd(referenceNode.parentNode, wmp.dom.getIndex(referenceNode));
};

/**
 * Sets the end position of a Range relative to another Node.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.setEndAfter = function (referenceNode) {
	this.setEnd(referenceNode.parentNode, wmp.dom.getIndex(referenceNode) + 1);
};

/**
 * Sets the Range to contain the node and its contents.
 * The parent Node of the start and end of the Range will be the same as
 * the parent of the referenceNode.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.selectNode = function (referenceNode) {
	this.setStartBefore(referenceNode);
	this.setEndAfter(referenceNode);
};

/**
 * Sets the Range to contain the contents of a Node.
 * The parent Node of the start and end of the Range will be the referenceNode. The 
 * startOffset is 0, and the endOffset is the number of child Nodes or number of characters 
 * contained in the reference node.
 * @param {Node} referenceNode
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.selectNodeContents = function (referenceNode) {
	this.setStart(referenceNode, 0);
	if(referenceNode.nodeType == wmp.dom.TEXT_NODE)
		this.setEnd(referenceNode, referenceNode.data.length);
	else
		this.setEnd(referenceNode, referenceNode.childNodes.length);
};

/**
 * Collapses the Range to one of its boundary points.
 * @param {Boolean} toStart When true the Range is collapsed to the start position, when false to the end position.
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.collapse = function (toStart) {
	this._range.collapse(toStart);
	
	//update the properties
	if(toStart) {
		this.endContainer = this.startContainer;
		this.endOffset = this.startOffset;
	} else {
		this.startContainer = this.endContainer;
		this.startOffset = this.endOffset;
	}
	this._commonAncestorContainer();
	this._collapsed();
};

// == editing ==
/**
 * Returns a document fragment copying the nodes of a Range.
 * Partially selected nodes include the parent tags necessary to make the 
 * document fragment valid.
 * @type Range
 */
wmp.dom.InternetExplorerRange.prototype.cloneContents = function () {
	var df = this.doc.createDocumentFragment();
	
	var container = this.commonAncestorContainer;
	if(container.nodeType == wmp.dom.TEXT_NODE) {
		df.appendChild(this.doc.createTextNode(this._range.text));
		return df;
	}
	
	var startNode = this.startContainer;
	if(this.startContainer.nodeType != wmp.dom.TEXT_NODE)
		startNode = this.startContainer.childNodes[this.startOffset];
	var endNode = this.endContainer;
	if(this.endContainer.nodeType != wmp.dom.TEXT_NODE)
		endNode = this.endContainer.childNodes[this.endOffset - 1];

	if(startNode == endNode) {
		df.appendChild(startNode.cloneNode(true));
		return df;
	}

	// Walk the tree.
	var current = container.firstChild;
	var parent = null;
	var clone;
	while(current) {
		//alert(current.nodeName +"\n"+ df.innerHTML);
		// Watch for the start node, then start adding nodes.
		if(!parent) {
			if(wmp.dom.isAncestorOf(current, startNode, container)) {
				parent = df;
			}
			// Skip this node.
			else {
				current = current.nextSibling;
				continue;
			}
		}

		// Clone the node.
		if(current == startNode && this.startContainer.nodeType == wmp.dom.TEXT_NODE) {
			content = this.startContainer.data.substring(this.startOffset);
			parent.appendChild(this.doc.createTextNode(content));
		}
		else if(current == endNode) {
			if(this.endContainer.nodeType == wmp.dom.TEXT_NODE) {
				content = this.endContainer.data.substring(0, this.endOffset);
				parent.appendChild(this.doc.createTextNode(content));
			}
			else parent.appendChild(endNode.cloneNode(false));
			// We're done.
			break; 
		}
		else {
			clone = current.cloneNode(false);
			parent.appendChild(clone);
		}
		
		// Move
		if(current.firstChild) {
			parent = clone;
			current = current.firstChild;
		}
		else if(current.nextSibling) {
			current = current.nextSibling;
		}
		// Climb the tree
		else while(current) {
			if(current.parentNode) {
				parent = parent.parentNode;
				current = current.parentNode;
				if(current.nextSibling) {
					current = current.nextSibling;
					break;
				}
			}
			else current = null;
		}
	}
	
	return df;
};


wmp.dom.InternetExplorerRange.prototype.deleteContents = function () {
	if(this.collapsed)
		return;
	var container = this.commonAncestorContainer;
	if(container.nodeType == wmp.dom.TEXT_NODE) {
		var middle = container.splitText(this.startOffset);
		middle.splitText(this.endOffset-this.startOffset);
		middle.parentNode.removeChild(middle);
		return;
	}
	
	var startNode = this.startContainer;
	if(this.startContainer.nodeType != wmp.dom.TEXT_NODE)
		startNode = this.startContainer.childNodes[this.startOffset];
	var endNode = this.endContainer;
	if(this.endContainer.nodeType != wmp.dom.TEXT_NODE)
		endNode = this.endContainer.childNodes[this.endOffset - 1];
	
	if(startNode == endNode) {
		startNode.parentNode.removeChild(startNode);
		return;
	}
	
	// Walk the tree.
	var current = container.firstChild;
	while(current) {
		var next = wmp.xml.walkThrough(current, container);
		if (current == startNode) {
			if (current.nodeType == 3)
			{
				if (this.startOffset != 0 && this.startOffset != current.nodeValue.length) {
					current.splitText(this.startOffset);
				}
				if (this.startOffset != 0)
					current = current.nextSibling;
			}
			var beginTheKilling = true;
		}
		if (beginTheKilling && !wmp.dom.isAncestorOf(current, endNode, container)) {
			next = wmp.xml.nextNode(current, container);
			current.parentNode.removeChild(current);
		}
		
		if (current == endNode) {
			if (current.nodeType == 3) {
				if (this.endOffset < current.nodeValue.length) {
					current.splitText(this.endOffset);
				}
			}
			current.parentNode.removeChild(current);
			break;
		}
		current = next;
	}
	//update properties
	this.collapse(true);
	this._commonAncestorContainer();
};

wmp.dom.InternetExplorerRange.prototype.extractContents = function () {
	var fragment = this.cloneContents();
	this.deleteContents();
	return fragment;
};

/**
 * Insert a node at the start of a Range.
 * newNode is inserted at the start boundary point of the Range. If the newNodes 
 * is to be added to a text Node, that Node is split at the insertion point, and 
 * the insertion occurs between the two text Nodes
 * 
 * If newNode is a document fragment, the children of the document fragment are  
 * inserted instead.
 * @param {Node} newNode The node to insert.
 * @type Void
 */
 
 
 
 
 
 
 
wmp.dom.InternetExplorerRange.prototype.insertNode = function (newNode) {
	//salert('wmp.dom.InternetExplorerRange.insertNode() is not implemented yet');
	if(this.startContainer.nodeType == wmp.dom.TEXT_NODE){
		
		//kills ie
		//for (var a in this.startContainer)
		//	alert(a + ": " + this.startContainer[a]);
		
		//if (this.startOffset>0) {
			this.startContainer.splitText(this.startOffset);
			this.startContainer.parentNode.insertBefore(newNode, this.startContainer.nextSibling);
			this.setStart(this.startContainer, this.startOffset);
		//}
		//else {
			//this.startContainer.parentNode.insertBefore(newNode, this.startContainer);
		//}
		//Mozilla collapses, is this needed?
		//this.collapse(true);
		//this._range.select();
		return;
	} else { //Element node
		var parentNode = this.startContainer.parentNode;
		if(this.startContainer.childNodes.length == this.startOffset) {
			parentNode.appendChild(newNode);
		}else {
			this.startContainer.insertBefore(newNode, this.startContainer.childNodes.item(this.startOffset));
			this.setStart(this.startContainer, this.startOffset+1);
			//this._range.select();
			return;
		}
	}
};

/**
 * Moves content of a Range into a new node.
 * SurroundContents is equivalent to newNode.appendChild(range.extractContents());
 * range.insertNode(newNode). After surrounding, the boundary points of the Range 
 * include newNode.
 * @param {Node} newNode The node to select.
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.surroundContents = function (newNode) {
	newNode.appendChild(this.extractContents());
	this.insertNode(newNode);
};

// == Other ==
/**
 * NOT IMPLEMENTED. Compares the boundary points of two Ranges
 * Returns a number, 1, 0, or -1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange
 * Any of the following constants can be passed as the value of how parameter:
 * Range.END_TO_END compares the end boundary-point of sourceRange to the end boundary-point of range.
 * Range.END_TO_START compares the end boundary-point of sourceRange to the start boundary-point of range.
 * Range.START_TO_END compares the start boundary-point of sourceRange to the end boundary-point of range.
 * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range
 * @param {Integer} how A code for the comparison method.
 * @param {Range} sourceRange
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.compareBoundaryPoints = function (how, sourceRange) {
	alert('wmp.dom.InternetExplorerRange.compareBoundaryPoints() is not implemented yet');
};

/**
 * Returns a Range object with boundary points identical to the cloned Range.
 * @type Range
 */
wmp.dom.InternetExplorerRange.prototype.cloneRange = function () {
	var r = new wmp.dom.InternetExplorerRange(this._range.duplicate());
	var properties = ["startContainer", "startOffset", "endContainer", "endOffset", "commonAncestorContainer", "collapsed"];
	for(var i=0; i < properties.length; i++) {
		r[properties[i]] = this[properties[i]];
	}
	return r;
};

/**
 * Releases Range from use to improve performance.
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.detach = function () {};

/**
 * Returns the text of the Range.
 * @type String
 */
wmp.dom.InternetExplorerRange.prototype.toString = function () {
	return this._range.text;
};

/**
 * Finds the commonAncestorComtainer.
 * @private
 * @type Element
 */
wmp.dom.InternetExplorerRange.prototype._commonAncestorContainer = function () {
	if(this.startContainer == null || this.endContainer == null){
		this.commonAncestorContainer = null;
		return;
	}
	if(this.startContainer == this.endContainer) {
		this.commonAncestorContainer = this.startContainer;	
	}
	else {
		this.commonAncestorContainer = wmp.dom.getCommonAncestor(this.startContainer, this.endContainer);
	}
}

/**
 * Check to see if this selection is collapsed, and assign a value to this.collapsed.
 * @private
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype._collapsed = function () {
	this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
}



/**
 * Store the details about this range in an object which can be used to restore the range.
 * @type Object
 */
wmp.dom.InternetExplorerRange.prototype.store = wmp.dom.Range.prototype.store;

/**
 * Takes a stored range object and creates a new range with the same properties.
 * @param {Object} state A state object from Selection.store() or Range.store().
 * @type Void
 */
wmp.dom.InternetExplorerRange.prototype.restore = wmp.dom.Range.prototype.restore;

