public function generate($tableData = null)
	{
		// The table data can optionally be passed to this function
		// either as a database result object or an array
		if (! empty($tableData))
		{
			if ($tableData instanceof BaseResult)
			{
				$this->_setFromDBResult($tableData);
			}
			elseif (is_array($tableData))
			{
				$this->_setFromArray($tableData);
			}
		}

		// Is there anything to display? No? Smite them!
		if (empty($this->heading) && empty($this->rows))
		{
			return 'Undefined table data';
		}

		// Compile and validate the template date
		$this->_compileTemplate();

		// Validate a possibly existing custom cell manipulation function
		if (isset($this->function) && ! is_callable($this->function))
		{
			$this->function = null;
		}

		// Build the table!

		$out = $this->template['table_open'] . $this->newline;

		// Add any caption here
		if ($this->caption)
		{
			$out .= '<caption>' . $this->caption . '</caption>' . $this->newline;
		}

		// Is there a table heading to display?
		if (! empty($this->heading))
		{
			$out .= $this->template['thead_open'] . $this->newline . $this->template['heading_row_start'] . $this->newline;

			foreach ($this->heading as $heading)
			{
				$temp = $this->template['heading_cell_start'];

				foreach ($heading as $key => $val)
				{
					if ($key !== 'data')
					{
						$temp = str_replace('<th', '<th ' . $key . '="' . $val . '"', $temp);
					}
				}

				$out .= $temp . (isset($heading['data']) ? $heading['data'] : '') . $this->template['heading_cell_end'];
			}

			$out .= $this->template['heading_row_end'] . $this->newline . $this->template['thead_close'] . $this->newline;
		}

		// Build the table rows
		if (! empty($this->rows))
		{
			$out .= $this->template['tbody_open'] . $this->newline;

			$i = 1;
			foreach ($this->rows as $row)
			{
				// We use modulus to alternate the row colors
				$name = fmod($i ++, 2) ? '' : 'alt_';

				$out .= $this->template['row_' . $name . 'start'] . $this->newline;

				foreach ($row as $cell)
				{
					$temp = $this->template['cell_' . $name . 'start'];

					foreach ($cell as $key => $val)
					{
						if ($key !== 'data')
						{
							$temp = str_replace('<td', '<td ' . $key . '="' . $val . '"', $temp);
						}
					}

					$cell = isset($cell['data']) ? $cell['data'] : '';
					$out .= $temp;

					if ($cell === '' || $cell === null)
					{
						$out .= $this->emptyCells;
					}
					elseif (isset($this->function))
					{
						$out .= call_user_func($this->function, $cell);
					}
					else
					{
						$out .= $cell;
					}

					$out .= $this->template['cell_' . $name . 'end'];
				}

				$out .= $this->template['row_' . $name . 'end'] . $this->newline;
			}
		}

		// Any table footing to display?
		if (! empty($this->footing))
		{
			$out .= $this->template['tfoot_open'] . $this->newline . $this->template['footing_row_start'] . $this->newline;

			foreach ($this->footing as $footing)
			{
				$temp = $this->template['footing_cell_start'];

				foreach ($footing as $key => $val)
				{
					if ($key !== 'data')
					{
						$temp = str_replace('<th', '<th ' . $key . '="' . $val . '"', $temp);
					}
				}

				$out .= $temp . (isset($footing['data']) ? $footing['data'] : '') . $this->template['footing_cell_end'];
			}

			$out .= $this->template['footing_row_end'] . $this->newline . $this->template['tfoot_close'] . $this->newline;
		}

		$out .= $this->template['tbody_close'] . $this->newline;

		// And finally, close off the table
		$out .= $this->template['table_close'];

		// Clear table class properties before generating the table
		$this->clear();

		return $out;
	}