// It is better to use a constant for event.button
Event.LEFT = 0;
Event.MIDDLE = 1;
Event.RIGHT = 2;

Event.prototype.__defineSetter__("returnValue", function (b) {
	if (!b) this.preventDefault();
	return b;
});

Event.prototype.__defineSetter__("cancelBubble", function (b) {
	if (b) this.stopPropagation();
	return b;
});

Event.prototype.__defineGetter__("srcElement", function () {
	var node = this.target;
	while (node.nodeType != 1) node = node.parentNode;
	return node;
});

Event.prototype.__defineGetter__("fromElement", function () {
	var node;
	if (this.type == "mouseover")
		node = this.relatedTarget;
	else if (this.type == "mouseout")
		node = this.target;
	if (!node) return;
	while (node.nodeType != 1) node = node.parentNode;
	return node;
});

Event.prototype.__defineGetter__("toElement", function () {
	var node;
	if (this.type == "mouseout")
		node = this.relatedTarget;
	else if (this.type == "mouseover")
		node = this.target;
	if (!node) return;
	while (node.nodeType != 1) node = node.parentNode;
	return node;
});

Event.prototype.__defineGetter__("offsetX", function () {
	return this.layerX;
});
Event.prototype.__defineGetter__("offsetY", function () {
	return this.layerY;
});

HTMLDocument.prototype.attachEvent =
HTMLElement.prototype.attachEvent = function (sType, fHandler) {
	var shortTypeName = sType.replace(/on/, "");
	fHandler._ieEmuEventHandler = function (e) {
		window.event = e;
		return fHandler();
	};
	this.addEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
};

HTMLDocument.prototype.detachEvent =
HTMLElement.prototype.detachEvent = function (sType, fHandler) {
	var shortTypeName = sType.replace(/on/, "");
	if (typeof fHandler._ieEmuEventHandler == "function")
		this.removeEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
	else
		this.removeEventListener(shortTypeName, fHandler, true);
};

/*
 * Simple emulation of document.all
 * this one is far from complete. Be cautious
 */

var allGetter = function () {
	var a = this.getElementsByTagName("*");
	var node = this;
	a.tags = function (sTagName) {
		return node.getElementsByTagName(sTagName);
	};
	return a;
};
HTMLDocument.prototype.__defineGetter__("all", allGetter);
HTMLElement.prototype.__defineGetter__("all", allGetter);

HTMLElement.prototype.__defineGetter__("parentElement", function () {
	if (this.parentNode == this.ownerDocument) return null;
	return this.parentNode;
});

HTMLElement.prototype.__defineGetter__("children", function () {
	var tmp = [];
	var j = 0;
	var n;
	for (var i = 0; i < this.childNodes.length; i++) {
		n = this.childNodes[i];
		if (n.nodeType == 1) {
			tmp[j++] = n;
			if (n.name) {	// named children
				if (!tmp[n.name])
					tmp[n.name] = [];
				tmp[n.name][tmp[n.name].length] = n;
			}
			if (n.id)		// child with id
				tmp[n.id] = n
		}
	}
	return tmp;
});

HTMLElement.prototype.contains = function (oEl) {
	if (oEl == this) return true;
	if (oEl == null) return false;
	return this.contains(oEl.parentNode);
};

Document.prototype.elementFromPoint = function(x, y) {
	this.addEventListener("mousemove", this.elementFromPoint__handler, false);
	var event = this.createEvent("MouseEvents");
	var box = this.getBoxObjectFor(this.documentElement);
	var screenDelta = { x: box.screenX, y: box.screenY };
	event.initMouseEvent("mousemove", true, false, this.defaultView, 0, x + screenDelta.x, y + screenDelta.y, x, y, false, false, false, false, 0, null);
	this.dispatchEvent(event);
	this.removeEventListener("mousemove", this.elementFromPoint__handler, false);
	return this.elementFromPoint__target;
}
Document.prototype.elementFromPoint__handler = function (event) {
	this.elementFromPoint__target = event.explicitOriginalTarget;

	// reparent target if it is a text node to emulate IE"s behavior
	if (this.elementFromPoint__target.nodeType == Node.TEXT_NODE)
		this.elementFromPoint__target = this.elementFromPoint__target.parentNode;

	// change an HTML target to a BODY target to emulate IE"s behavior (if we are in an HTML document)
	if (this.elementFromPoint__target.nodeName.toUpperCase() == "HTML" && this.documentElement.nodeName.toUpperCase() == "HTML")
		this.elementFromPoint__target = this.getElementsByTagName("BODY").item(0);

	event.preventDefault();
	event.stopPropagation();
}
Document.prototype.elementFromPoint__target = null;

