/**
 * jQuery Maxlength plugin
 * @version        $Id: jquery.maxlength.js 18 2009-05-16 15:37:08Z emil@anon-design.se $
 * @package        jQuery maxlength 1.0.5
 * @copyright    Copyright (C) 2009 Emil Stjerneman / http://www.anon-design.se
 * @license        GNU/GPL, see LICENSE.txt
 */

(function($) 
{

    $.fn.maxlength = function(options)
    {
        var settings = jQuery.extend(
        {
            events:                      [], // Array of events to be triggerd
            maxCharacters:          10, // Characters limit
            status:                      true, // True to show status indicator bewlow the element
            statusClass:            "status", // The class on the status div
            statusText:                " character left", // The status text
            statusShowCharacterLeft:               true,
            notificationClass:    "notification",    // Will be added to the emement when maxlength is reached
            showAlert:                 false, // True to show a regular alert message
            alertText:                "You have typed too many characters.", // Text in the alert message
            alertCallback:              function() {},
            slider:                      false // Use counter slider
        }, options );
        
        // Add the default event
        $.merge(settings.events, ['keyup']);

        return this.each(function() 
        {
            var item = $(this);
            var charactersLength = mbStringLength($(this).val());
            
            function mbStringLength(str)
            {
                var length = 0;

                for(var i = 0; i < str.length; i++)
                {
                    if(escape(str.charAt(i)).length >= 4)
                        length += 2;
                    else if(escape(str.charAt(i)) == "%A7")
                        length += 2;
                    else
                    if(escape(str.charAt(i)) != "%0D")
                        length++;
                }	

                return length;
            }

            function mbStringCut(str, max_length) 
            {
                var count = 0;
	 
                for(var i = 0; i < str.length; i++)
                {
                    if(escape(str.charAt(i)).length >= 4)
                        count += 2;
                    else
                    if(escape(str.charAt(i)) != "%0D")
                        count++;

                    if(count > max_length)
                    {
                        if(escape(str.charAt(i)) == "%0A")
                            i--;
                        break;		
                    }
                }
	
                return str.substring(0, i);
            }
            
            // Update the status text
            function updateStatus()
            {
                var statusCharacter = (settings.statusShowCharacterLeft === true) ?
                    statusCharacter = settings.maxCharacters - charactersLength :
                    statusCharacter = charactersLength;
                
                statusCharacter = (statusCharacter < 0) ? 0 : ((statusCharacter > 80) ? 80 : statusCharacter);
                
                item.next("div").html(statusCharacter + settings.statusText);
            }

            function checkChars() 
            {
                var valid = true;
                
                // Too many chars?
                if(charactersLength >= settings.maxCharacters) 
                {
                    // Too may chars, set the valid boolean to false
                    valid = false;
                    // Add the notifycation class when we have too many chars
                    item.addClass(settings.notificationClass);
                    
                    // Cut down the string
                    item.val(mbStringCut(item.val(), settings.maxCharacters));
                    item.blur();
                    
                    // Show the alert dialog box, if its set to true
                    settings.alertCallback();
                    showAlert();
                } 
                else 
                {
                    // Remove the notification class
                    if(item.hasClass(settings.notificationClass)) 
                    {
                        item.removeClass(settings.notificationClass);
                    }
                }

                if(settings.status)
                {
                    updateStatus();
                }
            }
                        
            // Shows an alert msg
            function showAlert() 
            {
                if(settings.showAlert)
                {
                    alert(settings.alertText);
                }
            }

            // Check if the element is valid.
            function validateElement() 
            {
                var ret = false;
                
                if(item.is('textarea')) {
                    ret = true;
                } else if(item.filter("input[type=text]")) {
                    ret = true;
                } else if(item.filter("input[type=password]")) {
                    ret = true;
                }

                return ret;
            }

            // Validate
            if(!validateElement()) 
            {
                return false;
            }
            
            // Loop through the events and bind them to the element
            $.each(settings.events, function (i, n) {
                item.bind(n, function(e) {
                    charactersLength = mbStringLength(item.val());
                    checkChars();
                });
            });

            // Insert the status div
            if(settings.status) 
            {
                item.after($("<div id='" + this.id + "_status' style='display:none;'/>").addClass(settings.statusClass).html('-'));
                updateStatus();
            }

            // Remove the status div
            if(!settings.status) 
            {
                var removeThisDiv = item.next("div."+settings.statusClass);
                
                if(removeThisDiv) {
                    removeThisDiv.remove();
                }

            }

            // Slide counter
            if(settings.slider) {
                item.next().hide();
                
                item.focus(function(){
                    item.next().slideDown('fast');
                });

                item.blur(function(){
                    item.next().slideUp('fast');
                }); 
            }

        });
    };
})(jQuery);
