<?php
error_reporting(E_ALL);
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false); 
header("Cache-Control: private");
header("Pragma: no-cache");

define('DEFAULT_TABLE_ALIGN', 'center');
define('DEFAULT_CELLPAD', 0);
define('DEFAULT_CELLSPACE', 0);
define('DEFAULT_ALIGN', 'left');
define('DEFAULT_VALIGN', 'top');


/**
* Table class
*
* @access public
* Table class with row objects and cell objects
*
* @author Roland van Wanrooy
*/
class Table
{

	protected $container;	// contains the row objects
	protected $outputStr;	// string with the proper html-tags and content data
	protected $elements;	// for future use: number of rows in the table
	var $width;				// width; if null or invalid width will be omitted
	var $height;			// height; if null or invalid height will be omitted
	var $align;				// hor align; (e.g. 'L' or 'left', 'C' or 'center', etc)
							// if null or invalid align will be DEFAULT_ALIGN
	var $cellPad;			// cellpadding; if null or invalid cellPad will be DEFAULT_CELLPAD
	var $cellSpace;			// cellspacing; defaults to DEFAULT_CELLSPACE
	var $style;				// style (for CSS styles)
	var $extra;				// extra (for extra parameters, e.g. "rules=" of "frame=")

	/**
	* constructor Table()
	*
	* @access public
	* @param string/integer $siWidth: the width of the table (e.g. '100%', 100 for 100% or '100' for 100 pixels)
	* @param string $sAlign: horizontal alignment of the table (e.g. 'L' or 'left', 'C' or 'center', etc)
	* @param string $iCellPad: cellpadding
	* @return void
	*/
	function Table($siWidth = null, $sAlign = DEFAULT_TABLE_ALIGN, $iCellPad = DEFAULT_CELLPAD) {
		$this->container	= array();
		$this->width		= $siWidth;
		$this->align		= $sAlign;
		$this->cellPad		= $iCellPad;
		$this->cellSpace	= DEFAULT_CELLSPACE;
		$this->elements		= 0;
	}
	
	/**
	* add()
	*
	* @access public
	* @param object $oRow: the row object which has to be added to the table-container
	* @return void
	*/
	public function add($oRow) {
		$this->container[] = $oRow;		// add the row to the table
		$this->elements++;				// for future use
	}

	/**
	* output()
	*
	* @access public
	* @params: none
	* @return string $this->outputStr: proper html-tags and data of the table with all the rows and cells
	*/
	public function output() {
		// check if everything is valid
		$this->width 		= setDim($this->width);
		$this->height 		= setDim($this->height);
		$this->cellPad 		= (isZeroOrPositiveNumber($this->cellPad) 	? $this->cellPad : DEFAULT_CELLPAD);
		$this->cellSpace 	= (isZeroOrPositiveNumber($this->cellSpace) ? $this->cellSpace : DEFAULT_CELLSPACE);
		// build output string
		$this->outputStr 	='<table'.
		($this->width		? ' width='			.quote($this->width) : '').
		($this->align 		? ' align='			.quote(setAlign($this->align, 'horizontal')) : '').
		($this->cellPad 	? ' cellpadding='	.quote($this->cellPad) : '').
		($this->cellSpace 	? ' cellspacing='	.quote($this->cellSpace) : '').
		($this->style 		? ' style='			.quote($this->style) : '').
		($this->extra 		? ' '				.$this->extra : '').
		' border="0" summary="">'."\n";
		foreach ($this->container as $oRow) {
			$this->outputStr .= $oRow->output();
		}
		$this->outputStr .= '</table>'."\n";
		return $this->outputStr;
	}

	/**
	* display()
	* echoes the string with all the proper html tags and data of the table
	*
	* @access public
	* @params: none
	* @return void
	*/
	public function display() {
		echo $this->output();
	}
} // end class table
	
class Row
{

	protected $container;	// contains the cell objects
	protected $outputStr;	// string with the proper html-tags of the row and its cells
	protected $elements;	// for future use: number of cells in the row
	var $align;				// hor align; (e.g. 'L' or 'left', 'C' or 'center', etc)
							// if null or invalid align will be DEFAULT_ALIGN
	var $valign;			// ver align; (e.g. 'T' or 'top', 'B' or 'bottom', etc); defaults to DEFAULT_VALIGN
	var $style;				// style (for CSS styles)
	var $extra;				// extra (for extra parameters, e.g. "char=" of "charoff=")

	/**
	* constructor Row()
	*
	* @access public
	* @param string $sAlign: horizontal alignment of the cells in the row
	* @param string $sVAlign: vertical alignment of the cells in the row
	* @return void
	*/
	function Row($sAlign = DEFAULT_ALIGN, $sVAlign = DEFAULT_VALIGN) {
		$this->container	= array();
		$this->align		= $sAlign;
		$this->valign		= $sVAlign;
		$this->elements		= 0;
	}

