/**
 * @class
 * Renders a widget for displaying a "loading" spinner.
 * 
 * Configuration options:
 * * +content+ - Actual content to embed in the spinner
 * * +background+ - CSS properties for the background
 * * +backgroundClass+ - The css class to add to the background element
 * * +foreground+ - CSS properties for the foreground
 * * +foregroundClass+ - The css class to add to the foreground element
 * 
 * == Examples
 * 
 * To display a spinner:
 * 
 *   <div id="container">
 *     <div id="data" style="width: 100px; height: 100px;"></div>
 *   </div>
 *   
 *   <script type="text/javascript">
 *     $('#data').spinner({content: 'Loading...'});
 *   </script>
 *   
 *   // >>
 *   
 *   <div id="container">
 *     <div id="data" style="width: 100px; height: 100px;"></div>
 *     <div class="ui-spinner-background" style="width: 100px; height: 100px; top: 47px; left: 253px;"></div>
 *     <div class="ui-spinner-foreground" style="width: 100px; height: 100px; top: 47px; left: 253px;">Loading...</div>
 *   </div>
 */
;(function($) {
  $.widget('ui.spinner', {
    /**
     * Creates a new spinner widget to be rendered within the current element
     */
    _init: function() {
      this.options.event += '.spinner'; // Namespace events
      
      // Background / "overlay"
      this.$background = $('<div />')
        .addClass(this.options.backgroundClass)
        .css(this.options.background)
        .appendTo(this.element.parent());
      
      // Foreground / "content"
      if (this.options.content) {
        // If content is displayed within the spinner, an additional inner
        // content element will be added
        this.$foreground = $('<div />')
          .addClass(this.options.foregroundClass)
          .css(this.options.foreground)
          .append($(this.options.content))
          .appendTo(this.element.parent());
      }
      
      this.refresh();
    },
    
    /**
     * Gets the current value (in pixels) of the dimension type
     * 
     * @param {String} type The type of dimension to calculate (can be "width" or "height")
     * @return {Number} The numeric dimension value
     */
    _dimension: function(type) {
      // Get the current dimension acccording to jQuery
      var value = this.element[type]();
      
      var parents = this.element.parents();
      for (var i = 0; i < parents.length; i++) {
        var parent = parents.eq(i);
        
        // If the parent is hiding overflow, then part of the element may be
        // hidden
        if (parent.css('overflow') == 'hidden') {
          var parentValue = parseFloat(parent[0].style[type]);
          
          if (value > parentValue) {
            // The current dimension value is *greater* than what was set on a
            // parent; since this means part of the element is being hidden, the
            // value is adjusted to the parent value
            value = parentValue;
          }
        }
      }
      
      return value;
    },
    
    /**
     * Repositions the spinner to match the width/height of the element that
     * it was rendered on.
     */
    refresh: function() {
      // Get position information from the element
      var position = this.element.position();

      // Build attributes for laying out the spinner
      var layout = {
        position: 'absolute',
        
        // Position the spinner over the entire element
        width: this.options.width || this.element.outerWidth(),
        height: this.options.height || this.element.outerHeight(),
        top: position.top,
        left: position.left
      };
      
      this.$background.css(layout);
      if (this.$foreground) this.$foreground.css(layout);
    },
    
    /**
     * Cleans up any changes made to the element
     */
    destroy: function() {
      // Remove the spinner from the page
      if (this.$foreground) this.$foreground.remove();
      this.$background.remove();
      
      // Reset the widget state for the element
      this.element.removeData('spinner');
    }
  });
  
  /**
   * The default configuration options for the ui.goodselector widget
   */
  $.ui.spinner.defaults = {
    /**
     * The content to display within the spinner, such as a loading message or
     * image indicating that something is being processed.
     * 
     * This can be any of the types of parameters processed by the jQuery
     * function, including:
     * 1. A css selector to the element to embed
     * 2. An html fragment to build an element from
     * 3. An actual dom element (regardless of whether it already exists on the page)
     * 
     * @type String|Element
     */
    content: null,
    
    /**
     * CSS properties to set for the background element
     * 
     * @type Object
     * @default {}
     */
    background: {},
    
    /**
     * The css class for the background element
     * 
     * @type String
     * @default "ui-spinner-background"
     */
    backgroundClass: 'ui-spinner-background',
    
    /**
     * CSS properties to set for the foreground element
     * 
     * @type Object
     * @default {}
     */
    foreground: {},
    
    /**
     * The css class for the foreground element
     * 
     * @type String
     * @default "ui-spinner-foreground"
     */
    foregroundClass: 'ui-spinner-foreground'
  };
})(jQuery);
