var ua = window.navigator.userAgent;

var Browser = function() {
	this.type = function() {
		if(ua.indexOf("MSIE ") > 0){return 'ie';}
		if(/Safari/.test(ua)){return 'safari'}
		if(/Firefox/.test(ua)){return 'firefox'}
	}
	this.isSafari = /Safari/.test(ua);
	this.isFirefox = /Firefox/.test(ua);
	this.isIE = (ua.indexOf("MSIE ") > 0);
	this.baseUrl = window.location.protocol + '//' + window.location.host
}

var busy = false;
var baseTools = [];

//builds the basetools array based on the buttons in _toolbar partial
var determineBaseTools = function(tname) {
	$A($(tname).childNodes).each(function(elem){
		if(elem.id){
			if(Element.hasClassName(elem, 'button')){
				baseTools.push(elem.id);
			}
		}
	});
}

// detect browser type
// display plain form if the browser is not one of the main 3
var browser = new Browser();
function detectBrowserCompat() {
	switch(browser.type()){
		case 'firefox':
			return true;
			break;
		case 'ie':
			return true;
			break;
		case 'safari':
			return true;
			break;
		default :
			return false;
	}
}

// toggles the display type on all items passed in the list
function toggle_items(list, tname, display) {
	//toggle each element in list
	var toolbar = $(tname);
	var elements = toolbar.childNodes;
	for (var e = elements.length - 1; e >= 0; e--) {
		if (list.include(toolbar.childNodes[e].id)) {
			toolbar.childNodes[e].style.display = display;
		}
	}
}

//this function hides unsupported execCommands in the different browsers
//param is toolbar name so it can support multiple editors on one page
function toolBarBuilder(tname) {
	if (browser.isSafari) {
		var list = baseTools.without('link', 'insertunorderedlist','insertorderedlist', 'indent', 'outdent', 'unlink');
		toggle_items(list, tname, 'block');
	}
	if (browser.isFirefox) {
		var list = baseTools;
		toggle_items(list, tname, 'block');
	}
	if (browser.isIE) {
		var list = baseTools;
		toggle_items(list, tname, 'block');
	}
}

function appendIframeObjects() {
	//alert('woot');
	if (browser.isIE) {
		//IE hack to keep ie from adding p tags on newlines
		var oDiv = this.doc.createElement("DIV");
		this.doc.body.appendChild(oDiv);
	}
}

