<?php
/**
 * FPDF Table - FPDF class extension
 * Copyright (c) 2005-2010, http://www.interpid.eu
 *
 * FPDF Table is licensed under the terms of the GNU Open Source GPL 3.0
 * license.
 *
 * Commercial use is prohibited. Visit <http://www.interpid.eu/fpdf-components>
 * if you need to obtain a commercial license.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
 *
 * 
  * Version:        3.4.3
 * Date:        2005/07/20
 * Author:        Bintintan Andrei <andy@interpid.eu>



/**
Modifications:
2007.03.03
	- added support for ROWSPAN
	- changed the class functions/variables for PHP5 
2006.09.25
    - corrected a bug for empty cell texts
    - corrected a bug for cell lines aligment error on new page
2006.05.18
    - added support for cell splitting if new page ocuurs. FPDF_TABLE::tbSetSplitMode(true/false)
    sets the splitting mode.
            true = normal mode, the cell is splitted where the split ocuurs.
            false = if splitting is required then the cell is drawed on the new page. If the cell
            Height is bigger then the page height then the cell will be splitted.
    - if the header does not have enough space for double it's Height then a new page ocuurs.
*/
require_once(dirname(__FILE__).'/class.multicelltag.php');

/**
 * FPDF_TABLE - FPDF TABLE Add On Class
 * @author 		Bintintan Andrei
 * @copyright 	2005 - 2007
 */
