/*
 * Lightweight RTE - jQuery Plugin
 * Copyright (c) 2009 Andrey Gayvoronsky - http://www.gayvoronsky.com
 */
jQuery.fn.rte = function(options) {
	$(this).each( function() {
		return new lwRTE (this, options);
	});
	
	//return editor;
}

var lwRTE = function (textarea, options) {
	this.css_url	= options.css;
	this.css_class	= options.frame_class;
	this.base_url	= options.base_url;
	this.width		= options.width || '100%';
	this.height		= options.height || 350;

	this.iframe		= null;
	this.iframe_doc	= null;
	this.textarea	= null;
	this.event		= null;
	this.range		= null;
	this.registered_attributes = options.registered_attributes || {};
	this.registered_styles = options.registered_styles || {};
	this.table_attributes = options.table_attributes || {};
	
	this.toolbars	= {rte: '', html : ''};
	this.controls	= {html: {}, rte: {}};
	
	this.knopka = {html: {enable: {hint: 'Visual editor'}}, rte: {disable: {hint: 'Source editor'}}};
	
	if (fullscreen) {
		if (options.cb_fullscreen_on) {
			fullscreen.cb_fullscreen_on = options.cb_fullscreen_on;
		}
		if (options.cb_fullscreen_off) {
			fullscreen.cb_fullscreen_off = options.cb_fullscreen_off;
		}
	}
	
	$.extend(this.controls.html, options.controls_html);
	$.extend(this.controls.rte, options.controls_rte);
	
	//$.extend(this.controls.html, this.knopka.html);
	//$.extend(this.controls.rte, this.knopka.rte);
	
	if(document.designMode || document.contentEditable) {
		$(textarea).wrap($('<div></div>').addClass('rte-zone').width(this.width));
		this.textarea	= textarea;
		this.enable_design_mode();
	}
}

lwRTE.prototype.editor_cmd = function(command, args) {
	this.iframe.contentWindow.focus();
	try {
		this.iframe_doc.execCommand(command, false, args);
	} catch(e) {
		console.log(e)
	}
	this.iframe.contentWindow.focus();
}

lwRTE.prototype.get_toolbar = function() {
	var editor = (this.iframe) ? $(this.iframe) : $(this.textarea);
	return (editor.prev().hasClass('rte-toolbar')) ? editor.prev() : null;
}

lwRTE.prototype.activate_toolbar = function(editor, tb) {
	var old_tb = this.get_toolbar();

	if(old_tb)
		old_tb.remove();

	$(editor).before($(tb).clone(true));
}
	
lwRTE.prototype.enable_design_mode = function() {
	var self = this;

	// need to be created this way
	self.iframe	= document.createElement("iframe");
	self.iframe.frameBorder = 0;
	self.iframe.frameMargin = 0;
	self.iframe.framePadding = 0;
	self.iframe.width = '100%';
	self.iframe.height = self.height || '100%';
	
	if($(self.textarea).attr('class'))
		self.iframe.className = $(self.textarea).attr('class');

	if($(self.textarea).attr('id'))
		self.iframe.id = $(self.textarea).attr('id');
	
	if($(self.textarea).attr('name'))
		self.iframe.title = $(self.textarea).attr('name');

	var content	= $(self.textarea).val();

	$(self.textarea).hide().after(self.iframe).remove();
	self.textarea	= null;

	var css = (self.css_url) ? "<link type='text/css' rel='stylesheet' href='" + self.css_url + "' />" : '';
	var base = (self.base_url) ? "<base href='" + self.base_url + "' />" : '';
	var style = (self.css_class) ? "class='" + self.css_class + "'" : '';

	// Mozilla need this to display caret
	if($.trim(content) == '')
		content	= '<br>';

	var doc = "<html><head>" + base + css + "</head><body " + style + " style='padding:5px'>" + content + "</body></html>";

	self.iframe_doc	= self.iframe.contentWindow.document;

	try {
		self.iframe_doc.designMode = 'on';
	} catch ( e ) {
		// Will fail on Gecko if the editor is placed in an hidden container element
		// The design mode will be set ones the editor is focused
		$(self.iframe_doc).focus(function() { self.iframe_doc.designMode(); } );
	}

	self.iframe_doc.open();
	self.iframe_doc.write(doc);
	self.iframe_doc.close();

	if(!self.toolbars.rte)
		self.toolbars.rte	= self.create_toolbar(self.controls.rte);

	self.activate_toolbar(self.iframe, self.toolbars.rte);

	$(self.iframe).parents('form').submit( 
			function() { self.disable_design_mode(true); }
	);

	$(self.iframe_doc).mouseup(function(event) { 
		if(self.iframe_doc.selection)
			self.range = self.iframe_doc.selection.createRange();  //store to restore later(IE fix)

		self.set_selected_controls( (event.target) ? event.target : event.srcElement, self.controls.rte); 
	});

	$(self.iframe_doc).keyup(function(event) { self.set_selected_controls( self.get_selected_element(), self.controls.rte); });

	// hook onpaste event for ie
	if ($.browser.msie || $.browser.opera) {
		// listen for ctrl+v
		$(self.iframe_doc).keydown(function (e) {
			if (e.ctrlKey && e.keyCode == 86) {
				self.clean_code();
			}
		});
		// disable rightclick
		$(self.iframe_doc).mousedown(function (e) {
			e = e || self.win.event;
			if (e.button == 2 || e.button == 3) {
				if ($.browser.opera) {
					alert('Опция отключена для браузера Opera. Для вставки текста используйте ctrl+v');
				}
				return false;
			}
		});
		$(self.iframe_doc).bind('contextmenu', function () {
			return false;
		});
		// hook onpaste event for normal browsers (webkit, ff)
	} else {
		$(self.iframe_doc).bind('paste', function () {
			setTimeout(function () {
				self.clean_code();
			}, 100);
		});
	}
	this.clean_code();
	// Mozilla CSS styling off
	if(!$.browser.msie)
		self.editor_cmd('styleWithCSS', false);
}
    
