/*
 * 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); 