class fpdf_table extends fpdf_multicelltag 
{
	
/**
 * Number of Columns of the Table
 * @access 	protected
 * @var		int
 */
protected 	$iColumnsNr = 0;

/**
 *	Contains the Header Data - header characteristics and texts
 *	
 *	Characteristics constants for Header Type:
 *	EVERY CELL FROM THE TABLE IS A MULTICELL
 *
 *	WIDTH - this is the cell width. This value must be sent only to the HEADER!!!!!!!!
 *	T_COLOR - text color = array(r,g,b);
 *	T_SIZE - text size
 *	T_FONT - text font - font type = "Arial", "Times"
 *	T_ALIGN - text align - "RLCJ"
 *	V_ALIGN - text vertical alignment - "TMB"
 *	T_TYPE - text type (Bold Italic etc)
 *	LN_SPACE - space between lines
 *	BG_COLOR - background color = array(r,g,b);
 *	BRD_COLOR - border color = array(r,g,b);
 *	BRD_SIZE - border size --
 *	BRD_TYPE - border size -- up down, with border without!!! etc
 *	BRD_TYPE_NEW_PAGE - border type on new page - this is user only if specified(<>'')
 *	TEXT - header text -- THIS ALSO BELONGS ONLY TO THE HEADER!!!!
 *
 *	all these setting conform to the settings from the multicell functions!!!!	
 * 
 * @access 	protected
 * @var 	array
 */
protected 	$aTableHeaderType = array();

/**
 * Header is drawed or not
 * @access 	protected
 * @var		boolean
 */
protected	$bTableHeaderDraw = true;

/**
 * Table Border is drawed or not
 * @access 	protected
 * @var		boolean
 */
protected	$bTableBorderDraw = true;

/**
 * Table Data Characteristics 
 * @access 	protected
 * @var		array
 */
protected 	$aTableDataType = array();

/**
 * Table Characteristics 
 * @access 	protected
 * @var		array
 */
protected 	$aTableType = array();

/**
 * Page Split Variable - if the table does not have enough space on the current page then the cells will be splitted.
 * This onlu if $bTableSplit == TRUE
 * If $bTableSplit == FALSE then the current cell will be drawed on the next page
 *
 * @access 	protected
 * @var 	boolean
 */
protected	$bTableSplit = true;

/**
 * TRUE - if on current page was some data written
 * @access 	protected
 * @var		boolean
 */
protected	$bDataOnCurrentPage = false;

/**
 * Table Data Cache. Will contain the information about the rows of the table
 * @access 	protected
 * @var		array
 */
protected	$aDataCache = array();

/**
 * TRUE - if there is a Rowspan in the Data Cache
 * @access 	protected	
 * @var		boolean
 */
protected	$bRowSpanInCache = false;

/**
 * Sequence for Rowspan ID's. Every Rowspan gets a unique ID
 * @access 	protected
 * @var		int
 */
protected	$iRowSpanID = 0;

/**
 * Table Header Cache. Will contain the information about the header of the table
 * @access 	protected
 * @var		array
 */
protected	$aHeaderCache = array();

/**
 * Header Height. In user units!
 * @access 	protected
 * @var		int
 */
protected	$iHeaderHeight = 0;

/**
 * Table Start X Position
 * @access 	protected
 * @var		int
 */
protected	$iTableStartX = 0;

/**
 * Table Start Y Position
 * @access 	protected
 * @var		int
 */
protected	$iTableStartY = 0;

/**
 * CLASS FUNCTIONS 
 */

/**
 * Returns the current page Width
 *
 * @access 	protected
 * @param 	void
 * @return  integer - the Page Width
 */
protected function PageWidth(){
	return (int) $this->w - $this->rMargin - $this->lMargin;
}//function PageWidth


/**
 * Returns the current page Height
 *
 * @access 	protected
 * @param 	void
 * @return	integer - the Page Height
 */
protected function PageHeight(){
	return (int) $this->h - $this->tMargin - $this->bMargin;
}//function PageHeight



/**
 * CONSTRUCTOR
 * Table Initialization Function
 *
 * @access 	public
 * @param	integer	- $iColumnsNr - Number of Colums 
 * @param	boolean	- $bTableHeaderDraw	- true => Draw the table header on a new page
 * @param	boolean - $bTableBorderDraw - true => Draw the table border
 * @return 	null
 */
public function tbInitialize($iColumnsNr = 0, $bTableHeaderDraw = true, $bTableBorderDraw = true){

	$this->iColumnsNr = $iColumnsNr;
	$this->aTableHeaderType = Array();
	$this->bTableHeaderDraw = $bTableHeaderDraw;
	$this->aTableDataType = Array();
	
	$this->aDataCache = Array();
	$this->aHeaderCache = Array();
	
	$this->bTableBorderDraw = $bTableBorderDraw;
	$this->bTableHeaderDraw = $bTableHeaderDraw;
			
	$this->iTableStartX = $this->GetX();
	$this->iTableStartY = $this->GetY();

	$this->bDataOnCurrentPage = false;
}

/**
 * Sets the number of Columns in the Table
 *
 * @access 	public
 * @param	integer	$iNr	- the number of Columns
 * @return 	void
 */
public function tbSetColumnsNo($iNr){
	$this->iColumnsNr = $iNr;
}

/**
 * Sets the Split Mode of the Table. Default is ON(true)
 *
 * @access 	public
 * @param	boolean $bSplit - if TRUE then Split is Active
 * @return 	void
 */
public function tbSetSplitMode($bSplit = true){
	$this->bTableSplit = $bSplit;
}

/**
 * Sets the Header Type
 * 
 * $aHeaderType=
 *	 array(
 *		0=>array(
 *				"WIDTH" => 10,
 *				"T_COLOR" => array(120,120,120),
 *				"T_SIZE" => 5,
 *				...
 *				"TEXT" => "Header text 1"
 *			  ),
 *		1=>array(
 *				...
 *			  ),
 *	 );
 * 
 * 	where 0,1... are the column number
 * 
 * If the Header has multiple lines than $aHeaderType WILL HAVE TO Contain an array, which elements are composed from the array
 * desribed above.
 * 		$aHeaderType = array ($aHeaderType1, $aHeaderType2) where $aHeaderType1 and $aHeaderType2 have the above description
 *
 * @access 	public
 * @param	array	$type_arr - header type
 * @param	boolean $bMultiLines - the header has multiple lines or not
 * @return 	void
 */
public function tbSetHeaderType($aHeaderType, $bMultiLines = false){
	if ($bMultiLines == false)
		$this->aTableHeaderType[0] = $aHeaderType;
	else 
		$this->aTableHeaderType = $aHeaderType;
		
	//create the header cache data
	foreach ($this->aTableHeaderType as $val)
		$this->_tbAddDataToCache($val, 'header');	
		
	$this->_tbCacheParseRowspan(0, 'header');
		
	$this->tbHeaderHeight();
}


/**
 * Calculates the Header Height. 
 * If the Header height is bigger than the page height then the script dies. 
 * 
 * @access 	private
 * @param 	void
 * @return 	void
 */
private function tbHeaderHeight(){
	$this->iHeaderHeight = 0;
		
	$iItems = count($this->aHeaderCache);
	for ($i=0; $i< $iItems; $i++){
		$this->iHeaderHeight += $this->aHeaderCache[$i]['HEIGHT'];
	}
		
	if ($this->iHeaderHeight > $this->PageHeight()){
		die("Header Height({$this->iHeaderHeight}) bigger than Page Height({$this->PageHeight()})");
	}
}//private function tbHeaderHeight



/**
 * Calculates the X margin of the table depending on the ALIGN 
 *
 * @access 		protected
 * @param 		void
 * @return 		void
 */
protected function tbMarkMarginX(){
	
	
	if (isset($this->aTableType['TB_ALIGN'])){
		$tb_align = $this->aTableType['TB_ALIGN']; 
	}else{
		$tb_align='';
	}

	//set the table align
	switch($tb_align){
		case 'C':
			$this->iTableStartX = $this->lMargin + $this->aTableType['L_MARGIN'] + ($this->PageWidth() - $this->tbGetWidth())/2;
			break;
		case 'R':
			$this->iTableStartX = $this->lMargin + $this->aTableType['L_MARGIN'] + ($this->PageWidth() - $this->tbGetWidth());
			break;
		default:
			$this->iTableStartX = $this->lMargin + $this->aTableType['L_MARGIN'];
			break;
	}//
	
}//protected function tbMarkMarginX


/*
Characteristics constants for Data Type:
EVERY CELL FROM THE TABLE IS A MULTICELL
	T_COLOR - text color = array(r,g,b);
	T_SIZE - text size
	T_FONT - text font - font type = "Arial", "Times"
	T_ALIGN - text align - "RLCJ"
	V_ALIGN - text vertical alignment - "TMB"
	T_TYPE - text type (Bold Italic etc)
	LN_SPACE - space between lines
	BG_COLOR - background color = array(r,g,b);
	BRD_COLOR - border color = array(r,g,b);
	BRD_SIZE - border size --
	BRD_TYPE - border size -- up down, with border without!!! etc
	BRD_TYPE_NEW_PAGE - border type on new page - this is user only if specified(<>'')

	all these settings conform to the settings from the multicell functions!!!!
*/

/**
 * Sets the Data Type. This Data Type is used as the default type for datas in the entire table. Of corse the user can
 * specify for every cell some specific data types
 * $aDataType=
 *	 array(
 *		0=>array(
 *				"WIDTH" => 10,
 *				"T_COLOR" => array(120,120,120),
 *				"T_SIZE" => 5,
 *				...
 *				"TEXT" => "Header text 1"
 *			  ),
 *		1=>array(
 *				...
 *			  ),
 *	 );
 * 
 * 	where 0,1... are the column number
 * 
 * @access 	public
 * @param	array - $aDataType - Array Containing the Data Type
 * @return 	void
 */
public function tbSetDataType($aDataType){
	$this->aTableDataType = $aDataType;
}//function tbSetDataType


/**
 * Sets the Table Type
 * 
 * $aTableType = array(
 * 					"BRD_COLOR"=> array (120,120,120), //border color
 * 					"BRD_SIZE"=>5), //border line width
 * 					"iColumnsNr"=>5), //the number of columns
 * 					"TB_ALIGN"=>"L"), //the align of the table, possible values = L, R, C equivalent to Left, Right, Center
 * 					'L_MARGIN' => 0// left margin... reference from this->lmargin values
 * 					);
 * 
 * @access 	public
 * @param	array	$aTableType - array containing the Table Type
 * @return 	void
 */
public function tbSetTableType($aTableType){

	if (isset($aTableType['iColumnsNr'])) $this->iColumnsNr = $aTableType['iColumnsNr'];
	if (!isset($aTableType['L_MARGIN'])) $aTableType['L_MARGIN']=0;//default values

	$this->aTableType = $aTableType;
	$this->tbMarkMarginX();

}//function tbSetTableType


/**
 * Draws the Table Border
 * 
 * @access 	public
 * @param 	void
 * @return 	void
 */
public function tbDrawBorder(){

	if ( ! $this->bTableBorderDraw ) return;

	if ( ! $this->bDataOnCurrentPage) return; //there was no data on the current page

	//set the colors
	list($r, $g, $b) = $this->aTableType['BRD_COLOR'];
	$this->SetDrawColor($r, $g, $b);

	//set the line width
	$this->SetLineWidth($this->aTableType['BRD_SIZE']);
    
	//draw the border
	$this->Rect(
		$this->iTableStartX,
		$this->iTableStartY,
		$this->tbGetWidth(),
		$this->GetY() - $this->iTableStartY);

}//function tbDrawBorder


/**
 * End Page Special Border Draw. This is called in the case of a Page Split
 *
 * @access 	protected
 * @param 	void
 * @return 	void
 */
protected function _tbEndPageBorder(){
	if (isset($this->aTableType['BRD_TYPE_END_PAGE'])){

		if (strpos($this->aTableType['BRD_TYPE_END_PAGE'], 'B') >= 0){

			//set the colors
			list($r, $g, $b) = $this->aTableType['BRD_COLOR'];
			$this->SetDrawColor($r, $g, $b);

			//set the line width
			$this->SetLineWidth($this->aTableType['BRD_SIZE']);

			//draw the line
			$this->Line($this->table_startx, $this->GetY(), $this->table_startx + $this->tbGetWidth(), $this->GetY());
		}//fi
	}//fi
}//function _tbEndPageBorder

/**
 * Returns the table width in user units
 *
 * @access 	public
 * @param 	void
 * @return 	integer - table width
 */
public function tbGetWidth()
{
	//calculate the table width
	$tb_width = 0;
	
	for ($i=0; $i < $this->iColumnsNr; $i++){
		$tb_width += $this->aTableHeaderType[0][$i]['WIDTH'];
	}
	
	return $tb_width;
}//tbGetWidth


/**
 * Aligns the table to the Start X point
 *
 * @access 		protected
 * @param 		void
 * @return 		void
 * 
 */
protected function _tbAlign(){
	$this->SetX($this->iTableStartX);
}//function _tbAlign(){


/**
 * "Draws the Header". 
 * More specific puts the data from the Header Cache into the Data Cache
 * 
 * @access 	public
 * @param 	void
 * @return 	void
 */
public function tbDrawHeader(){
	
	foreach($this->aHeaderCache as $val){
		$this->aDataCache[] = $val;
	}
}//function tbDrawHeader


/**
 * Adds a line to the Table Data or Header Cache.
 * Call this function after the table initialization, table, header and data types are set
 * 
 * @access 	public
 * @param	array $data - Data to be Drawed
 * @param	booleab $header - Array Containing data is Header Data or Data Data
 * @return	null
 */
public function tbDrawData($data, $header = true){
	$this->_tbAddDataToCache($data);
}

/**
 * Adds the data to the cache
 *
 * @access	protected
 * @param	array	$data - array containing the data to be added
 * @param	string 	$sDataType - data type. Can be 'data' or 'header'. Depending on this data the $data is put in the selected cache
 * @return 	void
 */
protected function _tbAddDataToCache($data, $sDataType = 'data'){
	
	
	if (!is_array($data)) {
		//this is fatal error
		trigger_error("Invalid data value 0x00012. (not array)", E_USER_ERROR);
	}
	
	//IF UTF8 Support is needed then 
	if (isset($this->utf8_support) && ($this->utf8_support)){
		for($i=0; $i < $this->iColumnsNr; $i++){
			$data[$i]['TEXT'] = utf8_decode($data[$i]['TEXT']);
		}
		
		//keep the compatibility with the "old" fpdf utf8 support.
		if (isset($this->utf8_decoded)) $this->utf8_decoded = true;		
	}
		
	if ($sDataType == 'data')
		$aDataCache = & $this->aDataCache;
	elseif ($sDataType == 'header')
		$aDataCache = & $this->aHeaderCache;
		
	$aRowSpan = array();
	
	
	$hm = 0;
	$rowspan = false;
	
	/**
	 * If datacache is empty initialize it
	 */
	if (count($aDataCache) > 0) $aLastDataCache = end($aDataCache);
	else $aLastDataCache = array();
	
	//this variable will contain the active colspans
	$iActiveColspan = 0;
	
	//calculate the maximum height of the cells
	for($i=0; $i < $this->iColumnsNr; $i++){
		
        if (!isset($data[$i]['TEXT']) || ($data[$i]['TEXT']=='')) $data[$i]['TEXT'] = ' ';
		if (!isset($data[$i]['T_FONT'])) $data[$i]['T_FONT'] = $this->aTableDataType[$i]['T_FONT'];
		if (!isset($data[$i]['T_TYPE'])) $data[$i]['T_TYPE'] = $this->aTableDataType[$i]['T_TYPE'];
		if (!isset($data[$i]['T_SIZE'])) $data[$i]['T_SIZE'] = $this->aTableDataType[$i]['T_SIZE'];
		if (!isset($data[$i]['T_COLOR'])) $data[$i]['T_COLOR'] = $this->aTableDataType[$i]['T_COLOR'];
		if (!isset($data[$i]['T_ALIGN'])) $data[$i]['T_ALIGN'] = $this->aTableDataType[$i]['T_ALIGN'];
		if (!isset($data[$i]['V_ALIGN'])) $data[$i]['V_ALIGN'] = $this->aTableDataType[$i]['V_ALIGN'];
		if (!isset($data[$i]['LN_SIZE'])) $data[$i]['LN_SIZE'] = $this->aTableDataType[$i]['LN_SIZE'];
		if (!isset($data[$i]['BRD_SIZE'])) $data[$i]['BRD_SIZE'] = $this->aTableDataType[$i]['BRD_SIZE'];
		if (!isset($data[$i]['BRD_COLOR'])) $data[$i]['BRD_COLOR'] = $this->aTableDataType[$i]['BRD_COLOR'];
		if (!isset($data[$i]['BRD_TYPE'])) $data[$i]['BRD_TYPE'] = $this->aTableDataType[$i]['BRD_TYPE'];
		if (!isset($data[$i]['BG_COLOR'])) $data[$i]['BG_COLOR'] = $this->aTableDataType[$i]['BG_COLOR'];
		if (!isset($data[$i]['COLSPAN'])) $data[$i]['COLSPAN'] = 1; else $data[$i]['COLSPAN'] = (int) $data[$i]['COLSPAN'];
		if (!isset($data[$i]['ROWSPAN'])) $data[$i]['ROWSPAN'] = 1; else $data[$i]['ROWSPAN'] = (int) $data[$i]['ROWSPAN'];
		$data[$i]['HEIGHT'] = 0;	//default HEIGHT
		$data[$i]['SKIP'] = false;	//default SKIP (don't skip)
		$data[$i]['CELL_WIDTH'] = $this->aTableHeaderType[0][$i]['WIDTH'];	//copy this from the header settings
		$data[$i]['ROWSPAN_PRIMARY'] = FALSE;	//==true then this row has generated the rowspan
		$data[$i]['ROWSPAN_ID'] = 0;	//rowspan ID
		$data[$i]['HEIGHT'] = 0;	//default HEIGHT
				
		if ($data[$i]['LN_SIZE'] <= 0){
			trigger_error("Invalid Line Size {$data[$i]['LN_SIZE']}", E_USER_ERROR);
		}
		
		
		//if there is an active colspan on this line we just skip this cell
		if ($iActiveColspan > 1){
			$data[$i]['SKIP'] = true;
			//if ($i>0) $data[$i]['ROWSPAN'] = $data[$i-1]['ROWSPAN'];
			$iActiveColspan --;
			continue;
		}

		
		if (!empty($aLastDataCache)){
			
			//there was at least one row before
			
			if ( $aLastDataCache['DATA'][$i]['ROWSPAN'] > 1 ){
				/**
				 * This is rowspan over this cell. The cell will be ignored but some characteristics are kept
				 */
				
				//this cell will be skipped
				$data[$i]['SKIP'] =true;
				//decrease the rowspan value... one line less to be spanned
				$data[$i]['ROWSPAN'] = $aLastDataCache['DATA'][$i]['ROWSPAN'] - 1;
				$data[$i]['ROWSPAN_ID'] = $aLastDataCache['DATA'][$i]['ROWSPAN_ID'];
				$data[$i]['ROWSPAN_PRIMARY'] = false;
				//copy the colspan from the last value
				$data[$i]['COLSPAN'] = $aLastDataCache['DATA'][$i]['COLSPAN'];
				//cell with is the same as the one from the line before it
				$data[$i]['CELL_WIDTH'] = $aLastDataCache['DATA'][$i]['CELL_WIDTH'];
				
				if ($data[$i]['COLSPAN'] > 1){
					$iActiveColspan = $data[$i]['COLSPAN'];
				}
				
				continue; //jump to the next column
				
			}//if
			
		}//if
		
		
		//set the font settings
		$this->SetFont(	$data[$i]['T_FONT'],
						$data[$i]['T_TYPE'],
						$data[$i]['T_SIZE']);

		
		/**
		 * If we have colspan then we ignore the "colspanned" cells
		 */
		if ( $data[$i]['COLSPAN'] > 1 ){

			for ($j = 1; $j < $data[$i]['COLSPAN']; $j++){
				//if there is a colspan, then calculate the number of lines also with the with of the next cell
				if (($i + $j) < $this->iColumnsNr)
					$data[$i]['CELL_WIDTH'] += $this->aTableHeaderType[0][$i + $j]['WIDTH'];
			}//for
					
		}//if
		
		//add the cells that are with rowspan to the rowspan array - this is used later
		if ( $data[$i]['ROWSPAN'] > 1 ){
			$data[$i]['ROWSPAN_PRIMARY'] = true;
			$this->iRowSpanID++;
			$data[$i]['ROWSPAN_ID'] = $this->iRowSpanID;
			$aRowSpan[] = $i;
		}
       
		
        //$MaxLines = floor($AvailPageH / $data[$i]['LN_SIZE']);//floor this value, must be the lowest possible
        
        if (!isset($data[$i]['TEXT_STRLINES'])) $data[$i]['TEXT_STRLINES'] = $this->mt_StringToLines($data[$i]['CELL_WIDTH'], $data[$i]['TEXT']);
        $data[$i]['CELL_LINES'] = count($data[$i]['TEXT_STRLINES']);
        
        /**
         * IF THERE IS ROWSPAN ACTIVE Don't include this cell Height in the calculation. 
         * This will be calculated later with the sum of all heights
         */
        
        $data[$i]['HEIGHT'] = $data[$i]['LN_SIZE'] * $data[$i]['CELL_LINES'];
        
        if ( $data[$i]['ROWSPAN'] == 1 ){
        	$hm = max($hm, $data[$i]['HEIGHT']);//this would be the normal height
        }
        
		if ( $data[$i]['COLSPAN'] > 1 ){
			//just skip the other cells
			$iActiveColspan = $data[$i]['COLSPAN'];
		}//if
		
	}//for($i=0; $i < $this->iColumnsNr; $i++)	
	
	
	$aDataCache[] = array(
		'HEIGHT' => $hm,	//THIS LINE MAXIMUM HEIGHT
		'DEFAULT_HEIGHT' => $hm,	//THIS LINE DEFAULT MAXIMUM HEIGHT
		'DEFAULT_HEIGHT_SET' => true,
		'DATATYPE' => $sDataType,	//The data Type - Data/Header
		'DATA' => $data,	//this line's data
		'ROWSPAN' => $aRowSpan	//rowspan ID array
	);
	
	//we set the rowspan in cache variable to true if we have a rowspan
	if (! empty($aRowSpan) && (!$this->bRowSpanInCache)){
		$this->bRowSpanInCache = true;
	}
	
	return;
}//function _tbAddDataToCache



/**
 * Parses the Data Cache and calculates the maximum Height of each row. Normally the cell Height of a row is calculated 
 * when the data's are added, but when that row is involved in a Rowspan then it's Height can change!
 *
 * @access 	protected
 * @param	integer	$iStartIndex - the index from which to parse
 * @param	string	$sCacheType - what type has the cache - possible values: 'header' && 'data'
 * @return	void
 */
protected function _tbCacheParseRowspan($iStartIndex = 0, $sCacheType = 'data'){
	
	if ($sCacheType == 'data')
		$aDataCache = & $this->aDataCache;
	else 
		$aDataCache = & $this->aHeaderCache;
	
	$aRowSpans = array();
	
	$iItems = count($aDataCache);
	
	for ($ix = $iStartIndex; $ix < $iItems; $ix++){
		
		$val = & $aDataCache[$ix];
	
		if (!in_array($val['DATATYPE'], array('data', 'header') )) continue;
		
		//if there is no rowspan jump over
		if (empty($val['ROWSPAN'])) continue;
		
		foreach ($val['ROWSPAN'] as $k){
			
			#$val['HEIGHT'] = $val['DEFAULT_HEIGHT'];			
			
			if ($val['DATA'][$k]['ROWSPAN'] < 1) continue;	//skip the rows without rowspan
			
			/**
			if ($val['DEFAULT_HEIGHT_SET'] == false){
				$val['HEIGHT'] = $val['DEFAULT_HEIGHT'];
			}
			*/
			
			$aRowSpans[] = array(
				'row_id' => $ix,
				'cell_id' => &$val['DATA'][$k]
			);
			
			$h_rows = 0;
			
			//calculate the sum of the Heights for the lines that are included in the rowspan
			for ( $i=0; $i < $val['DATA'][$k]['ROWSPAN']; $i++){
				if (isset($aDataCache[$ix + $i]))
					$h_rows += $aDataCache[$ix + $i]['HEIGHT'];
			}
			
			//this is the cell height that makes the rowspan
			$h_cell = $val['DATA'][$k]['HEIGHT'];
			
			//if the 
			//$val['DATA'][$k]['HEIGHT_MAX'] = max($h_cell, $h_rows);
			
			/**
			 * The Rowspan Cell's Height is bigger than the sum of the Rows Heights that he is spanning
			 * In this case we have to increase the height of each row
			 */
			if ($h_cell > $h_rows){
				//calculate the value of the HEIGHT to be added to each row
				$add_on = ($h_cell - $h_rows) / $val['DATA'][$k]['ROWSPAN'];
				for ( $i=0; $i < $val['DATA'][$k]['ROWSPAN']; $i++){
					if (isset($aDataCache[$ix + $i])){
						$aDataCache[$ix + $i]['HEIGHT'] += $add_on;
						$aDataCache[$ix + $i]['DEFAULT_HEIGHT_SET'] = false;
					}
				}//for
			}//
			
		}//foreach
	}//foreach
	
	
	
	
	/**
	 * Calculate the height of each cell that makes the rowspan. 
	 * The height of this cell is the sum of the heights of the rows where the rowspan occurs
	 */
	
	foreach ($aRowSpans as $val1){
		$h_rows = 0;
		//calculate the sum of the Heights for the lines that are included in the rowspan
		for ( $i=0; $i < $val1['cell_id']['ROWSPAN']; $i++){
			if (isset($aDataCache[$val1['row_id'] + $i]))
				$h_rows += $aDataCache[$val1['row_id'] + $i]['HEIGHT'];
		}
		$val1['cell_id']['HEIGHT_MAX'] = $h_rows;
		if (false == $this->bTableSplit){
		    $aDataCache[$val1['row_id']]['HEIGHT_ROWSPAN'] = $h_rows;
		}
	}
	
}//function _tbCacheParseRowspan


/**
 * Splits a cell into 2 cells. The first cell will have maximum $iHeightMax height
 *
 * @access 		protected
 * @param		array - $aCellData - array containing cell data
 * @param 		integer - $iRowHeight - the Height of the row that contains this cell
 * @param		integer - $iHeightMax - the maximum Height of the first cell
 * @return 		$aNewData - the second cell value
 */
protected function tbSplitCell(&$aCellData, $iHeightRow = 0, $iHeightMax = 0){
	
	//$aTData will contain the second cell data
	$aCell2Data = $aCellData;
	$fHeightSplit = 0;		//The Height where the split will be made
	
	/**
	 * Have to look at the V_ALIGN of the cells and calculate exaclty for each cell how much space is left
	 */
	switch($aCellData['V_ALIGN']){
		case 'M':
			//Middle align
			$x = ($iHeightRow - $aCellData['HEIGHT']) / 2;

			if ($iHeightMax  <= $x){
				//CASE 1
				$fHeightSplit = 0;
				$aCellData['V_OFFSET'] = $x - $iHeightMax;
				$aCellData['V_ALIGN'] = 'T';//top align
				
			}elseif( ($x + $aCellData['HEIGHT']) >= $iHeightMax){
				//CASE 2
				$fHeightSplit = $iHeightMax - $x;
				$aCellData['V_ALIGN'] = 'B';//top align
				$aCell2Data['V_ALIGN'] = 'T';//top align
			}else{//{
				//CASE 3
				$fHeightSplit = $iHeightMax;
				$aCellData['V_OFFSET'] = $x;
				$aCellData['V_ALIGN'] = 'B';//bottom align
			}
													
			break;
		case 'B':
			//Bottom Align
			if (($iHeightRow - $aCellData['HEIGHT']) > $iHeightMax){
				//if the text has enough place on the other page then we show nothing on this page
				$fHeightSplit = 0;
			}else{
				//calculate the space that the text needs on this page 
				$fHeightSplit = $iHeightMax - ($iHeightRow - $aCellData['HEIGHT']);
			}
			
			break;
			
		case 'T':
		default:
			//Top Align and default align 
			$fHeightSplit = $iHeightMax;
			break;
	}

	//calculate the number of the lines that have space on the $fHeightSplit
	$iNoLinesCPage = floor($fHeightSplit / $aCellData['LN_SIZE']);
	//if the number of the lines is bigger than the number of the lines in the cell decrease the number of the lines
	if ($iNoLinesCPage > $aCellData['CELL_LINES']){
		$iNoLinesCPage = $aCellData['CELL_LINES'];
	}
										
	$aCellData['TEXT_SPLITLINES'] = array_splice($aCellData['TEXT_STRLINES'], $iNoLinesCPage);
	#$aCellData['CELL_LINES'] = $iNoLinesCPage;
	$aCellData['CELL_LINES'] = count($aCellData['TEXT_STRLINES']);
	
	//calculate the new height for this cell
	$aCellData['HEIGHT'] = $aCellData['LN_SIZE'] * $aCellData['CELL_LINES'];
	
	#$fRowH = max($fRowH, $aData[$j]['HEIGHT'] );
	
	//this is the second cell from the splitted one
	$aCell2Data['TEXT_STRLINES'] = $aCellData['TEXT_SPLITLINES'];
	$aCell2Data['CELL_LINES'] = count ($aCell2Data['TEXT_STRLINES']);
	$aCell2Data['HEIGHT'] = $aCell2Data['LN_SIZE'] * $aCell2Data['CELL_LINES'];
	
	return array($aCell2Data, $fHeightSplit);
				
}//function tbSplitCell()

/**
 * Splits the Data Cache into Pages. 
 * Parses the Data Cache and when it is needed then a "new page" command is inserted into the Data Cache. 
 *
 * @access 	protected
 * @param 	void
 * @return 	void
 */
protected function _tbCachePaginate(){

	$iPageHeight = $this->PageHeight();

	/**
	 * This Variable will contain the remained page Height
	 */
	$iLeftHeight = $iPageHeight - $this->GetY() + $this->tMargin;

	//the number of lines that the header contains
	if ($this->bTableHeaderDraw){
		$iHeaderLines = count($this->aHeaderCache);	
	}else {
		$iHeaderLines = 0;
	}
		
	$bWasData = true;		//can be deleted
	$iLastOkKey = -1;		//can be deleted
	
	$bDataOnThisPage = false;
	$bHeaderOnThisPage = false;
	$iLastDataKey = 0;

	
	//will contain the rowspans on the current page, EMPTY THIS VARIABLE AT EVERY NEW PAGE!!!
	$aRowSpans = array();
	
	$aDC = & $this->aDataCache;
	
	$iItems = count($aDC);
	
	for ($i=0; $i < $iItems; $i++){
		
		$val = & $aDC[$i];
		
		$bIsHeader = $val['DATATYPE'] == 'header';
		
		if (($bIsHeader) && ($bWasData)){
			$iLastDataKey = $iLastOkKey;
		}//fi
		
		if (isset($val['ROWSPAN'])){
			
			foreach ($val['ROWSPAN'] as $k=>$v){
				$aRowSpans[] = array($i, $v);
				$aDC[$i]['DATA'][$v]['HEIGHT_LEFT_RW'] = $iLeftHeight;
			}//foreach
			
		}//fi
		
		$iLeftHeightLast = $iLeftHeight;
		
		$iRowHeight = $val['HEIGHT'];
		$iRowHeightRowspan = 0;
		if ((false == $this->bTableSplit) && (isset($val['HEIGHT_ROWSPAN']))){
		    $iRowHeightRowspan = $val['HEIGHT_ROWSPAN'];
		}
		
        $iLeftHeightRowspan = $iLeftHeight - $iRowHeightRowspan;				
		$iLeftHeight -= $iRowHeight;

		if (($iLeftHeight >= 0) && ($iLeftHeightRowspan >=0)){
			//this row has enough space on the page
			if (true == $bIsHeader) {
				$bHeaderOnThisPage = true;
			}else{
				$iLastDataKey = $i;
				$bDataOnThisPage = true;
			}
			$iLastOkKey = $i;
			$bLastOkType = $bIsHeader;
			
		}else{
							
			/**
			 * THERE IS NOT ENOUGH SPACE ON THIS PAGE - HAVE TO SPLIT
			 * Decide the split type
			 * 
			 * SITUATION 1:
			 * IF
			 * 		- the current data type is header OR
			 * 		- on this page we had no data(that means untill this point was nothing or just header) AND bTableSplit is off
			 * THEN we just add new page on the positions of LAST DATA KEY ($iLastDataKey)
			 * 
			 * SITUATION 2:
			 * IF
			 * 		- TableSplit is OFF and the height of the current data is bigger than the Page Height minus (-) Header Height
			 * THEN we split the current cell
			 * 
			 * SITUATION 3:
			 * 		- normal split flow
			 *  
			 */
			
			//use this switch for flow control
			switch(1){
				case 1:
				
				//SITUATION 1:
				if ((true == $bIsHeader) OR ((false == $bHeaderOnThisPage) AND (false == $bDataOnThisPage) AND (false == $this->bTableSplit)) ){
					$iItems = $this->tbInsertNewPage($iLastDataKey, null, (!$bIsHeader) && (!$bHeaderOnThisPage));
					break;//exit from switch(1);
				}

				$bSplitCommand = $this->bTableSplit;
				
				//SITUATION 2:
				if ($val['HEIGHT'] > ($iPageHeight - $this->iHeaderHeight)){
					//even if the bTableSplit is OFF - split the data!!!
					$bSplitCommand = true;
				}

				if (true == $bSplitCommand){
				/***************************************************
				 * * * * * * * * * * * * * * * * * * * * * * * * * * 
				 * SPLIT IS ACTIVE
				 * * * * * * * * * * * * * * * * * * * * * * * * * * 
				 ***************************************************/
								
					//if we can draw on this page at least one line from the cells
					$bAtLeastOneLine = false;
					
					$aData = $val['DATA'];
					
					$fRowH = $iLeftHeightLast;
					#$fRowH = 0;
					$fRowHTdata = 0;
					
					$aTData = array();
					
					//parse the data's on this line
					for( $j=0; $j < $this->iColumnsNr; $j++){
						
						$aTData[$j] = $aData[$j];
						
						/**
						 * The cell is Skipped or is a Rowspan. For active split we handle rowspanned cells later
						 */
						if (($aData[$j]['SKIP'] === TRUE) || ($aData[$j]['ROWSPAN'] > 1)) continue;
						
						list($aTData[$j]) = $this->tbSplitCell($aData[$j], $val['HEIGHT'], $iLeftHeightLast);
						
						$fRowH = max($fRowH, $aData[$j]['HEIGHT'] );
						$fRowHTdata = max($fRowHTdata, $aTData[$j]['HEIGHT'] );
										
					}//for
					
					$val['HEIGHT'] = $fRowH;
					$val['DATA'] = $aData;				
					
					$v_new = $val;
					$v_new['HEIGHT'] = $fRowHTdata;
					$v_new['ROWSPAN'] = array();
					/**
					 * Parse separately the rows with the ROWSPAN
					 */
					
					
					$bNeedParseCache = false;
					
					$aRowSpan = $aDC[$i]['ROWSPAN'];
					
					
					foreach ($aRowSpans as $rws_key => $rws){
										
						$rData = & $aDC[$rws[0]]['DATA'][$rws[1]];
															
						if ($rData['HEIGHT_MAX'] > $rData['HEIGHT_LEFT_RW']){
							/**
							 * This cell has a rowspan in IT
							 * We have to split this cell only if its height is bigger than the space to the end of page
							 * that was set when the cell was parsed. HEIGHT_LEFT_RW 
							 */
													
							list($aTData[$rws[1]], $fHeightSplit)  = $this->tbSplitCell($rData, $rData['HEIGHT_MAX'] , $rData['HEIGHT_LEFT_RW']);
				
							$rData['HEIGHT_MAX'] = $rData['HEIGHT_LEFT_RW'];
												
							$aTData[$rws[1]]['ROWSPAN'] = $aTData[$rws[1]]['ROWSPAN'] - ($i - $rws[0]);
							
							$v_new['ROWSPAN'][] = $rws[1];
							
							$bNeedParseCache = true;												
						}//fi
					}//foreach
					
					$v_new['DATA'] = $aTData;
					
					//Insert the new page, and get the new number of the lines
					$iItems = $this->tbInsertNewPage($i, $v_new);
					
					if ($bNeedParseCache) $this->_tbCacheParseRowspan($i+1);
					
				}else{
					
				/***************************************************
				 * * * * * * * * * * * * * * * * * * * * * * * * * * 
				 * SPLIT IS INACTIVE
				 * * * * * * * * * * * * * * * * * * * * * * * * * * 
				 ***************************************************/
	
					/**
					 * Check if we have a rowspan that needs to be splitted
					 */
					
					#var_dump($aRowSpans); die();
					$bNeedParseCache = false;
					
					$aRowSpan = $aDC[$i]['ROWSPAN'];
					
					foreach ($aRowSpans as $rws){
										
						$rData = & $aDC[$rws[0]]['DATA'][$rws[1]];
						
						if ($rws[0] == $i)continue;	//means that this was added at the last line, that will not appear on this page
										
						if ($rData['HEIGHT_MAX'] > $rData['HEIGHT_LEFT_RW']){
							/**
							 * This cell has a rowspan in IT
							 * We have to split this cell only if its height is bigger than the space to the end of page
							 * that was set when the cell was parsed. HEIGHT_LEFT_RW 
							 */
							
							list($aTData, $fHeightSplit)  = $this->tbSplitCell($rData, $rData['HEIGHT_MAX'] , $rData['HEIGHT_LEFT_RW'] - $iLeftHeightLast);
				
							$rData['HEIGHT_MAX'] = $rData['HEIGHT_LEFT_RW'] - $iLeftHeightLast;
												
							$aTData['ROWSPAN'] = $aTData['ROWSPAN'] - ($i - $rws[0]);
							
							$aDC[$i]['DATA'][$rws[1]] = $aTData;
							
							$aRowSpan[] = $rws[1];
							$aDC[$i]['ROWSPAN'] = $aRowSpan;
							
							$bNeedParseCache = true;
													
						}//fi
					}//for
					
					if ($bNeedParseCache) $this->_tbCacheParseRowspan($i);
	
					//Insert the new page, and get the new number of the lines
					$iItems = $this->tbInsertNewPage($i);
	
				}//else				
							
				
			}//switch(1);
			
			$iLeftHeight = $iPageHeight;
			$aRowSpans = array();
			$bDataOnThisPage = false;	//new page
			
		}//else
		
		
	}//for
	
}//function _tbCachePaginate



/**
 * Inserts a new page in the Data Cache, after the specified Index. If sent then also a new data is inserted after the new page
 *
 * @access 		protected
 * @param		integer	- $iIndex - after this index is the new page inserted
 * @param		resource - $rNewData - default null. If specified this data is inserted after the new page
 * @param 		boolean	- $bInsertHeader - true then the header is inserted, false - no header is inserted
 * @return 		integer - the new number of lines that the Data Cache Contains. 
 */
protected function tbInsertNewPage($iIndex, $rNewData = null, $bInsertHeader = true){
	
	//the number of lines that the header contains
	if ((true == $this->bTableHeaderDraw) && (true == $bInsertHeader)){
		$iHeaderLines = count($this->aHeaderCache);	
	}else {
		$iHeaderLines = 0;
	}
	
	$aDC = & $this->aDataCache;
	$iItems = count($aDC);		//the number of elements in the cache

	//if we have a NewData to be inserted after the new page then we have to shift the data with 1
	if( null != $rNewData) $iShift = 1;
	else $iShift = 0;
	
	//shift the array with the number of lines that the header contains + one line for the new page
	for($j = $iItems; $j > $iIndex; $j--){
		$aDC[$j + $iHeaderLines + $iShift] = $aDC[$j - 1];
	}//for
		
	$aDC[$iIndex + $iShift] = array(
	    'HEIGHT' => 0, 
	    'DATATYPE' => 'new_page',
	);
	
	$j = $iShift;
	
	
	if ($iHeaderLines > 0){
		//only if we have a header
		
		//insert the header into the corresponding positions
		foreach ($this->aHeaderCache as $rHeaderVal){
			$j++;
			$aDC[$iIndex + $j] = $rHeaderVal;
		}//foreach
		
	}//fi
	
	if( 1 == $iShift ){
		$j++;
		$aDC[$iIndex + $j] = $rNewData;	
	}//fi
	
	/**/
	$this->bDataOnCurrentPage = false;
	
	return count($aDC);
	
}//function tbInsertNewPage



/**
 * Sends all the Data Cache to the PDF Document. 
 * This is the REAL Function that Outputs the table data to the pdf document
 *
 * @access 	protected
 * @param 	void
 * @return 	void
 */
protected function _tbCachePrepOutputData(){
	
	$aDataCache = & $this->aDataCache;
			
	$iItems = count($aDataCache);
	
	for ($k=0; $k < $iItems; $k++){
		
	$val = & $aDataCache[$k];
		
		//each array contains one line
		$this->_tbAlign();
		
		if ($val['DATATYPE'] == 'new_page') {
			//add a new page
			$this->tbAddPage();
			continue;
		}
		
		$data = &$val['DATA'];
				
		//Draw the cells of the row
		for( $i = 0; $i < $this->iColumnsNr; $i++ )
		{
			
			//Save the current position
			$x=$this->GetX();
			$y=$this->GetY();
			
			if ($data[$i]['SKIP'] === FALSE){
				
				if (isset($data[$i]['HEIGHT_MAX'])) 
					$h = $data[$i]['HEIGHT_MAX'];
				else 
					$h = $val['HEIGHT'];
				
			
				//border size BRD_SIZE
				$this->SetLineWidth($data[$i]['BRD_SIZE']);
		
				//fill color = BG_COLOR
				list($r, $g, $b) = $data[$i]['BG_COLOR'];
				$this->SetFillColor($r, $g, $b);
		
				//Draw Color = BRD_COLOR
				list($r, $g, $b) = $data[$i]['BRD_COLOR'];
				$this->SetDrawColor($r, $g, $b);
		
				//Text Color = T_COLOR
				list($r, $g, $b) = $data[$i]['T_COLOR'];
				$this->SetTextColor($r, $g, $b);
		
				//Set the font, font type and size
				$this->SetFont(	$data[$i]['T_FONT'],
								$data[$i]['T_TYPE'],
								$data[$i]['T_SIZE']);
			
				//print the text
				$this->tbMultiCellTbl(
						$data[$i]['CELL_WIDTH'],
						$data[$i]['LN_SIZE'],
						$data[$i]['TEXT_STRLINES'],
						$data[$i]['BRD_TYPE'],
						$data[$i]['T_ALIGN'],
						$data[$i]['V_ALIGN'],
						1,
						$h - $data[$i]['HEIGHT']
						);
			}
	
			//Put the position to the right of the cell
			$this->SetXY($x + $data[$i]['CELL_WIDTH'],$y);
	
			//if we have colspan, just ignore the next cells
			if (isset($data[$i]['COLSPAN'])){
				$i = $i + (int) $data[$i]['COLSPAN'] - 1;
			}
	
		}//for
	
		$this->bDataOnCurrentPage = true;
	
		//Go to the next line
		$this->Ln($val['HEIGHT']);
	}//foreach	
	
}//function _tbCachePrepOutputData


/**
 * Prepares the cache for Output.
 * 
 * Parses the cache for Rowspans, Paginates the cache and then send the data to the pdf document
 * @access 	protected
 * @param 	void
 * @return 	void
 */
protected function _tbCachePrepOutput(){
	
	if ($this->bRowSpanInCache) $this->_tbCacheParseRowspan();
	
	$this->_tbCachePaginate();
	
	$this->_tbCachePrepOutputData();
}



/**
 * Adds a new page in the pdf document and initializes the table and the header if necessary.
 *
 * @access 	protected
 * @param	void	 
 * @return	void
 */
protected function tbAddPage($bHeader = true){
    
	$this->tbDrawBorder();//draw the table border

    $this->_tbEndPageBorder();//if there is a special handling for end page??? this is specific for me
    
    $bUtf8Set = false;

	//IF UTF8 Support is needed then 
	if (isset($this->utf8_support) && ($this->utf8_support)){
		//keep the compatibility with the "old" fpdf utf8 support.
		if (isset($this->utf8_decoded)){
			$old_utf8_decoded = $this->utf8_decoded;
			$this->utf8_decoded = false;
			$bUtf8Set = true;
		}		
	}    
    
    $this->AddPage($this->CurOrientation);//add a new page
    
	//IF UTF8 Support is needed then
	if ($bUtf8Set){
		 $this->utf8_decoded = $old_utf8_decoded;
	}

    $this->bDataOnCurrentPage = false;

    $this->iTableStartX = $this->GetX();
    $this->iTableStartY = $this->GetY();
    $this->tbMarkMarginX();
    
}//function tbAddPage


/**   This method allows printing text with line breaks.
      It works like a modified MultiCell
      Call:
      @param
                        $w - width
                        $h - line height
                        $txtData - the outputed text
                        $border - border(LRTB 0 or 1)
                        $align - horizontal align 'JLR'
                        $valign - Vertical Alignment - Top, Middle, Bottom
                        $fill - fill (1/0)
                        $vh - vertical adjustment - the Multicell Height will be with this VH Higher!!!!
                        $vtop - vertical top add-on
      @return           nothing
*/
/**
 * Ouputs a Table Cell. It works like a modified MultiCell.
 *
 * @param 	integer $w	- cell width
 * @param	integer $h	- line height
 * @param	array	$txtData - variable that contains the data to be outputted. This data is already formatted!!!
 * @param	string 	$border - border(LRTB 0 or 1)
 * @param	string 	$align - horizontal align 'JLR'
 * @param 	string 	$valign - Vertical Alignment - Top, Middle, Bottom
 * @param 	string	$fill - Cell Fill (0 no Fill, 1 fill)
 * @param	integer	$vh	- Vertical Adjustment	- the Multicell Height will be with this VH Higher!!!!
 * @param	integer	$vtop - vertical top add-on
 * @param	integer $pad_left - Cell Pad left - NOT IMPLEMENTED
 * @param 	integer $pad_top - Cell Pad left - NOT IMPLEMENTED
 * @param 	integer $pad_right - Cell Pad left - NOT IMPLEMENTED
 * @param 	integer $pad_bottom - Cell Pad left - NOT IMPLEMENTED
 * @return 	void
 */
function tbMultiCellTbl($w, $h, $txtData, $border=0, $align='J', $valign='T', $fill=0, $vh=0, $vtop=0, $pad_left=0, $pad_top=0, $pad_right=0, $pad_bottom=0){

	$b1 = '';//border for top cell
	$b2 = '';//border for middle cell
	$b3 = '';//border for bottom cell
	$wh_Top = 0;
	
	if ($vtop > 0){//if this parameter is set
		if($vtop < $vh){//only if the top add-on is bigger than the add-width
			$wh_Top = $vtop;
			$vh = $vh - $vtop;
		}
	}
	
	if($border)
	{
		if($border==1)
		{
			$border = 'LTRB';
			$b1 = 'LRT';//without the bottom
			$b2 = 'LR';//without the top and bottom
			$b3 = 'LRB';//without the top
		}
		else
		{
			$b2='';
			if(is_int(strpos($border,'L')))
				$b2.='L';
			if(is_int(strpos($border,'R')))
				$b2.='R';
			$b1=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
			$b3=is_int(strpos($border,'B')) ? $b2.'B' : $b2;

		}
	}
	
	if (empty($txtData)){
		//draw the top borders!!!
		$this->Cell($w,$vh,'',$border,2,$align,$fill);//19.01.2007 - andy
		return;
	}
	
	
	

	switch ($valign){
		case 'T':
			$wh_T = $wh_Top;//Top width
			$wh_B = $vh - $wh_T;//Bottom width
			break;
		case 'M':
			$wh_T = $wh_Top + $vh/2;
			$wh_B = $vh/2;
			break;
		case 'B':
			$wh_T = $wh_Top + $vh;
			$wh_B = 0;
			break;
		default://default is TOP ALIGN
			$wh_T = $wh_Top;//Top width
			$wh_B = $vh - $wh_T;//Bottom width
	}

	//save the X position
	$x = $this->x;
	/*
		if $wh_T == 0 that means that we have no vertical adjustments so I will skip the cells that
		draws the top and bottom borders
	*/

	if ($wh_T > 0)//only when there is a difference
	{
		//draw the top borders!!!
		$this->Cell($w,$wh_T,'',$b1,2,$align,$fill);//19.01.2007 - andy
	}
	
	$b2 = is_int(strpos($border,'T')) && ($wh_T == 0) ? $b2.'T' : $b2;
	$b2 = is_int(strpos($border,'B')) && ($wh_B == 0) ? $b2.'B' : $b2;		
	$this->MultiCellTag($w, $h, $txtData, $b2, $align, 1, $pad_left, $pad_top, $pad_right, $pad_bottom, false);

	if ($wh_B > 0){//only when there is a difference

		//go to the saved X position
		//a multicell always runs to the begin of line
		$this->x = $x;

		$this->Cell($w, $wh_B, '', $b3, 2, $align,$fill);//19.01.2007 - andy

		#$this->x = $this->lMargin;//andy 23.02.2006
		$this->x = $x;
	}

}//function tbMultiCellTbl


/**
 * Sends to the pdf document the cache data
 * 
 * @access 	public
 * @param 	void
 * @return 	void
 */
public function tbOuputData(){
	$this->_tbCachePrepOutput();

	//IF UTF8 Support is needed then 
	if (isset($this->utf8_support) && ($this->utf8_support)){
		//keep the compatibility with the "old" fpdf utf8 support.
		if (isset($this->utf8_decoded)) $this->utf8_decoded = false;		
	}
}//function tbOuputData


}//end of pdf_table class

?>