lwRTE.prototype.disable_design_mode = function(submit) {
	var self = this;

	self.textarea = (submit) ? $('<input type="hidden" />').get(0) : $('<textarea></textarea>').width('100%').height(self.height).get(0);

	if(self.iframe.className)
		self.textarea.className = self.iframe.className;

	if(self.iframe.id)
		self.textarea.id = self.iframe.id;
		
	if(self.iframe.title)
		self.textarea.name = self.iframe.title;
	
	$(self.textarea).val($('body', self.iframe_doc).html());
	$(self.iframe).before(self.textarea);

	if(!self.toolbars.html)
		self.toolbars.html	= self.create_toolbar(self.controls.html);

	if(submit != true) {
		$(self.iframe).remove();
		self.iframe = null;
		self.activate_toolbar(self.textarea, self.toolbars.html);
	}
}

lwRTE.prototype.toolbar_click = function(obj, control) {
	var fn = control.exec;

	$('.rte-panel', this.get_toolbar()).remove();

	if(fn)
		fn.apply(this);
	else if(this.iframe && control.command) {
		var args = control.args;

		if(obj.tagName.toUpperCase() == 'SELECT') {
			args = obj.options[obj.selectedIndex].value;

			if(args.length <= 0)
				return;
		}

		this.editor_cmd(control.command, args);
	}
}

