jQuery.fn.forms = function(options) {

  var gotfocus = false;

  return this.each(function() {
    this.options = {
      focus: ''
    };

    jQuery.extend(this.options, options);

    jQuery(this).forms_highlight();
    jQuery(this).forms_charsleft();
    jQuery(this).forms_tooltip();
    jQuery(this).forms_defaultvalue();
    if (!gotfocus) {
      gotfocus = jQuery(this).forms_setfocus(this.options.focus);
    }
  });
};

jQuery.fn.extend({
  forms_setfocus: function(focus) {
    var el = this.find(focus);
    if (el) {
      el.focus();
    }
    return (el.length == 1);
  }
});

jQuery.fn.extend({
  forms_defaultvalue: function() {
    this.each(function() {

      jQuery('input[data-defaultvalue], textarea[data-defaultvalue]').each(function() {

        var defaultvalue = jQuery(this).attr('data-defaultvalue');

        jQuery(this).focus(function() {
          if (jQuery(this).val() == '') {
            jQuery(this).val(defaultvalue);
          }
        });

        jQuery(this).blur(function() {
          if (jQuery(this).val() == defaultvalue) {
            jQuery(this).val('');
          }
        });
      });
    });
  }
});

jQuery.fn.extend({
  forms_highlight: function(options) {

    this.options = {
      selector: 'div',
      className: 'highlight'
    };

    jQuery.extend(this.options, options);

    var myoptions = this.options;

    jQuery('textarea, select, multi-select, :text, :image, :password, :radio, :checkbox, :file', this).each(function() {

      jQuery(this).focus(function() {
        var parents = jQuery(this).parents(myoptions.selector)
        var parent = jQuery(parents.get(0))
        parent.addClass(myoptions.className);
      });

      jQuery(this).blur(function() {
        var parents = jQuery(this).parents(myoptions.selector)
        var parent = jQuery(parents.get(0))
        parent.removeClass(myoptions.className);
      });

    });
  }
});

jQuery.fn.extend({
  forms_tooltip: function(options) {

    this.options = {};

    jQuery.extend(this.options, options);

    var myoptions = this.options;

    if (jQuery('div#tooltip').length == 0) {
      jQuery('body').append("<div id='tooltip'></div>");
    }

    jQuery('img.tooltip', this).each(function() {
      var tooltip = jQuery(this).attr('title');
      jQuery(this).removeAttr('title')
      jQuery(this).attr("tooltip", tooltip);

      var hover = jQuery.browser.msie ? 'mouseenter' : 'mouseover';

      jQuery(this).bind(hover, function(e) {

        var X = e.pageX;
        var Y = e.pageY;

        var parent = jQuery(this);

        jQuery('#tooltip').css({
          'top': parent.offset().top + (parent.outerHeight()),
          'left': parent.offset().left + 10 + (parent.outerHeight()),
          'display': 'block'
        })

        jQuery('#tooltip').html(parent.attr('tooltip'));

      });

      jQuery(this).bind('mouseout', function(e) {
        jQuery('#tooltip').css({
          'display': 'none'
        })
      });

    });
  }
});

jQuery.fn.extend({
  forms_charsleft: function(options) {

    this.options = {
      selector: 'div',
      classCharsLeft: 'charsleft',
      classLimitReached: 'charsfull'
    };

    jQuery.extend(this.options, options);

    var myoptions = this.options;

    jQuery('textarea, :text, :password', this).each(function() {

      tagName = this.tagName.toLowerCase();

      var el = jQuery(this);

      var attributeValue = (tagName == 'textarea') ? el.attr('data-maxlength') : el.attr('maxlength');

      if (attributeValue >= '1' && attributeValue < '99999') {

        if (!el.next().is('span.' + myoptions.classCharsLeft)) {
          el.after(jQuery('<span/>').addClass(myoptions.classCharsLeft).html('-'));
          updateCharsLeft(el);
        }

        el.focus(function() {

          updateCharsLeft(el);

          el.bind(
                'keyup',
                function() {
                  updateCharsLeft(el, 'keyup');
                }
              );

          el.bind(
                'keydown',
                function() {
                  updateCharsLeft(el, 'keydown');
                }
              );
        });

        el.blur(function() {
          el.unbind(
              'keyup',
              function() {
                updateCharsLeft(el);
              }
            );

          el.unbind(
	            'keydown',
	            function() {
	              updateCharsLeft(el);
	            }
            );
        });

      }


      // Update the status text
      function updateCharsLeft(item, eventname) {

        var tagName = item.context.tagName.toLowerCase();
        var maxlength = (tagName == 'textarea') ? item.attr('data-maxlength') : item.attr('maxlength');
        var characters = item.val().length;
        var classLimitReached = 'charsfull';

        if (characters > maxlength) {
          var hasClass = item.hasClass(classLimitReached);
          if (eventname == 'keydown') {
            if (!hasClass) {
              item.addClass(classLimitReached);
            }
          } else if (eventname == 'keyup') {
            if (hasClass) {
              item.removeClass(classLimitReached);
            }
          }
          item.val(item.val().substr(0, maxlength));
          characters = maxlength;
        }
        else {
          if (item.hasClass(classLimitReached)) {
            item.removeClass(classLimitReached);
          }
        }

        var charactersLeft = maxlength - characters;
        item.next("span").html(charactersLeft);
      };

    });
  }
});

