/**
 * jQuery Lined Textarea Plugin
 *   http://alan.blog-city.com/jquerylinedtextarea.htm
 *
 * Copyright (c) 2010 Alan Williamson
 *
 * Contributions done by Ryan Zielke (NeoAlchemy@gmail.com)
 *
 * Version:
 *    $Id: jquery-linedtextarea.js 464 2010-01-08 10:36:33Z alan $
 *
 * Released under the MIT License:
 *    http://www.opensource.org/licenses/mit-license.php
 *
 * Usage:
 *   Displays a line number count column to the left of the textarea
 *
 *   Class up your textarea with a given class, or target it directly
 *   with JQuery Selectors
 *
 *   $(".lined").linedtextarea({
 *   	selectedLine: 10,
 *    selectedClass: 'lineselect'
 *   });
 */

(function($) {
    $.fn.linedtextarea = function(options) {
	// Get the Options
	var opts = $.extend({}, $.fn.linedtextarea.defaults, options);

	/*
	 * Helper function to make sure the line numbers are always
	 * kept up to the current system
	 */
	var fillOutLines = function(codeLines, h, lineNo){
	    while ( (codeLines.height() - h ) <= 0 ){
		if ( lineNo == opts.selectedLine )
		    codeLines.append("<div id='lineno" + lineNo + "' class='lineno lineselect'>" + lineNo + "</div>");
		else
		    codeLines.append("<div id='lineno" + lineNo + "' class='lineno'>" + lineNo + "</div>");

		lineNo++;
	    }
	    return lineNo;
	};

	/*
	 * Iterate through each of the elements are to be applied to
	 */
	return this.each(function() {
	    var lineNo = 1;
	    var textarea = $(this);

	    /* Turn off the wrapping of as we don't want to screw up the line numbers */
	    textarea.attr("wrap", "off");
	    textarea.css({resize:'both'});
	    var originalTextAreaWidth = textarea.outerWidth();

	    /* Wrap the text area in the elements we need */
	    var linedTextAreaDiv = textarea.wrap("<div class='linedwrap'></div>");
	    var linedWrapDiv = linedTextAreaDiv.parent();

	    linedWrapDiv.prepend("<div class='lines' style='width:50px'></div>");

	    var linesDiv = linedWrapDiv.find(".lines");

	    /* Draw the number bar; filling it out where necessary */
	    linesDiv.append("<div class='codelines'></div>");
	    var codeLinesDiv = linesDiv.find(".codelines");
	    lineNo = fillOutLines( codeLinesDiv, linesDiv.height(), 1 );

	    /* Move the textarea to the selected line */
	    if ( opts.selectedLine != -1 && !isNaN(opts.selectedLine) ){
		var fontSize = parseInt( textarea.height() / (lineNo-2) );
		var position = parseInt( fontSize * opts.selectedLine ) - (textarea.height()/2);
		textarea[0].scrollTop = position;
	    }

	    /* Set the width */
	    var sidebarWidth = linesDiv.outerWidth(true);
	    var paddingHorizontal = parseInt( linedWrapDiv.css("border-left-width") ) + parseInt( linedWrapDiv.css("border-right-width") ) + parseInt( linedWrapDiv.css("padding-left") ) + parseInt( linedWrapDiv.css("padding-right") );
	    var linedWrapDivNewWidth = originalTextAreaWidth - paddingHorizontal;
	    var textareaNewWidth = originalTextAreaWidth - sidebarWidth - paddingHorizontal;

	    textarea.width(textareaNewWidth);
	    textarea.css({maxWidth: textareaNewWidth - 6}); //TODO make this calculated

	    /* React to the scroll event */
	    textarea.scroll( function(tn){
		var domTextArea = $(this)[0];
		var scrollTop = domTextArea.scrollTop;
		var clientHeight = domTextArea.clientHeight;
		codeLinesDiv.css({'margin-top': (-1*scrollTop) + "px"});
		lineNo = fillOutLines(codeLinesDiv, scrollTop + clientHeight, lineNo);
	    });

	    /* Should the textarea get resized outside of our control */
	    textarea.resize( function(tn){
		var domTextArea	= $(this)[0];
		linesDiv.height(domTextArea.clientHeight + 6);
	    });

	    window.setInterval( function(tn) {
		linesDiv.height(textarea.height());
		var scrollTop = textarea[0].scrollTop;
		var clientHeight = textarea[0].clientHeight;
		codeLinesDiv.css({'margin-top': (-1*scrollTop) + "px"});
		lineNo = fillOutLines(codeLinesDiv, scrollTop + clientHeight, lineNo);
	    },10);
	});
    };

    // default options
    $.fn.linedtextarea.defaults = {
  	selectedLine: -1,
  	selectedClass: 'lineselect'
    };
})(jQuery);
