function _fnDetectHeader(settings, thead, write) {
		var columns = settings.aoColumns;
		var rows = $(thead).children('tr');
		var row, cell;
		var i, k, l, iLen, shifted, column, colspan, rowspan;
		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
		var layout = [];
		var unique;
		var shift = function (a, i, j) {
			var k = a[i];
			while (k[j]) {
				j++;
			}
			return j;
		};

		// We know how many rows there are in the layout - so prep it
		for (i = 0, iLen = rows.length; i < iLen; i++) {
			layout.push([]);
		}

		for (i = 0, iLen = rows.length; i < iLen; i++) {
			row = rows[i];
			column = 0;

			// For every cell in the row..
			cell = row.firstChild;
			while (cell) {
				if (
					cell.nodeName.toUpperCase() == 'TD' ||
					cell.nodeName.toUpperCase() == 'TH'
				) {
					var cols = [];

					// Get the col and rowspan attributes from the DOM and sanitise them
					colspan = cell.getAttribute('colspan') * 1;
					rowspan = cell.getAttribute('rowspan') * 1;
					colspan = (!colspan || colspan === 0 || colspan === 1) ? 1 : colspan;
					rowspan = (!rowspan || rowspan === 0 || rowspan === 1) ? 1 : rowspan;

					// There might be colspan cells already in this row, so shift our target
					// accordingly
					shifted = shift(layout, i, column);

					// Cache calculation for unique columns
					unique = colspan === 1 ?
						true :
						false;

					// Perform header setup
					if (write) {
						if (unique) {
							// Allow column options to be set from HTML attributes
							_fnColumnOptions(settings, shifted, $(cell).data());

							// Get the width for the column. This can be defined from the
							// width attribute, style attribute or `columns.width` option
							var columnDef = columns[shifted];
							var width = cell.getAttribute('width') || null;
							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
							if (t) {
								width = t[1];
							}

							columnDef.sWidthOrig = columnDef.sWidth || width;

							if (isHeader) {
								// Column title handling - can be user set, or read from the DOM
								// This happens before the render, so the original is still in place
								if (columnDef.sTitle !== null && !columnDef.autoTitle) {
									cell.innerHTML = columnDef.sTitle;
								}

								if (!columnDef.sTitle && unique) {
									columnDef.sTitle = cell.innerHTML.replace(/<.*?>/g, "");
									columnDef.autoTitle = true;
								}
							}
							else {
								// Footer specific operations
								if (columnDef.footer) {
									cell.innerHTML = columnDef.footer;
								}
							}

							// Fall back to the aria-label attribute on the table header if no ariaTitle is
							// provided.
							if (!columnDef.ariaTitle) {
								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
							}

							// Column specific class names
							if (columnDef.className) {
								$(cell).addClass(columnDef.className);
							}
						}

						// Wrap the column title so we can write to it in future
						if ($('span.dt-column-title', cell).length === 0) {
							$('<span>')
								.addClass('dt-column-title')
								.append(cell.childNodes)
								.appendTo(cell);
						}

						if (isHeader && $('span.dt-column-order', cell).length === 0) {
							$('<span>')
								.addClass('dt-column-order')
								.appendTo(cell);
						}
					}

					// If there is col / rowspan, copy the information into the layout grid
					for (l = 0; l < colspan; l++) {
						for (k = 0; k < rowspan; k++) {
							layout[i + k][shifted + l] = {
								cell: cell,
								unique: unique
							};

							layout[i + k].row = row;
						}

						cols.push(shifted + l);
					}

					// Assign an attribute so spanning cells can still be identified
					// as belonging to a column
					cell.setAttribute('data-dt-column', _unique(cols).join(','));
				}

				cell = cell.nextSibling;
			}
		}

		return layout;
	}
Use the DOM source to create up an array of header cells. The idea here is to
create a layout grid (array) of rows x columns, which contains a reference
to the cell that that point in the grid (regardless of col/rowspan), such that
any column / row could be removed and the new grid constructed
 @param {node} thead The header/footer element for the table
 @returns {array} Calculated layout array
 @memberof DataTable#oApi