(function($)
{
	$.Redactor.prototype.source = function()
	{
		return {
			init: function()
			{
				var button = this.button.addFirst('html', 'HTML');
				this.button.addCallback(button, this.source.toggle);
				this.button.remove('file');

				var style = {
					'width': '100%',
					'margin': '0',
					'background': '#111',
					'box-sizing': 'border-box',
					'color': 'rgba(255, 255, 255, .8)',
					'font-size': '14px',
					'outline': 'none',
					'padding': '16px',
					'line-height': '22px',
					'font-family': 'Menlo, Monaco, Consolas, "Courier New", monospace'
				};

				this.source.$textarea = $('<textarea />');
				this.source.$textarea.css(style).hide();

				if (this.opts.type === 'textarea')
				{
					this.core.box().append(this.source.$textarea);
				}
				else
				{
					this.core.box().after(this.source.$textarea);
				}

				this.core.element().on('destroy.callback.redactor', $.proxy(function()
				{
					this.source.$textarea.remove();

				}, this));
				
				var icons = {
					'html': '<i class="vh vh-html"></i>',
                    'format': '<i class="vh vh-paragraph"></i>',
																				'bold': '<i class="vh vh-bold"></i>',
                    'italic': '<i class="vh vh-italic"></i>',
																				'deleted': '<i class="vh vh vh-strikethrough"></i>',
																				'unorderedlist': '<i class="vh vh-unorderedlist"></i>',
																				'orderedlist': '<i class="vh vh-orderedlist"></i>',
																				'outdent': '<i class="vh vh-outdent"></i>',
																				'indent': '<i class="vh vh-indent"></i>',
																				'image': '<i class="vh vh-image"></i>',
                    'link': '<i class="vh vh-link"></i>',
																				'alignment': '<i class="vh vh-alignment"></i>',
                    'horizontalrule': '<i class="re-icon rev-horizontalrule"></i>',
																				'lists': '<i class="vh vh-unordered-list"></i>'
                    
                };
 
                $.each(this.button.all(), $.proxy(function(i,s)
                {
                    var key = $(s).attr('rel');
 
                    if (typeof icons[key] !== 'undefined')
                    {
                        var icon = icons[key];
                        var button = this.button.get(key);
                        this.button.setIcon(button, icon);
                    }
 
                }, this));
																
																

			},
			toggle: function()
			{
				return (this.source.$textarea.hasClass('open')) ? this.source.hide() : this.source.show();
			},
			setCaretOnShow: function()
			{
				this.source.offset = this.offset.get();
				var scroll = $(window).scrollTop();

				var	width = this.core.editor().innerWidth();
				var height = this.core.editor().innerHeight();

				// caret position sync
				this.source.start = 0;
				this.source.end = 0;
				var $editorDiv = $("<div/>").append($.parseHTML(this.core.editor().html(), document, true));
				var $selectionMarkers = $editorDiv.find("span.redactor-selection-marker");

				if ($selectionMarkers.length > 0)
				{
					var editorHtml = $editorDiv.html().replace(/&amp;/g, '&');

					if ($selectionMarkers.length === 1)
					{
						this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
						this.source.end = this.source.start;
					}
					else if ($selectionMarkers.length === 2)
					{
						this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
						this.source.end = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-2").prop("outerHTML")) - $editorDiv.find("#selection-marker-1").prop("outerHTML").toString().length;
					}
				}

			},
			setCaretOnHide: function(html)
			{
			    this.source.start = this.source.$textarea.get(0).selectionStart;
				this.source.end = this.source.$textarea.get(0).selectionEnd;

				// if selection starts from end
				if (this.source.start > this.source.end && this.source.end > 0)
				{
					var tempStart = this.source.end;
					var tempEnd = this.source.start;

					this.source.start = tempStart;
					this.source.end = tempEnd;
				}

				this.source.start = this.source.enlargeOffset(html, this.source.start);
				this.source.end = this.source.enlargeOffset(html, this.source.end);

				html = html.substr(0, this.source.start) + this.marker.html(1) + html.substr(this.source.start);

				if (this.source.end > this.source.start)
				{
					var markerLength = this.marker.html(1).toString().length;

					html = html.substr(0, this.source.end + markerLength) + this.marker.html(2) + html.substr(this.source.end + markerLength);
				}


				return html;

			},
			hide: function()
			{
				this.source.$textarea.removeClass('open').hide();
				this.source.$textarea.off('.redactor-source');

				var code = this.source.$textarea.val();

				code = this.paragraphize.load(code);
				code = this.source.setCaretOnHide(code);

				this.code.start(code);
				this.button.enableAll();
				this.core.editor().show().focus();
				this.selection.restore();
				//this.code.sync();
			},
			show: function()
			{
				this.selection.save();
				this.source.setCaretOnShow();

				var height = this.core.editor().innerHeight();
				var code = this.code.get();

				code = code.replace(/\n\n\n/g, "\n");
				code = code.replace(/\n\n/g, "\n");

				this.core.editor().hide();
				this.button.disableAll('html');
				this.source.$textarea.val(code).height(height).addClass('open').show();
				this.source.$textarea.on('keyup.redactor-source', $.proxy(function()
				{
					if (this.opts.type === 'textarea')
					{
						this.core.textarea().val(this.source.$textarea.val());
					}

				}, this));

				this.marker.remove();

				$(window).scrollTop(scroll);

				if (this.source.$textarea[0].setSelectionRange)
				{
					this.source.$textarea[0].setSelectionRange(this.source.start, this.source.end);
				}

				this.source.$textarea[0].scrollTop = 0;

				setTimeout($.proxy(function()
				{
					this.source.$textarea.focus();

				}, this), 0);
			},
			enlargeOffset: function(html, offset)
			{
				var htmlLength = html.length;
				var c = 0;

				if (html[offset] === '>')
				{
					c++;
				}
				else
				{
					for(var i = offset; i <= htmlLength; i++)
					{
						c++;

						if (html[i] === '>')
						{
							break;
						}
						else if (html[i] === '<' || i === htmlLength)
						{
							c = 0;
							break;
						}
					}
				}

				return offset + c;
			}
		};
	};
})(jQuery);