lwRTE.prototype.clean_code = function(html) {
	var self = this;
	var modify_content = !html;
	if (modify_content) {
		html = this.get_content();
	}
	var is_registered_attribute = function (name, value) {
		if (!self.registered_attributes || !self.registered_attributes[name]) {
			return false;
		}
		return self.registered_attributes[name] === true || $.inArray(value, self.registered_attributes[name]) !== -1;
	};
	var check_registered_style = function (rules) {
		
		if (!self.registered_styles) {
			return false;
		}
		rules = rules.split(/\s*;\s*/);
		var result_rules = [];
		$(rules).each(function (i, rule) {
			rule = rule.split(':');
			var property = $.trim(rule[0]);
			var value = $.trim(rule[1]);
			if (self.registered_styles[property]) {
				if (typeof self.registered_styles[property] === 'function') {
					result_rules.push(property + ': ' + self.registered_styles[property](value));
				} else {
					result_rules.push(property + ': ' + value);
				}
			}
		});
		return result_rules.join(';');
	}
	
	var fsize = {
		1: 'xx-small',
		2: 'x-small',
		3: 'small',
		4: 'medium',
		5: 'large',
		6: 'x-large',
		7: 'xx-large'
	};
	// Remove comments [SF BUG-1481861].
	html = html.replace(/<\!--[\s\S]*?-->/g, '')
	.replace(/<o:p>\s*<\/o:p>/g, '')
	.replace(/<o:p>[\s\S]*?<\/o:p>/g, '&nbsp;')
	// Remove mso-xxx styles.
	.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '')
	// Remove margin styles.
	.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*;/gi, '')
	.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*"/gi, "\"")
	.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '')
	.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"")
	.replace( /\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"")
	.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"")
	.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"")
	.replace( /\s*tab-stops:[^;"]*;?/gi, '')
	.replace( /\s*tab-stops:[^"]*/gi, '')
	// Remove style, meta and link tags
	.replace( /<STYLE[^>]*>[\s\S]*?<\/STYLE[^>]*>/gi, '')
	.replace( /<TITLE[^>]*>[\s\S]*?<\/TITLE[^>]*>/gi, '')
	.replace( /<(?:META|LINK)[^>]*>\s*/gi, '')
	.replace( /<col.*?>/gi, '')
	// replace font with span
	.replace(/<font([^>]*)/gi, function(str, attr) {
		var css = '', m = attr.match(/size=('|")(\d)/i);
		if (m && m[2] && fsize[m[2]]) {
			css = 'font-size: '+fsize[m[2]]+'; ';
		}
		m = attr.match(/face=('|")([a-z0-9\s,]+)/i);
		if (m && m[2]) {
			css += 'font-family: '+m[2];
		}
		return '<span' + (css ? ' style="'+css+'"' : '');
	})
	.replace(/<\/font/i, '</span')
	// remove empty styles and classes
	.replace(/(\s*(class|style)="\s*")/gi, '')
	// strip whitespaces
	.replace(/\r?\n(\s)*/mg, "\n")
	.replace( /<([a-z][a-z0-9]*)\s*(.*?)>/gi, function (whole, tagname, attrs) {
		attrs = attrs.replace(/([a-z]+)="([^"]*)"\s*/gi, function (attr, name, value) {
			if (name === 'style') {
				var s = check_registered_style(value);
				return s ? ' style="' + s + '"' : '';
			}
			return is_registered_attribute(name, value) ? ' ' + name + '="' + value + '"' : '';
		});
		return '<' + tagname + attrs + '>';
	})
	// replace headings with strong
	.replace(/<h\d/gi,'<strong')
	.replace(/<\/h\d/gi,'<\/strong');
	
	// dom replacementText Text Text
	var $s = $('<span />');
	$s.html(html);

	function cleanable($el) {
		if ($el.size() !== 1) {
			return false
		}
		var node = $el[0].firstChild, span_count = 0;
		while (node) {
			if (node.nodeType === 3 && node.nodeValue.replace(/\s*/, '') !== '') {
				return false;
			}
			if (node.nodeType === 1) {
				if (node.nodeName === 'SPAN') {
					span_count += 1;
				} else {
					return false;
				}
			}
			node = node.nextSibling;
		}
		return span_count === 1;
	}

	// make all spans dirty
	$s.find('span').addClass('dirty');
	// than clean one-by-one
	var $t = $s.find('span.dirty:first');
	while ($t.size() === 1) {
		// calc style
		if (!cleanable($t)) {
			$t.removeClass('dirty');
			$t = $s.find('span.dirty:first');
			continue;
		}
		var spanstack = [$t.attr('style')], $span = $t.find('>span');

		var $prevspan = $t;
		while (cleanable($span)) {
			var s = $span.attr('style');
			if (s) {
				spanstack.push(s);
			}
			$prevspan = $span;
			$span = $span.find('>span');
		}
		// do clean
		var styles = spanstack.join(';').replace(/\s*;+\s*/g, ';').split(';');
		var result = $prevspan.html(), s = '', span_mixed_style = [];
		var flush_span = function () {
			if (span_mixed_style.length > 0) {
				result = '<span style="' + span_mixed_style.join(';') + '">' + result + '</span>';
				span_mixed_style = [];
			}
		};
		var push_span = function (s) {
			span_mixed_style.push(s.join(':'));
		};
		var push_tag = function (tag) {
			flush_span();
			result = '<' + tag + '>' + result + '</' + tag + '>';
		};
		for (var i = styles.length - 1; i >= 0; i--) {
			if (!styles[i]) continue;
			var s = styles[i].split(/\s*:\s*/);
			var val = s[1];
			switch (s[0]) {
			case 'font-weight':
				if (isNaN(parseInt(val)) && (val == 'bold' || val == 'bolder') || val > 500) {
					push_tag('strong');
				} else {
					push_span(s);
				}
				break;
			case 'text-decoration': 
				if (val == 'underline') {
					push_tag('u');
				} else if (val == 'line-through') {
					push_tag('s');
				} else {
					push_span(s);
				}
				break;
			case 'font-style':
				if (val == 'italic' || val == 'oblique') {
					push_tag('i');
				} else {
					push_span(s);
				}
				break;
			default:
				push_span(s);
				break;
			}
		};
		flush_span();
		$t.replaceWith(result);
		// next!
		$t = $s.find('span.dirty:first');
	}

	// add styles to tables
	$s.find('table').each(function (i, table) {
		for (var i in self.table_attributes) {
			if (self.table_attributes.hasOwnProperty(i)) {
				$(table).attr(i, self.table_attributes[i]);
			}
		}
	});

	// remove empty styles and classes
	html = $s.html().replace(/(\s*(class|style)="\s*")/gi, '');
	if (modify_content) {
		this.set_content(html);
	}
	return html;
}

lwRTE.prototype.create_toolbar = function(controls) {
	var self = this;
	var tb = $("<div></div>").addClass('rte-toolbar').width('100%').append($("<ul></ul>")).append($("<div></div>").addClass('clear'));
	var obj, li;
	
	for (var key in controls){
		
		if(controls[key].separator) {
			li = $("<li></li>").addClass('separator');
		} else {
			if(controls[key].select) {
				obj = $(controls[key].select)
					.change( function(e) {
						self.event = e;
						self.toolbar_click(this, controls[this.className]); 
						return false;
					});
			} else {
				
				obj = $("<a href='#'></a>")
					.attr('title', (controls[key].hint) ? controls[key].hint : key)
					.attr('rel', key)
					.click( function(e) {
						self.event = e;
						self.toolbar_click(this, controls[this.rel]);
						if(this.rel=='bold' || this.rel=='italic' || this.rel=='strikeThrough' || this.rel=='underline' || this.rel=='subscript' || this.rel=='superscript'){
							if(!$(this).hasClass('active')) {
								$(this).addClass('active');
							}else{
								$(this).removeClass('active');
							}
						}
						
						return false;
					})
			}

			li = $("<li></li>").append(obj.addClass(key));
			if (controls[key].list_item_style) {
				li.css(controls[key].list_item_style)
			}
		}

		$("ul",tb).append(li);
	}

	$('.enable', tb).click(function() {
		self.enable_design_mode();
		return false; 
	});

	$('.disable', tb).click(function() {
		self.disable_design_mode();
		return false; 
	});

	return tb.get(0);
}

lwRTE.prototype.create_panel = function(title, html) {
	var self = this;
	var tb = self.get_toolbar();
	
	if(!tb)
		return false;

	$('.rte-panel', tb).remove();
	var left = 100;
	var top = 100;
	var panel	=  $('<div></div>').hide().addClass('modal-box');
	
	panel.append('<div class="modal-bg" style="z-index:5000;"></div>').hide();
	panel.append('<div class="modal-window" style="z-index:10000;"><button class="modal-close" id="cancel"></button><div class="modal-data" id="modal_window"><p>' + html + '</p></div></div>').hide();
	tb.append(panel);

	$('.modal-box').show();
	$('.modal-bg').show();
	$('.modal-window').show();
	
	return panel;
}

lwRTE.prototype.error = function(s){
    if($.blockUI){
        $.blockUI({
         message: s.replace(/\n/gi,'<br/>'),
         css: { 
          border:'none', padding:'15px', size:'12.0pt',
          backgroundColor:'#a6b08b', color:'#000000',
          opacity:'.9','-webkit-border-radius': '10px','-moz-border-radius': '10px'
         }
        });
        window.setTimeout($.unblockUI, 2000);
   } else{
	alert(s);
   }
}

lwRTE.prototype.get_content = function() {
	return (this.iframe) ? $('body', this.iframe_doc).html() : $(this.textarea).val();
};

lwRTE.prototype.set_content = function(content) {
	if (this.iframe) {
		var $body = $('body', this.iframe_doc);
		$body.html(content);
	} else {
		$(this.textarea).val(content);
	}
};

/* 
lwRTE.prototype.init_table_resizing = function ($body) {
	$body.find('table').each(function () {
		if ($.browser.msie && $.browser.version == 6) {
			$(this).addClass('ie6-resize-table');
		} else {
			$(this).addClass('resize-table');
		}
		this.contentEditable = false;
		this._moz_resizing = null;
		$(this).find('td').each(function () {
			if ($.browser.mozilla && false) {
				$(this).html('<table class="inner-table"><tr><td>' + $(this).html() + '</td></tr></table>');
			} else {
				$(this).html('<div class="td-content">' + $(this).html() + '</div>' +
					'<div class="td-vertical-resize"></div>' +
					'<div class="td-horizontal-resize"></div>' +
					'<div class="td-both-resize"></div>');
			}
		});
	});
};
 */

lwRTE.prototype.set_selected_controls = function(node, controls) {
	var toolbar = this.get_toolbar();

	if(!toolbar)
		return false;
		
	var key, i_node, obj, control, tag, i, value;

	for (key in controls) {
		control = controls[key];
		obj = $('.' + key, toolbar);

		obj.removeClass('active');

		if(!control.tags)
			continue;

		i_node = node;
		do {
			if(i_node.nodeType != 1)
				continue;

			tag	= i_node.nodeName.toLowerCase();
			if($.inArray(tag, control.tags) < 0 )
				continue;

			if(control.select) {
				obj = obj.get(0);
				if(obj.tagName.toUpperCase() == 'SELECT') {
					obj.selectedIndex = 0;

					for(i = 0; i < obj.options.length; i++) {
						value = obj.options[i].value;
						if(value && ((control.arg_cmp && control.arg_cmp(i_node, value)) || tag == value)) {
							obj.selectedIndex = i;
							break;
						}
					}
				}
			} else
					obj.addClass('active');
		}  while(i_node = i_node.parentNode)
	}
		
	return true;
}

lwRTE.prototype.get_selected_element = function () {
	var node, selection, range;
	var iframe_win	= this.iframe.contentWindow;
	
	if (iframe_win.getSelection) {
		try {
			selection = iframe_win.getSelection();
			range = selection.getRangeAt(0);
			node = range.commonAncestorContainer;
		} catch(e){
			return false;
		}
	} else {
		try {
			selection = iframe_win.document.selection;
			range = selection.createRange();
			node = range.parentElement();
		} catch (e) {
			return false;
		}
	}

	return node;
}

lwRTE.prototype.get_selection_range = function() {
	var rng	= null;
	var iframe_window = this.iframe.contentWindow;
	this.iframe.focus();
	
	if(iframe_window.getSelection) {
		rng = iframe_window.getSelection().getRangeAt(0);
		if($.browser.opera) { //v9.63 tested only
			var s = rng.startContainer;
			if(s.nodeType === Node.TEXT_NODE)
				rng.setStartBefore(s.parentNode);
		}
	} else {
		this.range.select(); //Restore selection, if IE lost focus.
		rng = this.iframe_doc.selection.createRange();
	}

	return rng;
}

lwRTE.prototype.get_selected_text = function() {
	var iframe_win = this.iframe.contentWindow;

	if(iframe_win.getSelection)	
		return iframe_win.getSelection().toString();

	this.range.select(); //Restore selection, if IE lost focus.
	return iframe_win.document.selection.createRange().text;
};

lwRTE.prototype.get_selected_html = function() {
	var html = null;
	var iframe_window = this.iframe.contentWindow;
	var rng	= this.get_selection_range();

	if(rng) {
		if(iframe_window.getSelection) {
			var e = document.createElement('div');
			e.appendChild(rng.cloneContents());
			html = e.innerHTML;		
		} else {
			html = rng.htmlText;
		}
	}

	return html;
};
	
lwRTE.prototype.selection_replace_with = function(html) {
	var rng	= this.get_selection_range();
	var iframe_window = this.iframe.contentWindow;

	if(!rng)
		return;

	this.editor_cmd('removeFormat'); // we must remove formating or we will get empty format tags!
	
	//rng.pasteHTML(html);
	
	if(iframe_window.getSelection) {
		//rng.createContextualFragment(html)
		//rng.deleteContents();
		rng.insertNode(rng.createContextualFragment(html));
		//this.editor_cmd('delete');
	} else {
		//this.editor_cmd('delete');
		rng.pasteHTML(html);
	}
}