	/**
	* add()
	*
	* @access public
	* @param object $oCell: the cell object which has to be added to the row-container
	* @return void
	*/
	public function add($oCell) {
		$this->container[] = $oCell;	// add the cell to the row
		$this->elements++;				// for future use
	}

	/**
	* output()
	*
	* @access public
	* @return string $this->outputStr: proper html-tags and data of the row and all the cells in the row
	*/
	public function output() {
		$this->outputStr .= "\t".'<tr'.
		($this->align	? ' align='		.quote(setAlign($this->align, 'horizontal')) : '').
		($this->valign	? ' valign='	.quote(setAlign($this->valign, 'vertical')) : '').
		($this->style	? ' style='		.quote($this->style) : '').
		($this->extra	? ' '			.$this->extra : '').
		'>'."\n";
		foreach ($this->container as $oCell) {
			$this->outputStr .= $oCell->output();
		}
		$this->outputStr .= "\t".'</tr>'."\n";
		return $this->outputStr;
	}
} // end class row

class Cell
{

	protected $outputStr;	// string with the proper html-tags and the data of the cell
	var $width;				// width; if null or invalid width will be omitted
	var $height;			// height; if null or invalid height will be omitted
	var $align;				// hor align; (e.g. 'L' or 'left', 'C' or 'center', etc)
							// if null or invalid align will be DEFAULT_ALIGN
	var $valign;			// ver align; (e.g. 'T' or 'top', 'B' or 'bottom', etc); defaults to DEFAULT_VALIGN
	var $style;				// style (for CSS styles)
	var $extra;				// extra (for extra parameters, e.g. "char=" of "charoff=")
	var $colspan;			// colspan; omitted if null or invalid
	var $rowspan;			// rowspan; omitted if null or invalid
	var $nowrap;			// 'nowrap' yes or no, default=false (no)
	var $content;			// content of the cell, the data

	/**
	* constructor Cell()
	*
	* @access public
	* @param string/integer $siWidth: width of the cell (e.g. '100%', 100 for 100% or '100' for 100 pixels)
	* @param string $sAlign: horizontal alignment of the cell
	* @param string $sVAlign: vertical alignment of the cell
	* @return void
	*/
	function Cell($siWidth=null, $sAlign = DEFAULT_ALIGN, $sVAlign = DEFAULT_VALIGN) {
		$this->width	= $siWidth;
		$this->align	= $sAlign;
		$this->valign	= $sVAlign;
		$this->nowrap	= false;
	}

	/**
	* output()
	*
	* @access public
	* @return string $this->outputStr: proper html-tags and data of the cell
	*/
	public function output() {
		// check if everything is valid
		$this->width 	= setDim($this->width);
		$this->height 	= setDim($this->height);
		$this->colspan 	= (isPositiveNumber($this->colspan) ? $this->colspan : null);
		$this->rowspan 	= (isPositiveNumber($this->rowspan) ? $this->rowspan : null);
		// build output string
		$this->outputStr = "\t\t".'<td'.
		($this->width	? ' width='		.quote($this->width) : '').
		($this->height	? ' height='	.quote($this->height) : '').
		($this->align  	? ' align='		.quote(setAlign($this->align, 'horizontal')) : '').
		($this->valign	? ' valign='	.quote(setAlign($this->valign, 'vertical')) : '').
		($this->colspan ? ' colspan='	.quote($this->colspan) : '').
		($this->rowspan	? ' rowspan='	.quote($this->rowspan) : '').
		($this->style	? ' style='		.quote($this->style) : '').
		($this->nowrap	? ' nowrap' : '').
		($this->extra	? ' '.$this->extra : '').
		'>'."\n";
		$this->outputStr .= ($this->content ? "\t\t\t".$this->content : '')."\n";
		$this->outputStr .= "\t\t".'</td>'."\n";
		return $this->outputStr;
	}
} // end class cell

/**
* setDim($siDim)
*
* @access public
* @param string/integer $siDim: width/height of the element (table, cell)
* @return string $sDim: example '34' or '34%'
*
* 	with an integer, float or numeric string param, the return value will be with percentage
*	examples:
*	- 34, 34,3		-> returns '34%'
*	- '34', '34,3' 	-> returns '34'
*/
function setDim($siDim) {
	$sDim = null;
	if ((is_integer($siDim) or is_float($siDim)) and ($siDim > 0))	// param is integer and positive; e.g. 34 or 34,5
		$sDim = round($siDim,0).'%';
	
	else { // param is string '34', '34,5' or '34%'
	
		if (substr($siDim,-1) == '%') {	// param is string with percentage; example '34%'; recurive call.
			$siDim = (int) substr($siDim,0,-1);
			$sDim = setDim($siDim);
		}
		
		else {	// param is string without %-sign
			$iTemp = (int) $siDim;
			if ($iTemp > 0)	// check if positive number
				$sDim = $siDim;
		}
	}
	// beyond this point the param is invalid; return value will be NULL
	return $sDim;
}

