/*
  @author: remy sharp / http://remysharp.com
  @params:
    feedback - the selector for the element that gives the user feedback. Note that this will be relative to the form the plugin is run against.
    hardLimit - whether to stop the user being able to keep adding characters. Defaults to true.
    useInput - whether to look for a hidden input named 'maxlength' instead of the maxlength attribute. Defaults to false.
    words - limit by characters or words, set this to true to limit by words. Defaults to false.
  @license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
  @version: 1.2
  @changes: code tidy via Ariel Flesler and fix when pasting over limit and including \t or \n
*/

(function ($) {

$.fn.maxlength = function (settings) {

    if (typeof settings == 'string') {
        settings = { feedback : settings };
    }

    settings = $.extend({}, $.fn.maxlength.defaults, settings);

    function length(el) {
        var parts = el.value;
        if ( settings.words ){
            parts = el.value.length ? parts.split(/\s+/) : { length : 0 };
            
        }
        return parts.length;
    }
    
    return this.each(function () {
        var field = this,
            $field = $(field),
            $form = $(field.form),
            limit = settings.useInput ? $form.find('input[name=maxlength]').val() : $field.attr('maxlength'),
            $charsLeft = $form.find(settings.feedback);

    function limitCheck(event) {
        var len = length(this),
        exceeded = len >= limit,
        code = event.keyCode;

        if ( !exceeded ){
            return;
        }
        
        switch (code) {
            case 8:  // allow delete
            case 9:
            case 17:
            case 36: // and cursor keys
            case 35:
            case 37: 
            case 38:
            case 39:
            case 40:
            case 46:
            case 65:
            return;

            default:
            return settings.words && code != 32 && code != 13 && len == limit;
            }
        }


        var updateCount = function () {
            var len = length(field),
            diff = limit - len;

            $charsLeft.html( diff || "0" );

            // truncation code
            if (settings.hardLimit && diff < 0) {
                field.value = settings.words ? 
                // split by white space, capturing it in the result, then glue them back
                field.value.split(/(\s+)/, (limit*2)-1).join('') :
                field.value.substr(0, limit);

                updateCount();
            }
        };

        $field.keyup(updateCount).change(updateCount);
        if (settings.hardLimit) {
            $field.keydown(limitCheck);
        }

        updateCount();
    });
};

$.fn.maxlength.defaults = {
    useInput : false,
    hardLimit : true,
    feedback : '.charsLeft',
    words : false
};

})(jQuery);
