var RichEditorConfig = new Object();
RichEditorConfig.url = "rich/"

Object.extend(Element, {
	getSize: function(element) {
		element = $(element);
		var width = element.style.width ? element.style.width   : (element.offsetWidth + 'px');
		var height = element.style.height ? element.style.height : (element.offsetHeight + 'px');
		return {
			width: width,
			height: height,
			w: parseInt(width.substring(0, width.length - 2), 10),
			h: parseInt(height.substring(0, height.length - 2), 10)
		};
	}
});

var RichEditor = Class.create();
RichEditor.prototype = {
	panelHeight: 28,
	disableButton: [],
	paraContainerTags: " body td th caption fieldset div",
	blockTags: " body form textarea fieldset ul ol dl li div " +
			   "p h1 h2 h3 h4 h5 h6 quote pre table thead " +
			   "tbody tfoot tr td th iframe address blockquote",
	initialize: function(id) {
		//Check Browser
		if (!Browser.is_ie && !Browser.is_gecko) {
			return;
		}
		//Add Css
		var head = document.getElementsByTagName("head")[0];
		var linkCss = document.createElement("link");
		linkCss.type = "text/css";
		linkCss.href = this.convertPath("richStyle.css");
		linkCss.rel = "stylesheet"
		head.appendChild(linkCss);

		this.textElement = $(id);
		//Set ClassName
		Element.addClassName(this.textElement, "richframe");

		//TextArea's size adjust
		this.textElementSize = Element.getSize(id);
		this.textElement.style.width = (this.textElementSize.w) + 'px';
		this.textElement.style.height = (this.textElementSize.h - this.panelHeight - 4) + 'px';

		//Create the iframe
		this.iframeElement = document.createElement("iframe");
		//Set iframe CSS
		this.iframeElement.className = "richframe";
		this.iframeElement.id = "iframe_" + id;
		this.iframeElement.setAttribute("frameBorder", "0");
		this.iframeElement.setAttribute("marginWidth", "0");
		this.iframeElement.setAttribute("marginHeight", "0");
		this.iframeElement.setAttribute("leftMargin", "0");
		this.iframeElement.setAttribute("topMargin", "0");
		this.iframeElement.style.width = (this.textElementSize.w - 2) + 'px';
		this.iframeElement.style.height = (this.textElementSize.h - this.panelHeight - 6) + 'px';

		//Hide the textArea Element
		this.textElement.style.display = "none";

		var richEditorDiv = document.createElement("div");
		this.textElement.parentNode.insertBefore(richEditorDiv, this.textElement);
		richEditorDiv.appendChild(this.createPanel());
		richEditorDiv.appendChild(this.iframeElement);

		//initialize iframe
		if (Browser.is_gecko) {
			this.iframeDocument = this.iframeElement.contentDocument;
		} else if (Browser.is_ie) {
			this.iframeDocument = this.iframeElement.contentWindow.document;
		}
		this.iframeDocument.designMode = "On";
		this.iframeDocument.write("");
		this.iframeDocument.close();
		Event.observe(this.iframeDocument, "keypress", this.maintainKey.bindAsEventListener(this), false);
	},
	doHTML: function() {
		this.controlPanel(false);
		this.iframeElement.style.display = "none";
		this.textElement.style.display = "block";
		this.textElement.value = this.iframeDocument.body.innerHTML;
		this.textElement.focus();
	},
	doRich: function() {
		this.controlPanel(true);
		this.iframeElement.style.display = "block";
		this.textElement.style.display = "none";
		this.iframeDocument.body.innerHTML = this.textElement.value;
		this.iframeDocument.designMode = "On";
		this.iframeElement.contentWindow.focus();
	},
	doRefreshHTML: function() {
		this.textElement.value = this.iframeDocument.body.innerHTML;
	},
	getHTML: function() {
		this.doRefreshHTML();
		return this.textElement.value;
	},
	convertPath: function(path) {
		return RichEditorConfig.url + path;
	},
	createPanel: function() {
		var tableElement = document.createElement("table");
		tableElement.className = "richpanelstyle";
		var rowElement = tableElement.insertRow(0);
		this.createButton(rowElement, "Bold", this.convertPath("img/bold.gif"), "richpanelbutton",
				function() {
					this.doRichEditCommand("bold", null);
				}.bind(this));
		this.createButton(rowElement, "Italic", this.convertPath("img/italic.gif"), "richpanelbutton",
				function() {
					this.doRichEditCommand("italic", null);
				}.bind(this));
		this.createButton(rowElement, "Underline", this.convertPath("img/underline.gif"), "richpanelbutton",
				function() {
					this.doRichEditCommand("underline", null);
				}.bind(this));
		this.createButton(rowElement, "Link", this.convertPath("img/link.gif"), "richpanelbutton",
				function() {
					var url = window.prompt("Please input the link url:", "http://");
					if (url != null && url != "") {
						this.doRichEditCommand("createlink", url);
					}
				}.bind(this));
		this.createButton(rowElement, "Unlink", this.convertPath("img/unlink.gif"), "richpanelbutton",
				function() {
					this.doRichEditCommand("unlink", null);
				}.bind(this));
		this.createButton(rowElement, "Image", this.convertPath("img/image.gif"), "richpanelbutton",
				function() {
					var url = window.prompt("Please input the image url:", "http://");
					if (url != null && url != "") {
						this.doRichEditCommand("insertimage", url);
					}
					this.iframeElement.contentWindow.focus();
				}.bind(this));
		this.createActiveButton(rowElement, "HTML", this.convertPath("img/code.gif"), "richpanelbutton",
				function() {
					this.doHTML();
				}.bind(this),
				function() {
					this.doRich();
				}.bind(this));
		return tableElement;
	},
	controlPanel: function(status) {
		for (var i = 0; i < this.disableButton.length; i++) {
			if (status) {
				Event.observe(this.disableButton[i].element, "click", this.disableButton[i].click, false);
			} else {
				Event.stopObserving(this.disableButton[i].element, "click", this.disableButton[i].click, false);
			}
		}
	},
	createButton: function(row, alt, imageSrc, className, clickHandler) {
		var cellElement = row.insertCell(-1);
		var imageElement = document.createElement("img");
		imageElement.setAttribute("alt", alt);
		imageElement.setAttribute("src", imageSrc);
		imageElement.className = className;
		Event.observe(imageElement, "mouseover",
				function() {
					imageElement.className = className + "Hover";
				}, false);
		Event.observe(imageElement, "mouseout",
				function() {
					imageElement.className = className;
				}, false);
		Event.observe(imageElement, "click", clickHandler, false);
		cellElement.appendChild(imageElement);
		this.disableButton[this.disableButton.length] = {element:imageElement, click:clickHandler};
	},
	createActiveButton: function(row, alt, imageSrc, className, clickHandler, activeHandler) {
		var cellElement = row.insertCell(-1);
		var imageElement = document.createElement("img");
		imageElement.setAttribute("alt", alt);
		imageElement.setAttribute("src", imageSrc);
		imageElement.className = className;
		imageElement.onmouseover = function() {
			if (imageElement.className.indexOf("Active") == -1) {
				imageElement.className = className + "Hover";
			}
		}
		imageElement.onmouseout = function() {
			if (imageElement.className.indexOf("Active") == -1) {
				imageElement.className = className;
			}
		}
		imageElement.onclick = function() {
			if (imageElement.className.indexOf("Active") == -1) {
				clickHandler();
				imageElement.className = className + "Active";
			} else {
				activeHandler();
				imageElement.className = className + "Hover";
			}
		}
		cellElement.appendChild(imageElement);
	},
	doRichEditCommand: function(cmd, args) {
		if (this.iframeDocument.execCommand) {
			this.iframeDocument.execCommand(cmd, false, args);
			this.iframeElement.contentWindow.focus();
		}
	},
	maintainKey: function(event) {
		switch (event.keyCode) {
			case 13: // KEY enter
				if (Browser.is_gecko && !event.shiftKey) {
					this.checkInsertParagraph();
					//Stop the key event
					event.preventDefault();
					event.stopPropagation();
				}
				break;
		}
	},
	checkInsertParagraph: function() {
		// Get the insertion point, we'll scrub any highlighted text the user wants rid of while we are there.
		var sel = this.getSelection();
		var range = this.createRange(sel);
		if (!range.collapsed) {
			range.deleteContents();
		}
		var SC = range.startContainer;
		var SO = range.startOffset;
		var EC = range.endContainer;
		var EO = range.endOffset;

		if (SC == EC && SC == body && !SO && !EO) {
			p = this.iframeDocument.createTextNode(" ");
			body.insertBefore(p, body.firstChild);
			range.selectNodeContents(p);
			SC = range.startContainer;
			SO = range.startOffset;
			EC = range.endContainer;
			EO = range.endOffset;
		}
		var p = this.getAllAncestors();
		var block = null;
		var body = this.iframeDocument.body;
		for (var i = 0; i < p.length; ++i) {
			if (this.isParaContainer(p[i])) {
				break;
			} else if (this.isBlockElement(p[i]) && !/body|html/i.test(p[i].tagName)) {
				block = p[i];
				break;
			}
		}
		if (!block) {
			var wrap = range.startContainer;
			while (wrap.parentNode && !this.isParaContainer(wrap.parentNode)) {
				wrap = wrap.parentNode;
			}
			var start = wrap;
			var end = wrap;

			while (start.previousSibling) {
				if (start.previousSibling.tagName) {
					if (!this.isBlockElement(start.previousSibling)) {
						start = start.previousSibling;
					} else {
						break;
					}
				} else {
					start = start.previousSibling;
				}
			}
			while (end.nextSibling) {
				if (end.nextSibling.tagName) {
					if (!this.isBlockElement(end.nextSibling)) {
						end = end.nextSibling;
					} else {
						break;
					}
				} else {
					end = end.nextSibling;
				}
			}
			range.setStartBefore(start);
			range.setEndAfter(end);
			range.surroundContents(this.iframeDocument.createElement('p'));
			block = range.startContainer.firstChild;
			range.setStart(SC, SO);
		}
		range.setEndAfter(block);
		var r2 = range.cloneRange();
		sel.removeRange(range);
		var df = r2.extractContents();
		if (df.childNodes.length == 0) {
			df.appendChild(this.iframeDocument.createElement('p'));
			df.firstChild.appendChild(this.iframeDocument.createElement('br'));
		}
		if (df.childNodes.length > 1) {
			var nb = this.iframeDocument.createElement('p');
			while (df.firstChild) {
				var s = df.firstChild;
				df.removeChild(s);
				nb.appendChild(s);
			}
			df.appendChild(nb);
		}
		if (!/\S/.test(block.innerHTML)) block.innerHTML = "&nbsp;";
		p = df.firstChild;
		if (!/\S/.test(p.innerHTML)) p.innerHTML = "<br />";

		if (/^\s*<br\s*\/?>\s*$/.test(p.innerHTML) && /^h[1-6]$/i.test(p.tagName)) {
			df.appendChild(this.convertNode(p, "p"));
			df.removeChild(p);
		}
		var newblock = block.parentNode.insertBefore(df.firstChild, block.nextSibling);
		sel = this.getSelection();
		sel.removeAllRanges();
		sel.collapse(newblock, 0);

		this.scrollToElement(newblock);
	},
	createRange: function(selection) {
		if (Browser.is_ie) {
			return selection.createRange();
		} else {
			if (typeof selection != "undefined") {
				try {
					return selection.getRangeAt(0);
				} catch(e) {
					return this.iframeDocument.createRange();
				}
			} else {
				return this.iframeDocument.createRange();
			}
		}
	},
	getSelection: function() {
		if (Browser.is_ie) {
			return this.iframeDocument.selection;
		} else {
			return this.iframeElement.contentWindow.getSelection();
		}
	},
	getAllAncestors: function() {
		var p = this.getParentElement();
		var a = [];
		while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
			a.push(p);
			p = p.parentNode;
		}
		a.push(this.iframeDocument.body);
		return a;
	},
	isParaContainer: function(element) {
		return element && element.nodeType == 1 && (this.paraContainerTags.indexOf(" " + element.tagName.toLowerCase() + " ") != -1);
	},
	isBlockElement: function(element) {
		return element && element.nodeType == 1 && (this.blockTags.indexOf(" " + element.tagName.toLowerCase() + " ") != -1);
	},
	convertNode: function(element, newTagName) {
		var newElement = this.iframeDocument.createElement(newTagName);
		while (element.firstChild) newElement.appendChild(element.firstChild);
		return newElement;
	},
	getParentElement: function(selection) {
		if (typeof selection == 'undefined') {
			selection = this.getSelection();
		}
		var range = this.createRange(selection);
		if (Browser.is_ie) {
			switch (selection.type) {
				case "Text":
				case "None":
					return range.parentElement();
				case "Control":
					return range.item(0);
				default:
					return this.iframeDocument.body;
			}
		} else {
			try {
				var p = range.commonAncestorContainer;
				if (!range.collapsed && range.startContainer == range.endContainer &&
					range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes())
					p = range.startContainer.childNodes[range.startOffset];
				while (p.nodeType == 3) {
					p = p.parentNode;
				}
				return p;
			} catch (e) {
				return null;
			}
		}
	},
	scrollToElement: function(element) {
		if (Browser.is_gecko) {
			var top = 0;
			var left = 0;
			while (element) {
				top += element.offsetTop;
				left += element.offsetLeft;
				if (element.offsetParent && element.offsetParent.tagName.toLowerCase() != 'body') {
					element = element.offsetParent;
				} else {
					element = null;
				}
			}
			this.iframeElement.contentWindow.scrollTo(left, top);
		}
	}
};