HTMLElement.prototype.__defineGetter__("currentStyle", function () {
	return this.ownerDocument.defaultView.getComputedStyle(this, null);
	/*
	var cs = {};
	var el = this;
	for (var i = 0; i < properties.length; i++) {
		cs.__defineGetter__(properties[i], encapsulateObjects(el, properties[i]));
	}
	return cs;
	*/
});

// This function is used to generate a html string for the text properties/methods
// It replaces "\n" with "<BR"> as well as fixes consecutive white spaces
// It also repalaces some special characters
function convertTextToHTML(s) {
	s = s.replace(/\&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<BR>");
	while (/\s\s/.test(s))
		s = s.replace(/\s\s/, "&nbsp; ");
	return s.replace(/\s/g, " ");
}

HTMLElement.prototype.insertAdjacentHTML = function (sWhere, sHTML) {
	var df;	// : DocumentFragment
	var r = this.ownerDocument.createRange();

	switch (String(sWhere).toLowerCase()) {
		case "beforebegin":
			r.setStartBefore(this);
			df = r.createContextualFragment(sHTML);
			this.parentNode.insertBefore(df, this);
			break;

		case "afterbegin":
			r.selectNodeContents(this);
			r.collapse(true);
			df = r.createContextualFragment(sHTML);
			this.insertBefore(df, this.firstChild);
			break;

		case "beforeend":
			r.selectNodeContents(this);
			r.collapse(false);
			df = r.createContextualFragment(sHTML);
			this.appendChild(df);
			break;

		case "afterend":
			r.setStartAfter(this);
			df = r.createContextualFragment(sHTML);
			this.parentNode.insertBefore(df, this.nextSibling);
			break;
	}
};

HTMLElement.prototype.__defineSetter__("outerHTML", function (sHTML) {
	var r = this.ownerDocument.createRange();
	r.setStartBefore(this);
	var df = r.createContextualFragment(sHTML);
	this.parentNode.replaceChild(df, this);

	return sHTML;
});

HTMLElement.prototype.__defineGetter__("canHaveChildren", function () {
	switch (this.tagName) {
		case "AREA":
		case "BASE":
		case "BASEFONT":
		case "COL":
		case "FRAME":
		case "HR":
		case "IMG":
		case "BR":
		case "INPUT":
		case "ISINDEX":
		case "LINK":
		case "META":
		case "PARAM":
			return false;
	}
	return true;
});

HTMLElement.prototype.__defineGetter__("outerHTML", function () {
	var attr, attrs = this.attributes;
	var str = "<" + this.tagName;
	for (var i = 0; i < attrs.length; i++) {
		attr = attrs[i];
		if (attr.specified)
			str += " " + attr.name + "=\"" + attr.value + "\"";
	}
	if (!this.canHaveChildren)
		return str + ">";

	return str + ">" + this.innerHTML + "</" + this.tagName + ">";
});


HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
	this.innerHTML = convertTextToHTML(sText);
	return sText;
});

var tmpGet;
HTMLElement.prototype.__defineGetter__("innerText", tmpGet = function () {
	var r = this.ownerDocument.createRange();
	r.selectNodeContents(this);
	return r.toString();
});

HTMLElement.prototype.__defineSetter__("outerText", function (sText) {
	this.outerHTML = convertTextToHTML(sText);
	return sText;
});
HTMLElement.prototype.__defineGetter__("outerText", tmpGet);

HTMLElement.prototype.insertAdjacentText = function (sWhere, sText) {
	this.insertAdjacentHTML(sWhere, convertTextToHTML(sText));
};

/*
 * This function binds the event object passed along in an
 * event to window.event
 */

