/**
 * Disable an element to prevent it from making the same request
 * multiple times.
 */
$(selector).click(function(){
  if (!$(this).hasClass('disabled')) {
    $(this).addClass('disabled');
    $.get(url, function(){
      $(this).removeClass('disabled');
    });
  }
  return false;
});
/* 
 * Fun with getJSON
 */
jQuery.getJSON(url, function(jsonResponse) { 
  // Do something with jsonResponse
});
/*
 * Creates a normalized string with the browser name. 
 * Useful for adding the class to the main element
 * to do browser specific css fixes.
 */
$.browser.classes = function() {
  return $.grep("msie safari mozilla opera".split(" "), function(){
    return $.browser[this];
  }).join(" ");
}
/*
 * Creates getters and setters for an object
 *
 * accessors( self , "userName" );
 * self.userName( "cohitre" ); // returns self
 * self.userName(); // returns "cohitre"
 */
function accessors( obj , name ) {
  var object;
  obj[name] = function( val ) { 
    if (val === undefined) return object
    object = val ;
    return this;
  }
}
/*
 * Loads a bunch of scripts and optionally executes
 * a function when all the scripts have loaded.
 * $.getScripts( [] , function() {
 *  console.log( "All scripts loaded");
 * });
 */
$.getScripts = function(scripts, callback) {
  var loaded = 0;
  $.each(scripts, function(i, s) {
    $.getScript(s, function() {
      loaded++;
      loaded === scripts.length && callback && callback.call();
    });
  });
};
/*
 * Polls an input element while it has focus.
 *
 * %("input#search").observe( function() {
 *   console.log("Your search: " + $(this).val() );
 * });
 */
$.fn.observe = function(callb, interval) {
  interval = interval === undefined ? 200 : interval;

  this.each(function(i, obj) {
    var self = $(obj);

    self.focus(function() {
      var hasFocus = true;
      var previousValue = self.val();
      setTimeout(function(){
        (previousValue !== self.val()) && callb.call(obj);
        previousValue = self.val();
        hasFocus && setTimeout(arguments.callee , interval);
      }, interval);

      self.one( "blur" , function(){
        hasFocus = false;
      });
    });
  });
}
/**
 * Fun games to play with checkbox selectors.
 */
$(":checkbox").change( function(){
  if ( !$(":checkbox:checked").length ) {
    $("#message").text("All the boxes are unchecked");
  }    
  else if ( $(":checkbox:not(:checked)").length ) {
    $("#message").text("Some boxes are empty");      
  }
  else {
    $("#message").text("All the boxes are checked");
  }
});
/*
 * .change() doesn't have a way to know what 
 * was the previous value. This function 
 * stores the previous value internally and
 * passes it to the callback.
 */
$.fn.changeWithMemory = function(callback) {
  this.each(function() {
    var prev = $(this).val();

    $(this).change(function() {
      var args = Array.prototype.slice.call(arguments);
      args.push(prev);
      callback.apply(this, args);
      prev = $(this).val();
    });
  });
}

$("#message").previousValue( function( prev ){
  $("#display").empty().append(
    $("<p/>").text("Previous: " + prev) ,
    $("<p/>").text("Current: " + $(this).val() )
  );
});
/*
 * Polls an input element while it has focus.
 *
 * %("input#search").observe( function() {
 *   console.log("Your search: " + $(this).val() );
 * });
 */
$.fn.observe = function(callb, interval) {
  interval = interval === undefined ? 200 : interval;

  this.each(function(i, obj) {
    var self = $(obj);
    var previousValue = self.val();
    var hasFocus = false;
    self.focus(function() {
      hasFocus = true;
      setTimeout(function(){
        (previousValue !== self.val()) && callb.call(obj);
        previousValue = self.val();
        hasFocus && setTimeout(arguments.callee , interval);
      }, interval);

      self.bind( "blur" , function(){
        self.unbind('blur', arguments.callee);
        hasFocus = false;
      } );
    });
  });
}

$("#message-input").observe( function(){
  $("#message-output").text($(this).val());
});
/* 
 * Calculates auto height
 *
 * var menuHeight = $("div.menu").autoHeight();
 * menu.animate({ height: menuHeight });
 *
 */
$.fn.autoHeight = function(prop) {
    var temp = this.height();
    var result = this.height("auto").height();
    this.height(temp)
    return result;

};

$.fn.autoWidth = function(prop) {
    var temp = this.width();
    var result = this.width("auto").width();
    this.width(temp)
    return result;

};
/*
 * Fun with logging.
 */
function test(){
  console.group("test");
  // get the value from a dropdown select
  console.log( "Select" , $('select#foo option:selected').val() );
  // get the value from a set of radio buttons
  console.log( "Radio" , $('input:radio:checked').val() );
  // get the value from a checked checkbox
  console.log( "Checkbox" , $('input:checkbox:checked').val() );
  console.groupEnd("test");
}
/*
 * Iterates over an array of numbers
 */
function forRange( start , end , callback ) {
  var results = [];
  for ( var i = start ; i < end ; i++ ) {
    results.push(callback.call( i , i));
  }
  return results;
}
/*
 * Executes a function with the jquery object and returns the object.
 *
 * $("div").exec( function(){ return this.length; });
 *
 */
$.fn.exec = function(f) {
    return f.call(this, this);
};
/*
 * Number to currency
 */
jQuery.fn.numberToCurrency = function (number) {
  this.text("$"+number.toFixed(2));
};