var Editor = Class.create();
//params formName(the name of the form that is going to become the editor), updateDesc(boolean if you want to update the description)
Editor.prototype = {
	
	//initialize is called when you first create an editor object
	initialize: function(formName, updateDesc, callback) {
		// alert('laal');
		if(!detectBrowserCompat()) {return false;}
		this.tname = formName + '_toolbar';
		determineBaseTools(this.tname);
		this.formName = formName;
		this.determineFormElements();
		this.updateDescription = updateDesc ? updateDesc : false;
		this.fname = formName + '_frame';
		this.sourceEditName = this.tname + '_source_tabs';
		this.toolbar = $(this.tname);
		this.editingSource = false;
		
		this.createHtmlItems();
		toolBarBuilder(this.tname);
		
		new ToggleView(this.holder, this.fname);
		
		this.ifrm = $(this.fname);
		this.win = this.ifrm.contentWindow;
		var designMode = this.setDesignMode.bind(this); //set the context for the timeout on class method
		setTimeout(designMode, 500);
		var plainSource = this.setEditorPlainTextSource.bind(this);
		setTimeout(plainSource, 600);
		var events = this.addEventListeners.bind(this);
		setTimeout(events, 1000);
		var ifrmObj = appendIframeObjects.bind(this);
		setTimeout(ifrmObj, 1900);
		callback ? callback.call(this) : null
	},
	
	// this method is used to read the form elements in the form id passed to turn on the editor
	// it also adds an event listener to submit to update the postholder (like on a paste)
	// if the postholder has content (like on edit) write it to the editor
	determineFormElements: function() {
		Form.getElements(this.formName).each(function(elem) {
			if(elem.type == "textarea"){
				if (elem.id != 'post_description') {
					this.holder = elem;
				} else {
					this.description = elem;
				}
			}
		}.bind(this));
	},
	
	// inserts the html tabs, and iframe
	createHtmlItems: function() {
		var styleSheet = '<link rel="stylesheet" type="text/css" href="'+browser.baseUrl+'/stylesheets/editor.css" />';
		new Insertion.Top(this.sourceEditName, '<span id="'+this.tname+'_wrapper"><div id=\"editor_tabs\"><div><span id="source"><a  href="javascript:blankCall();" title="Click to Edit HTML">Edit HTML</a> <a href="/page/help#whatisedithtmlmode" target="_blank" title="Get help on Edit HTML Mode"><img src="/images/toolbar/editor_tab_help.gif" border="none" /></a> </span></div><div class="tab_selected"><span id="compose"><a href="javascript:blankCall();" title="Click to Compose with WYSIWYG Editor">Compose</a> <a href="/page/help#whatiscomposemode" target="_blank" title="Get help on Compose Mode"><img src="/images/toolbar/editor_tab_help.gif" border="none" /></a></span></div></div></span>');
		new Insertion.After(this.tname, '<iframe id="' + this.fname + '" class="edit_frame"> </iframe>');
		new Insertion.After(this.fname, '<input type="hidden" id="editor_state" name="editor_state" value="compose" />')
		var frameHtml = '<html>\n<head>'+styleSheet+'</head>\n<body>\n</body>\n</html>';
		var editFrame = $(this.fname).contentWindow.document;
		editFrame.open();
		editFrame.write(frameHtml);
		editFrame.close();
	},
	
	// called to remove the editor from the page
	removeEditor: function(){
		Element.remove(this.tname+'_wrapper');
		Element.remove(this.fname);
	},
	
	//set design modes and call to add event listeners
	//also call the append iframe objects method
	setDesignMode: function() {
		this.doc = this.ifrm.contentWindow.document;
		this.doc.designMode = "on";
		this.doc = this.ifrm.contentWindow.document;
		this.doc.contentEditable = true;
		this.fillHolder();
	},
	
	fillHolder: function() {
		if ($F(this.holder) != "") {
			if (browser.isIE) {
				this.doc.write(this.holder.firstChild.nodeValue);
			} else {
				this.ifrm.contentDocument.body.innerHTML = this.holder.firstChild.nodeValue;
			}
		}
	},
	
	//creates event listeners for updating areas that need it
	addEventListeners: function() {
		if (this.updateDescription) { 
				Event.observe(this.doc, 'keyup', this.updateDesc.bind(this));
				Event.observe(this.doc, 'mouseover', this.updateDesc.bind(this));
				Event.observe(this.doc, 'mouseout', this.updateDesc.bind(this));
			}
		Event.observe(this.doc, 'click', this.enableActiveButton.bind(this));
		Event.observe(this.toolbar, 'mousedown', this.execCmd.bind(this));
		
		Event.observe(this.doc, 'keyup', this.updatePostHolder.bind(this));
		Event.observe(this.doc, 'mouseover', this.updatePostHolder.bind(this));
		Event.observe(this.doc, 'mouseout', this.updatePostHolder.bind(this));
	},
	
	// this is the actual execCommand function that creates the editor functionality
	execCmd: function(e) {
		if(browser.isIE){var command = e.srcElement.parentElement.id;}
		else{var command = e.target.parentNode.id;}
		switch(command) {
			case 'link':
				return this.link();
				break;
			case 'source':
				return this.toggleSourceView('on');
				break;
			case 'compose':
				return this.toggleSourceView('off');
				break;
			case 'youtube':
				return this.popupInsert("Paste Embed Code", "youtube");
				break;
			case 'flickr':
				return this.popupInsert("Paste flickr HTML code", "flickr");
				break;
		}
		if (!busy)
	    {
	        busy = true;
	        try {this.doc.execCommand(command, false, null);}
			catch(e){ "error"; }

	        browser.isIE ? e.returnValue = false : e.preventDefault();
	        e.returnValue = false;

	        busy = false;

			if (this.updateDescription) { this.updateDesc() }; // update the description area when they click a tool
			this.enableActiveButton(); //update the button selected
			this.updatePostHolder(); // update the postholder
	    }
		this.win.focus();
	    return false;
	},
	
	// updates the description field
	updateDesc: function(evt) {
		var newDesc = '';
		if(browser.isSafari){ newDesc = this.source.innerText; }
		if(browser.isIE){newDesc = document.frames[this.fname].document.documentElement.innerText;}
		if(browser.isFirefox){ newDesc = this.source.innerHTML; }
		if(this.source.type == "textarea") {newDesc = this.source.value;} // have to do this for edit html
	    if(newDesc.length < 255 && desc_editted==0) {
			newDesc = newDesc.replace(/<br>/ig, '\r');
			newDesc = newDesc.replace(/&nbsp;/ig, '');
			$('post_description').value = newDesc.stripTags();
		}
	},
	
	// updates the hidden textarea which holds the content for the post
	// checks to make sure we aren't editing source which we don't need to update the holder
	updatePostHolder: function() {
		if(!this.editingSource) {
			if (browser.isIE) {
				this.holder.value = this.doc.body.innerHTML; //doc.body.innerHTML;
			} else {
				this.holder.value = this.ifrm.contentDocument.body.innerHTML; //ifrm.contentDocument.body.innerHTML;
			}
		}
	},
	
	// enables the active button when formatted text is selected
	enableActiveButton: function() {
		var tools = [ {cmd: 'bold', name: 'Bold', elem: 'bold'},
					{cmd: 'italic', name:'Italic', elem: 'italic'},
		    		{cmd: 'underline', name: 'Underline', elem: 'underline'},
					{cmd: 'insertunorderedlist', name: 'Un-ordered List', elem: 'insertunorderedlist'},
					{cmd: 'insertorderedlist', name: 'Ordered List', elem: 'insertorderedlist'} ];
		var list = $H(tools);

		for (var i = list.keys().length - 1; i >= 0; i--) {
			var cmd = list[i]['cmd'];
			var name = list[i]['name'];
			var elem = list[i]['elem'];
		    if (this.doc.queryCommandState(cmd)) {
				new Element.ClassNames(elem).add('active');
				$(elem).title = "Turn off " + name;
			}
			else {
				new Element.ClassNames(elem).remove('active');
				$(elem).title = name;
			}
		}
	},
	
	//creates the links, checks if no text is selected
	link: function() {
		var sel = '';
		if (this.win.getSelection) {
		  sel = this.win.getSelection();
		} else if (this.doc.selection) {
			var range = this.doc.selection.createRange();
			sel = range.text;
		}

		if (sel == '') {
			return alert("You must select text to make a link!");
		}
		var url = prompt("Enter a URL:", "http://");
		if ((url != null) && (url != "")) {
			if (/http:\/\//.test(url)) {
				this.doc.execCommand("CreateLink",false,url);
			} else { //if they erase the http, put it back in
				url = "http://" + url;
				this.doc.execCommand("CreateLink",false,url);
			}
			if (this.updateDescription) this.updateDesc();
		 }
		this.updatePostHolder();
	},
	
	popupInsert: function(message, name) {
		var embed = prompt(message, "");
		var sel = '';
		if(embed) {
			var code = "<div class='"+name+"'>" + embed + "</div><br />";
			if (this.win.getSelection) {
				sel = this.win.getSelection();
				var range = $R(0);
				this.holder.value = this.holder.value.substring(0, range.startOffset)
									+ code
									+ this.holder.value.substring(range.endOffset, this.holder.value.length);
			} else if (this.doc.selection) {
				this.win.focus();
				var range = this.doc.selection.createRange();
				this.holder.value = this.holder.value.substring(0, range.startOffset)
									+ code
									+ this.holder.value.substring(range.endOffset, this.holder.value.length);
			}
		}
		
		if (browser.isIE) {
			this.doc.body.innerHTML = this.holder.value;
		} else {
			this.ifrm.contentDocument.body.innerHTML = this.holder.value;
		}
	},
	
	// this toggles the source editor
	toggleSourceView: function(state) {
		var editTab = $(this.tname+'_wrapper').firstChild.firstChild;
		var composeTab = editTab.nextSibling;
		switch(state) {
			case 'on':
				toggle_items(baseTools, this.tname, 'none');
				this.addClass('tab_selected', composeTab, editTab);
				new ToggleView(this.fname, this.holder);
				if(this.updateDescription) {
					Event.observe(this.holder, 'keyup', this.updateDesc.bindAsEventListener(this));
				}
				this.switchPlainTextSource();
				this.editingSource = true;
				$('editor_state').value = 'source';
				break;
			case 'off':
				toolBarBuilder(this.tname);
				this.addClass('tab_selected', editTab, composeTab);
				if (browser.isIE) {
					this.doc.body.innerHTML = this.holder.value;
				} else {
					this.ifrm.contentDocument.body.innerHTML = this.holder.value;
				}
				new ToggleView(this.holder, this.fname);
				this.setEditorPlainTextSource();
				this.editingSource = false;
				$('editor_state').value = 'compose';
				break;
		}
	},
	
	//sets the plain text source for description update with editor as source (default)
	setEditorPlainTextSource: function() {
		if (browser.isIE) { this.source = this.ifrm.document.documentElement; }
		else { this.source = this.ifrm.contentDocument.body; }
	},
	
	// switches the plain text source for description update (when switching to edit html)
	switchPlainTextSource: function() {
		this.source = this.holder;
	},
	
	// adds named class to the on element removes it from the off element
	addClass: function(name, off, on) {
		new Element.ClassNames(off).remove(name);
		new Element.ClassNames(on).add(name);
	},
	
	removeButton: function(name) {
		$(name).style.display = 'none';
	}
};

var ToggleView = Class.create();
ToggleView.prototype = {
	
	initialize: function(off, on) {
		//editor is enabled by default
		$(off).style.visibility = 'hidden';
		$(off).style.height = '0';
		$(on).style.visibility = 'visible';
		$(on).style.height = '200px';
	},	
	
	switchEm: function(editor, holder) {
		this.initialize(elem, src);
	}
};

function blankCall() {
	true;
}