function emulateEventHandlers(eventNames){
	for (var i = 0; i < eventNames.length; i++) {
		document.addEventListener(eventNames[i], function (e) {window.event = e;}, true);	// using capture
	}
}
emulateEventHandlers(["click", "dblclick", "mouseover", "mouseout","mousedown", "mouseup", "mousemove","keydown", "keypress", "keyup"]);

// Emulation de l"objet Séléction
function SelectionObject(Window) { 
    this.window=(Window?Window:window);
    this.document=this.window.document;
}

SelectionObject.prototype={
  "clear":function() {
      try {
          var sel = this.window.getSelection();
          sel.collapse(true);
          sel.dettach();
      } catch (ex) {}
  },
  "createRange":function() {
      if (this.type=="none") {
          return "no selection";
      }
      var txt = this.document.getSelection()
      var sel = {};
      try { sel=this.window.getSelection().getRangeAt(0); } catch (ex) {}
      var html = getHTMLOfSelection(this.window, this.document);
      var range = null;
      
      range = new ControlRangeObject();
      range._text=(""+txt+"");
      range._htmlText=html;
      range._range=sel;
      range.base=sel.commonAncestorContainer?sel.commonAncestorContainer:this.document.body
      range.items=new Array();
      range.addElement=range.add;
      
      try {
          while (range.base.nodeName.substr(0,1)=="#") {
              range.base=range.base.parentNode;
          }
          var index = 0; var started;
          var current = range.base.childNodes[0];
          while (current) {
              if (started || current==sel.startContainer || current==sel.commonAncestorContainer) {
                  started = true;
                  range.items.push(current);
              }
              if (current == sel.endContainer || current==sel.commonAncestorContainer) {
                  break;
              }
              index++;
              current = range.base.childNodes[index];
          }
          range.length=range.items.length;
      } catch (ex) {}
      
      return range;
    }
}

SelectionObject.prototype.empty=SelectionObject.prototype.clear;
SelectionObject.prototype.createRangeControl=SelectionObject.prototype.createRange;
SelectionObject.prototype.__defineGetter__("type", function() {
  try {
      var sel = this.window.getSelection().getRangeAt(0);
      if (sel.commonAncestorContainer.nodeName.substr(0,1)=="#") {
          return "text";
      } else {
          return "control";
      }
  } catch (ex) {}
  return "none";
})
SelectionObject.prototype.__defineSetter__("type", function() {
  // Do nothing
})

// ControlRangeObject
function ControlRangeObject() {}
ControlRangeObject.prototype={
    "_text":"",
    "_htmlText":"",
    "_range":null,
    "parentElement":function() {
        return this.base;
    },
    "item":function(i) {
        return this.items[i];
    },
    "add":function(node) {
        try {
            this._range.insertNode(node);
        } catch (ex) {}
    },
    "execCommand":function(a1,a2,a3,a4) {
        var mode = document.designMode;
        document.designMode="on";
        document.execCommand(a1,a2,a3,a4);
        document.designMode=mode;
    }
}
// Properties
ControlRangeObject.prototype.__defineGetter__("text",function() {
    return this._text;
});
ControlRangeObject.prototype.__defineSetter__("text",function(value) {
    var range = this._range;
    var p=document.createTextNode(value);
    range.deleteContents();
    range.insertNode(p)
});

ControlRangeObject.prototype.__defineGetter__("htmlText",function() {
    return this._htmlText
});
ControlRangeObject.prototype.__defineSetter__("htmlText",function(value) {
    var range = this._range;
    var p=document.createElement("htmlSection");
    p.innerHTML=value;
    range.deleteContents();
    range.insertNode(p)
});

document.selection=new SelectionObject();

function getHTMLOfSelection (window, document) {
  var range;
  if (window.ActiveXObject && document.selection && document.selection.createRange) {
    range = document.selection.createRange();
    return range.htmlText;
  }
  else if (window.getSelection) {
    var selection = window.getSelection();
    if (selection.rangeCount > 0) {
      range = selection.getRangeAt(0);
      var clonedSelection = range.cloneContents();
      var div = document.createElement("div");
      div.appendChild(clonedSelection);
      return div.innerHTML;
    }
    else {
      return "";
    }
  }
  else {
    return "";
  }
}