/**
* setAlign($sAlign, $sDirection)
*
* @access public
* @param string $sAlign: accepts the whole string (e.g. 'left', 'bottom') as well as the one character abbreviation ('L','B')
* @param string $sDirection: accepts the whole string (e.g. 'horizontal') as well as the abbreviations ('H','HOR')
* @return string: the proper param as a lower string
*/
function setAlign($sAlign, $sDirection){
	$sAlign = strtoupper($sAlign);
	$sDirection = strtoupper($sDirection);
	if ($sDirection == 'H' or $sDirection == 'HOR' or $sDirection == 'HORIZONTAL') {
		// only left, right, center and justify. char is rarely used.
		switch ($sAlign) {
			case 'L': return 'left'; 	break;
			case 'R': return 'right'; 	break;
			case 'C': return 'center'; 	break;
			case 'J': return 'justify'; 	break;
			case 'LEFT':
			case 'CENTER':
			case 'RIGHT':
			case 'JUSTIFY':
				return strtolower($sAlign); break;
			default : return DEFAULT_ALIGN;	break;
		}
	}
	elseif ($sDirection == 'V' or $sDirection == 'VER' or $sDirection == 'VERTICAL') {
		// only top, middle and bottom. no baseline.
		switch ($sAlign) {
			case 'T': return 'top'; 	break;
			case 'M': return 'middle'; 	break;
			case 'B': return 'bottom'; 	break;
			case 'TOP':
			case 'MIDDLE':
			case 'BOTTOM':
				return strtolower($sAlign); break;
			default : return DEFAULT_VALIGN;	break;
		}
	}
}

/**
* isZeroOrPositiveNumber($iNumber)
*
* @access public
* @param integer $iNumber
* e.g.: 'ThisValue'	-> returns '"ThisValue"'
* @return bool: iNumber is 0 or positive
*/
function isZeroOrPositiveNumber($iNumber) {
	return (is_integer($iNumber) and ($iNumber >= 0));
}

/**
* isPositiveNumber($iNumber)
*
* @access public
* @param integer $iNumber
* @return bool: iNumber is positive
*/
function isPositiveNumber($iNumber) {
	return (isZeroOrPositiveNumber($iNumber) and ($iNumber > 0));
}

/**
* quote($xVal)
*
* @access public
* @param mixed $xVal: the value, which has to be quoted
* e.g.: 'ThisValue'	-> returns '"ThisValue"'
* @return string: the quoted string
*/
function quote($xVal) {
	return '"' . $xVal . '"';
}



/* #####################################################################################################
*
*	TEST
*
* #####################################################################################################*/

echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'."\n";
echo '<html><head><title>Table Object Test</title></head><body>'."\n\n";

$oCel1 =& new Cell(50, 'right', 'bottom');
$oCel1->content = 'dit is een test';
$oCel1->height		= '300';
$oCel1->nowrap		= true;

$oCel2 =& new Cell();
$oCel2->content = 'test2';
$oCel2->width		= 50;
$oCel2->align		= 'left';
$oCel2->valign		= 'top';
$oCel2->style		= 'background-color:#FF0000;color:FFFF00;font-weight:bold;font-size:130%;';
$oCel2->extra		= 'char="."';

$oCel3 =& new Cell();
$oCel3->content = 'tessie';

$oCel4 =& new Cell(null, 'right');
$oCel4->content = 'een cel';

$oCel5 =& new Cell(null, 'center');
$oCel5->colspan = 2;
$oCel5->style	= 'background-color:#CCCCCC;font-weight:bold;';
$oCel5->content = 'colspan is 2';

$oRow1 =& new Row();
$oRow1->style='background-color:#FFFF00;';
$oRow1->add($oCel1);
$oRow1->add($oCel2);

$oRow2 =& new Row();
$oRow2->add($oCel3);
$oRow2->add($oCel4);

$oRow3 =& new Row();
$oRow3->add($oCel5);

$oTbl =& new Table(60);
$oTbl->align		= 'left';
$oTbl->cellPad		= 5;
$oTbl->cellSpace	= 15;
$oTbl->height		= 100;
$oTbl->style		= 'background-color:#FFFFCC;border:2px solid #999999;';
$oTbl->extra		= 'frame="hsides"';
$oTbl->add($oRow1);
$oTbl->add($oRow2);
$oTbl->add($oRow3);
$oTbl->display();

echo "\n\n".'</body></html>';

?>
