/*******************************************************************************************
 * bbtagWysiwyg
 * Written by Craig Francis
 * A basic WYSIWYG editor for BB-Tag style content
 *
 * This source code is released under the BSD licence,
 * see the end of this script for the full details.
 * It was originally created by Craig Francis in 2006.
 *
 * http://www.craigfrancis.co.uk/features/code/jsBbtag/
 *
 *******************************************************************************************/

	var bbtagWysiwyg = new function() {

		//--------------------------------------------------
		// Old browsers

			if (!document.getElementById || !document.getElementsByTagName) {
				return;
			}

		//--------------------------------------------------
		// Initialisation

			this.init = function() {

				//--------------------------------------------------
				// Debug

					console.log('bbtagWysiwyg.js: Initialisation');

				//--------------------------------------------------
				// Get the references

					var textareas = document.getElementsByTagName('textarea');
					for (var k = (textareas.length - 1); k >= 0; k--) {
						if (cssjs('check', textareas[k], 'jsBbTagWysiwyg')) {
							bbtagWysiwyg.setup(textareas[k]);
						}
					}

			}

		//--------------------------------------------------
		// Setup

			this.setup = function(textarea) {

				//--------------------------------------------------
				// Debug

					console.log('bbtagWysiwyg.js: Found textarea (' + textarea.id + ')');

				//--------------------------------------------------
				// Get the parent form

					var parentForm = getParent(textarea, 'form');
					if (!parentForm) {
						console.log('bbtagWysiwyg.js: Missing parent form for textarea (' + textarea.id + ')');
					}

				//--------------------------------------------------
				// Build the editor

					var iframe = createElement('iframe');

					iframe.id = textarea.id + '_WYSIWYG';

					iframe.style.width = '97%';
					iframe.style.height = '300px';
					iframe.style.border = '1px solid #000';
					//iframe.style.width = textarea.style.width;
					//iframe.style.height = textarea.style.height;
					//iframe.style.frameBorder = 0;
					//iframe.style.scrolling = 'no';

					iframe.onload = function() {

							//--------------------------------------------------
							// Use design mode

								iframe.contentWindow.document.designMode = 'on';
								iframe.contentWindow.document.body.style.background = '#FFF';

							//--------------------------------------------------
							// Generate HTML

								bbtagWysiwyg.textarea2iframe(textarea, iframe);
								parentForm.onsubmit();

						};

				//--------------------------------------------------
				// Build the controls

					//--------------------------------------------------
					// Wrapper

						var controls = createElement('div');
						controls.editor = iframe;
						controls.style.margin = '0 0 5px 0';

					//--------------------------------------------------
					// Bold

						bbtagWysiwyg.addControl(controls, 'Bold', function(d, w) {

								var strong = bbtagWysiwyg.getElement(w, 'strong');
								var b = bbtagWysiwyg.getElement(w, 'b');

								if (strong) {
									bbtagWysiwyg.removeWrapper(strong);
								} else if (b) {
									bbtagWysiwyg.removeWrapper(b);
								} else {
									d.execCommand('styleWithCSS', false, false);
									d.execCommand('bold', false, null);
								}

							});

					//--------------------------------------------------
					// Italic

						bbtagWysiwyg.addControl(controls, 'Italic', function(d, w) {

								var em = bbtagWysiwyg.getElement(w, 'em');
								var i = bbtagWysiwyg.getElement(w, 'i');

								if (em) {
									bbtagWysiwyg.removeWrapper(em);
								} else if (i) {
									bbtagWysiwyg.removeWrapper(i);
								} else {
									d.execCommand('styleWithCSS', false, false);
									d.execCommand('italic', false, null);
								}

							});

					//--------------------------------------------------
					// Unordered list

						bbtagWysiwyg.addControl(controls, 'UL', function(d, w) {
								d.execCommand('insertorderedlist', false, null);
							});

					//--------------------------------------------------
					// Ordered list

						bbtagWysiwyg.addControl(controls, 'OL', function(d, w) {
								d.execCommand('insertunorderedlist', false, null);
							});

					//--------------------------------------------------
					// Heading

						bbtagWysiwyg.addControl(controls, 'Heading', function(d, w) {

								var heading = bbtagWysiwyg.getElement(w, 'h1');
								if (heading) {
									d.execCommand('formatblock', false, '<p>');
								} else {
									d.execCommand('formatblock', false, '<h1>');
								}

							});

					//--------------------------------------------------
					// Link

						bbtagWysiwyg.addControl(controls, 'Link', function(d, w) {

							//--------------------------------------------------
							// Current link

								var link = bbtagWysiwyg.getElement(w, 'a');

							//--------------------------------------------------
							// Get the url

								if (link) {
									var url = prompt('Edit the Link:', link.href);
								} else {
									var url = prompt('Create a Link:', 'http://');
								}

							//--------------------------------------------------
							// Apply

								if (url != null && url != '' && url != 'http://') {

									if (link) {
										link.href = url;
									} else {
										d.execCommand('CreateLink', false, url);
									}

									// link = '<a href="' + url + '" target="_blank">' + range.text + '</a>';
									// range.pasteHTML(link);

								} else if (link && url != null && url == '') {

									bbtagWysiwyg.removeWrapper(link);

								}

							});

					//--------------------------------------------------
					// Toggle

						textarea.showingWysiwyg = true;

						bbtagWysiwyg.addControl(controls, 'Toggle', function(d) {

								if (textarea.showingWysiwyg) {

									bbtagWysiwyg.iframe2textarea(iframe, textarea);

									textarea.style.display = 'block';
									iframe.style.display = 'none';

								} else {

									bbtagWysiwyg.textarea2iframe(textarea, iframe)

									textarea.style.display = 'none';
									iframe.style.display = 'block';

								}

								textarea.showingWysiwyg = !textarea.showingWysiwyg;

							});

				//--------------------------------------------------
				// Add

					textarea.parentNode.insertBefore(controls, textarea);
					textarea.parentNode.insertBefore(iframe, textarea);

				//--------------------------------------------------
				// Override the form action

					parentForm.onsubmit = function() {

						if (iframe.contentWindow) {
							bbtagWysiwyg.iframe2textarea(iframe, textarea);
						}

						return true;

					}

			}

		//--------------------------------------------------
		// textarea2iframe

			this.textarea2iframe = function(textarea, iframe) {

				//--------------------------------------------------
				// Debug

					console.log('bbtagWysiwyg.js: Converting BBTags to HTML (' + textarea.id + ')');

				//--------------------------------------------------
				// Value

					var value = textarea.value;
					console.log(value);

				//--------------------------------------------------
				// HTML entity encode

					value = value.replace(/</g, '&lt;');
					value = value.replace(/>/g, '&gt;');

				//--------------------------------------------------
				// White-space

					value = '<p>' + value + '</p>';
					value = value.replace(/\n\n/g, '</p><p>'); // Paragraphs
					value = value.replace(/\n/g, '<br />'); // Newline
					value = value.replace(/  /g, '&nbsp; '); // Space

				//--------------------------------------------------
				// Simple tags

					value = value.replace(/\[(\/)?B\]/gi, '<$1strong>'); // Bold
					value = value.replace(/\[(\/)?I\]/gi, '<$1em>'); // Italic

				//--------------------------------------------------
				// Heading

					value = value.replace(/\s*\[H\](.*?)\[\/H\]\s*/gi, "\n</p><h1>$1</h1><p>\n");

				//--------------------------------------------------
				// Links

					var matchRegExp = /\[(LINK|OPEN|MAIL) +("|')(.*?)\2(?: +\2(.*?)\2)?\]/gi;

					while ((match = matchRegExp.exec(value)) != null) {

						if (match[4] == undefined) {
							match[4] = match[3];
						}

						if (match[1] == 'MAIL') {
							match[3] = 'mailto:' + match[3];
						}

						var replace = '<a href="' + match[3] + '"' + (match[1] == 'OPEN' ? ' target="_blank"' : '') + '>' + match[4] + '</a>';

						value = value.replace(match[0], replace);

						matchRegExp.lastIndex = matchRegExp.lastIndex - match[0].length; // If replacement is shorter than original tag.

					}

				//--------------------------------------------------
				// Lists

					var matchRegExp = /\[LIST\](.*?)\[\/LIST\]/gi;

					while ((match = matchRegExp.exec(value)) != null) {

						var content = match[1].replace(/<br \/>/g, "\n");

						if (/^\s*#/.test(content)) {
							var list = 'ol';
						} else {
							var list = 'ul';
						}

						var replace = '<' + list + '>';

						var items = content.split("\n");
						var itemLength = items.length;
						for (var k = 0; k < itemLength; k++) {
							if (items[k] != '') {
								replace += '<li>' + items[k].replace(/^\s*(#|\*)/, '') + '</li>';
							}
						}
						replace += '</' + list + '>';

						value = value.replace(match[0], replace);

						matchRegExp.lastIndex = matchRegExp.lastIndex - match[0].length;

					}

				//--------------------------------------------------
				// Cleanup

					value = value.replace(/<p>\s*<\/p>/g, ''); // Empty paragraphs

				//--------------------------------------------------
				// Save

					iframe.contentWindow.document.body.innerHTML = value;
					console.log(value);

			}

		//--------------------------------------------------
		// iframe2textarea

			this.iframe2textarea = function(iframe, textarea) {

				//--------------------------------------------------
				// Debug

					console.log('bbtagWysiwyg.js: Converting HTML to BBTags (' + textarea.id + ')');

				//--------------------------------------------------
				// Value

					var value = iframe.contentWindow.document.body.innerHTML;
					console.log(value);

				//--------------------------------------------------
				// White-space

					value = value.replace(/<!--.*?-->/g, ''); // Comments
					value = value.replace(/^\s+|\s+$/g, ''); // Trim
					value = value.replace(/<p>(.*?)<\/p>/g, "$1\n\n"); // Paragraphs
					value = value.replace(/<br( \/)?>/g, "\n"); // Newline
					value = value.replace(/&nbsp;/g, ' '); // Space

				//--------------------------------------------------
				// Simple tags

					var matchRegExp = /<(\/)?(b|strong|em|i|span)([^>]*)>/gi;
					var openBold = 0;
					var openItalic = 0;
					var stack = [];

					while ((match = matchRegExp.exec(value)) != null) {

						var replace = '';

						if (match[1] == undefined) { // Open

							//--------------------------------------------------
							// Identify which tags

								tagBold = false;
								tagItalic = false;

								if (match[2] == 'b' || match[2] == 'strong') {
									tagBold = true;
								} else if (match[2] == 'i' || match[2] == 'em') {
									tagItalic = true;
								}

								if (/font-weight: bold/i.test(match[3])) tagBold = true;
								if (/font-weight: normal/i.test(match[3])) tagBold = false;
								if (/font-style: italic/i.test(match[3])) tagItalic = true;
								if (/font-style: normal/i.test(match[3])) tagItalic = false;

							//--------------------------------------------------
							// Add to stack

								stack[stack.length] = { 'tag' : match[2], 'bold' : tagBold, 'italic' : tagItalic };

							//--------------------------------------------------
							// Tag codes

								if (tagBold) {
									if (openBold == 0) replace += '[B]';
									openBold++;
								}

								if (tagItalic) {
									if (openItalic == 0) replace += '[I]';
									openItalic++;
								}

						} else {

							//--------------------------------------------------
							// Tags - caters for closing </span>

								var config = stack.pop();
								tagBold = config.bold;
								tagItalic = config.italic;

							//--------------------------------------------------
							// Tag codes

								if (tagItalic) {
									if (openItalic > 0) openItalic--;
									if (openItalic == 0) replace += '[/I]';
								}

								if (tagBold) {
									if (openBold > 0) openBold--;
									if (openBold == 0) replace += '[/B]';
								}

						}

						value = value.replace(match[0], replace);

						matchRegExp.lastIndex = matchRegExp.lastIndex - match[0].length; // If replacement is shorter than original tag.

					}

					value = value.replace(/\[\/B\]\[B\]/gi, '');
					value = value.replace(/\[\/I\]\[I\]/gi, '');

				//--------------------------------------------------
				// Heading

					value = value.replace(/\s*<h[0-9]>\s*([\w\W]*?)\s*<\/h[0-9]>\s*/gi, "\n\n[H]$1[/H]\n\n"); // Bold

				//--------------------------------------------------
				// Links

					var matchRegExp = /<a([^>]*)href="(mailto:)?([^"]+)"([^>]*)>(.*?)<\/a>/gi;

					while ((match = matchRegExp.exec(value)) != null) {

						if (match[2] != undefined) {
							var tag = 'MAIL';
						} else if (/_blank/.test(match[1]) || /_blank/.test(match[4])) {
							var tag = 'OPEN';
						} else {
							var tag = 'LINK';
						}

						if (match[3] == match[5]) {
							var replace = '[' + tag + ' "' + match[3] + '"]';
						} else {
							var replace = '[' + tag + ' "' + match[3] + '" "' + match[5] + '"]';
						}

						value = value.replace(match[0], replace);

						matchRegExp.lastIndex = matchRegExp.lastIndex - match[0].length; // If replacement is shorter than original tag.

					}

				//--------------------------------------------------
				// Lists

					var matchRegExp = /\s*<(ol|ul)>([\w\W]*?)<\/\1>\s*/gi; // \w\W used as "." ignores newline characters

					while ((match = matchRegExp.exec(value)) != null) {

						var content = match[2];
						var content = content.replace(/^\s*<li>/i, '');
						var content = content.replace(/<\/li>/gi, '');

						if (match[1] == 'ol') {
							var list = '#';
						} else {
							var list = '*';
						}

						var replace = "\n\n" + '[LIST]';

						var items = content.split(/<li>/i);
						var itemLength = items.length;
						for (var k = 0; k < itemLength; k++) {
							if (items[k] != '') {
								replace += "\n" + list + ' ' + items[k].replace(/^\s+|\s+$/g, '');
							}
						}

						replace += "\n" + '[/LIST]' + "\n\n";

						value = value.replace(match[0], replace);

						matchRegExp.lastIndex = matchRegExp.lastIndex - match[0].length;

					}

				//--------------------------------------------------
				// Cleanup

					value = value.replace(/<p>/g, ''); // Rouge paragraph - usually from the <h1> escaping the <p>
					value = value.replace(/<\/p>/g, '');

				//--------------------------------------------------
				// HTML entity decode (thanks tinyMCE)

					value = value.replace(/</g, '&lt;');
					value = value.replace(/>/g, '&gt;');

					var div = createElement('div');
					div.innerHTML = value;
					value = !div.firstChild ? value : div.firstChild.nodeValue;

						// This might need fixing, as looking at the
						// current version of tinyMCE, it now uses:
						//
						// e = this.doc.createElement("div");
						// e.innerHTML = s;
						// n = e.firstChild;
						// v = '';
						//
						// if (n) {
						// 	do {
						// 		v += n.nodeValue;
						// 	} while (n.nextSibling);
						// }
						//
						// return v || s;

				//--------------------------------------------------
				// Save

					textarea.value = value;
					console.log(value);

			}

		//--------------------------------------------------
		// Add control

			this.addControl = function(wrapper, name, action) {

				var control = createElement('a');
				control.appendChild(document.createTextNode(name));
				control.href = '#';
				control.onclick = function() {

						if (this.parentNode.editor.contentWindow) {
							var w = this.parentNode.editor.contentWindow;
							w.focus();
							action(w.document, w);
						}
						return false;

					};

				wrapper.appendChild(control);
				wrapper.appendChild(document.createTextNode(' '));

			}

		//--------------------------------------------------
		// Get element

			this.getElement = function(w, tagName) {

				if (w.getSelection) {
					var el = w.getSelection().getRangeAt(0).startContainer;
					if (el) {
						return getParent(el, tagName);
					}
				} else {
					alert('Not done yet');
				}

				return null;

			}

		//--------------------------------------------------
		// Remove wrapper

			this.removeWrapper = function(wrapper) {

				var ch = wrapper.childNodes;
				for (k = (ch.length - 1); k >= 0; k--) {
					wrapper.parentNode.insertBefore(ch[k], wrapper.nextSibling);
				}
				wrapper.parentNode.removeChild(wrapper);

			}

		//--------------------------------------------------
		// Set JS styles

			addCssRule('textarea.jsBbTagWysiwyg { display: none; }');

		//--------------------------------------------------
		// On page load

			addLoadEvent(function() {
				bbtagWysiwyg.init();
			});

	}

//--------------------------------------------------
// Copyright (c) 2008, Craig Francis All rights
// reserved.
//
// Redistribution and use in source and binary forms,
// with or without modification, are permitted provided
// that the following conditions are met:
//
//  * Redistributions of source code must retain the
//    above copyright notice, this list of
//    conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce
//    the above copyright notice, this list of
//    conditions and the following disclaimer in the
//    documentation and/or other materials provided
//    with the distribution.
//  * Neither the name of the author nor the names
//    of its contributors may be used to endorse or
//    promote products derived from this software
//    without specific prior written permission.
//
// This software is provided by the copyright holders
// and contributors "as is" and any express or implied
// warranties, including, but not limited to, the
// implied warranties of merchantability and fitness
// for a particular purpose are disclaimed. In no event
// shall the copyright owner or contributors be liable
// for any direct, indirect, incidental, special,
// exemplary, or consequential damages (including, but
// not limited to, procurement of substitute goods or
// services; loss of use, data, or profits; or business
// interruption) however caused and on any theory of
// liability, whether in contract, strict liability, or
// tort (including negligence or otherwise) arising in
// any way out of the use of this software, even if
// advised of the possibility of such damage.
//--------------------------------------------------