/*
 * jQuery columnHover plugin
 * Version: 0.1.1
 *
 * Copyright (c) 2007 Roman Weich
 * http://p.sohei.org
 *
 * Dual licensed under the MIT and GPL licenses 
 * (This means that you can choose the license that best suits your project, and use it accordingly):
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Changelog: 
 * v 0.1.1 - 2007-08-05
 *  -change: included new option "ignoreCols", through which columns can be excluded from the highlighting process
 * v 0.1.0 - 2007-05-25
 */

(function($)
{
  /**
   * Calculates the actual cellIndex value of all cells in the table and stores it in the realCell property of each cell.
   * Thats done because the cellIndex value isn't correct when colspans or rowspans are used.
   * Originally created by Matt Kruse for his table library - Big Thanks! (see http://www.javascripttoolbox.com/)
   * @param {element} table The table element.
   */
  var fixCellIndexes = function(table) 
  {
    var rows = table.rows;
    var len = rows.length;
    var matrix = [];
    for ( var i = 0; i < len; i++ )
    {
      var cells = rows[i].cells;
      var clen = cells.length;
      for ( var j = 0; j < clen; j++ )
      {
        var c = cells[j];
        var rowSpan = c.rowSpan || 1;
        var colSpan = c.colSpan || 1;
        var firstAvailCol = -1;
        if ( !matrix[i] )
        { 
          matrix[i] = []; 
        }
        var m = matrix[i];
        // Find first available column in the first row
        while ( m[++firstAvailCol] ) {}
        c.realIndex = firstAvailCol;
        for ( var k = i; k < i + rowSpan; k++ )
        {
          if ( !matrix[k] )
          { 
            matrix[k] = []; 
          }
          var matrixrow = matrix[k];
          for ( var l = firstAvailCol; l < firstAvailCol + colSpan; l++ )
          {
            matrixrow[l] = 1;
          }
        }
      }
    }
  };

  /**
   * Highlight whole table columns when hovering over a table.
   * Works on tables with rowspans and colspans.
   *
   * @param {map} options     An object for optional settings (options described below).
   *
   * @option {string} hoverClass    A CSS class that is set on the cells in the column with the mouse over.
   *              Default value: 'hover'
   * @option {boolean} eachCell   Allows highlighting the column while hovering over the table body or table footer. When disabled, highlighting is allowed only through the table header.
   *              Default value: false
   * @option {boolean} includeSpans   Includes columns with the colspan attribute set in the hover and highlight process.
   *              Default value: true
   * @option {array} ignoreCols   An array of numbers. Each column with the matching column index won't be included in the highlighting process.
   *              Index starting at 1!
   *              Default value: [] (empty array)
   *
   * @example $('#table').columnHover();
   * @desc Allow column hovering/highlighting for the table using the default settings.
   *
   * @example $('#table').columnHover({eachCell:true, hoverClass:'someclass'});
   * @desc Allow column hovering/highlighting for the whole table (including the body and footer). Set the class "someclass" to the cells in the column with the mouse over.
   *
   * @type jQuery
   *
   * @name columnHover
   * @cat Plugins/columnHover
   * @author Roman Weich (http://p.sohei.org)
   */
  $.fn.columnHover = function(options)
  {
    var settings = $.extend({
        hoverClass: 'hover',
        eachCell: false,
        includeSpans : true,
        ignoreCols : []
      }, options);

    /**
     * Adds or removes the hover style on the column.
     * @param {element} cell  The cell with the mouseover/mouseout event.
     * @param {array} colIndex  The index with the stored columns.
     * @param {boolean} on    Defines whether the style will be set or removed.
     */
    var hover = function(cell, colIndex, on)
    {
      var a = colIndex[cell.realIndex];
      var i = 0;
      if ( $(settings.ignoreCols).index(cell.realIndex + 1) != -1 )
      {
        return; //dont highlight the columns in the ignoreCols array
      }
      while ( ++i < cell.colSpan )
      {
        a = a.concat(colIndex[cell.realIndex + i]);
      }
      if ( on )
      {
        $(a).addClass(settings.hoverClass);
      }
      else
      {
        $(a).removeClass(settings.hoverClass);
      }
    };

    /**
     * Adds the hover events to the cell.
     * @param {jQuery result array} $s  The elements to add the events to.
     * @param {array} colIndex  The index with the stored columns.
     */
    var addHover = function($s, colIndex)
    {
      $s.bind('mouseover', function(){
        hover(this, colIndex, true);
      }).bind('mouseout', function(){
        hover(this, colIndex, false);
      });
    };
    
    return this.each(function() 
        {
      var colIndex = [];
      var tbl = this;
      var body, row, c, tboI, rowI, cI, rI, s;

      if ( !tbl.tBodies || !tbl.tBodies.length || !tbl.tHead || !settings.hoverClass.length )
      {
        return;
      }
      fixCellIndexes(tbl);
      //create index - loop through the bodies
      for ( tboI = 0; tboI < tbl.tBodies.length; tboI++ )
      {
        body = tbl.tBodies[tboI];
        //loop through the rows
        for ( rowI = 0; rowI < body.rows.length; rowI++ )
        {
          row = body.rows[rowI];
          //each cell
          for ( cI = 0; cI < row.cells.length; cI++ )
          {
            c = row.cells[cI];
            //ignore cells with colspan?
            if ( !settings.includeSpans && c.colSpan > 1 )
            {
              continue;
            }
            s = (settings.includeSpans) ? c.colSpan : 1;
            while ( --s >= 0 )
            {
              rI = c.realIndex + s;
              if ( !colIndex[rI] )
              {
                colIndex[rI] = [];
              }
              colIndex[rI].push(c);
            }
            //add hover event?
            if ( settings.eachCell )
            {
              addHover($(c), colIndex);
            }
          }
        }
      }
      //events
      addHover($('td, th', tbl.tHead), colIndex);
      //add hover event to footer?
      if ( settings.eachCell && tbl.tFoot )
      {
        addHover($('td, th', tbl.tFoot), colIndex);
      }
    });
  };
})(jQuery); 

