<?php
/**
 * HTML Report Generator
 *
 * used by the SAX parser to generate HTML reports from the XML report file.
 *
 * phpGedView: Genealogy Viewer
 * Copyright (C) 2002 to 2009  PGV Development Team.  All rights reserved.
 *
 * 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 2 of the License, or
 * (at your option) 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * @package PhpGedView
 * @subpackage Reports
 * @version $Id: class_reporthtml.php 5963 2009-07-21 18:17:14Z canajun2eh $
 */

if (!defined('PGV_PHPGEDVIEW')) {
	header('HTTP/1.0 403 Forbidden');
	exit;
}

define('PGV_CLASS_REPORTHTML_PHP', '');

require_once 'includes/classes/class_reportbase.php';

/**
* Main PGV Report Class for HTML
*
* @package PhpGedView
* @subpackage Reports
*/
class PGVReportBaseHTML extends PGVReportBase {
	/**
	* Default HTML font name
	* @var string
	*/
	public $defaultHtmlFont = 'Arial';
	/**
	* Cell padding
	* @var int
	*/
	public $cPadding = 2;
	/**
	* Cell height ratio
	* @var float
	*/
	public $cellHeightRatio = 1.3;
	/**
	* Line wrap width ratio
	* @var float
	*/
	public $wrapWidthRatio = 1.55;
	/**
	* Current horizontal position
	* @var int
	*/
	public $X = 0;
	/**
	* Current vertical position
	* @var int
	*/
	public $Y = 0;
	/**
	* Currently used style name
	* @var string
	*/
	public $currentStyle = '';
	/**
	* Page number counter
	* @var int
	*/
	public $pageN = 1;
	/**
	* Store the page width without left and right margins
	* In HTML, we don't need this
	* @var int
	*/
	public $noMarginWidth = 0;
	/**
	* Last cell height
	* @var int
	*/
	public $lastCellHeight = 0;
	/**
	* LTR or RTL alignement
	* "left" on LTR, "right" on RTL
	* Used in <div >
	* @var string
	*/
	public $rtlalign = 'left';
	/**
	* Largest Font Height is used by TextBox etc.
	* Use this to calculate a the text height.
	* This makes sure that the text fits into the cell/box when different font sizes are used
	* @var int
	*/
	public $largestFontHeight = 0;
	/**
	* Keep track of the highest Y position
	* Used with Header div / Body div / Footer div / "addpage" / The bottom of the last image etc.
	* @var float
	*/
	public $maxY = 0;

	public $headerElements = array();
	public $pageHeaderElements = array();
	public $footerElements = array();
	public $bodyElements = array();
	public $printedfootnotes = array();


	/**
	* HTML Setup - PGVReportBaseHTML
	*/
	function setup() {
		parent::setup();

		// Setting up the correct dimensions if Portrait (default) or Landscape
		if ($this->orientation == 'landscape') {
			$tmpw = $this->pagew;
			$this->pagew = $this->pageh;
			$this->pageh = $tmpw;
		}
		// Store the pagewidth without margins
		$this->noMarginWidth = floor($this->pagew - $this->leftmargin - $this->rightmargin);
		// If RTL, switch the alignment
		if ($this->rtl) {
			$this->rtlalign = "right";
		}

		if ($this->showGenText) {
			// The default style name for Generated by.... is 'genby'
			$element = new PGVRCellHTML(0, 10, 0, 'C', '', 'genby', 1, '.', '.', 0, 0, '', '', true);
			$element->addText($this->generatedby);
			$element->setUrl(parent::pgv_url);
			$this->footerElements[] = $element;
		}
	}

	function addElement($element) {
		if ($this->processing=="B") return $this->bodyElements[] = $element;
		else if ($this->processing=="H") {
			return $this->headerElements[] = $element;
		}
		else if ($this->processing=="F") {
			return $this->footerElements[] = $element;
		}
	}

	function runPageHeader() {
		foreach($this->pageHeaderElements as $element) {
			if (is_string($element) && $element=="footnotetexts") $this->Footnotes();
			else if (is_string($element) && $element=="addpage") {
				$this->AddPage();
			}
			else if (is_object($element)) {
				$element->render($this);
			}
		}
	}

	function Footnotes() {
		$this->currentStyle = "";
		if(!empty($this->printedfootnotes)) {
			print "<br/>";
			foreach($this->printedfootnotes as $element) {
				$element->renderFootnote($this);
			}
		}
	}

	function run() {
		global $download, $embed_fonts, $rtl_stylesheet, $waitTitle, $stylesheet, $TEXT_DIRECTION, $use_alternate_styles;

		$htmlcode = "
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$this->charset\" />
<meta name=Generator content=\"$this->generatedby\" />
<meta name=\"keywords\" content=\"$this->rkeywords\" />
<meta name=\"description\" content=\"$this->rsubject\" />
<title>$this->title</title>

<link rel=\"stylesheet\" href=\"$stylesheet\" type=\"text/css\" media=\"all\" />
";


		if ((!empty($rtl_stylesheet)) && ($TEXT_DIRECTION=="rtl")) {
			$htmlcode .= "\n<link rel=\"stylesheet\" href=\"$rtl_stylesheet\" type=\"text/css\" media=\"all\" />";
		}

		// Print before continue!
		print $htmlcode;

		// Delay all output until we've seen a page header
/*		ob_start();
		$waitTitle = true;
*/
		// Setting up the styles
		print "\n<style type=\"text/css\">\n";
		$this->PGVRStyles['footer'] = array('name'=>'footer', 'font'=>$this->defaultHtmlFont, 'size'=>'10', 'style'=>'');
		foreach($this->PGVRStyles as $class=>$style) {
			$htmlcode = "";
			$htmlcode .= ".".$class." {\n";
			if ($style['font']=='') $style['font'] = $this->defaultHtmlFont;
			else if ($style['font']=='dejavusans') {
				$style['font'] = $this->defaultHtmlFont;
			}
			$htmlcode .= "font-family: ".$style['font'].";\n";
			$htmlcode .= "font-size: ".($style['size'])."pt;\n";
			// Case-insensitive
			if (stristr($style['style'], 'B')!==false) $htmlcode .= "font-weight: bold;\n";
			if (stristr($style['style'], 'I')!==false) $htmlcode .= "font-style: italic;\n";
			if (stristr($style['style'], 'U')!==false) $htmlcode .= "text-decoration: underline;\n";
			if (stristr($style['style'], 'D')!==false) $htmlcode .= "text-decoration: line-through;\n";
			print $htmlcode."}\n";
		}

		print "</style>\n</head>\n\n<body>";
		unset($htmlcode);

		if (!isset($this->currentStyle)) $this->currentStyle = "";
		$temp = $this->currentStyle;
		//-- header divider
		print "<div id=\"headerdiv\" style=\"position: relative; top: ".($this->headermargin)."pt; width: ".$this->noMarginWidth."pt;\">\n";
		foreach($this->headerElements as $element) {
			if (is_string($element) && $element=="footnotetexts") $this->Footnotes();
			else if (is_string($element) && $element=="addpage") {
				$this->AddPage();
			}
			else $element->render($this);
		}
		print "</div>\n";

		print "<script type=\"text/javascript\">\ndocument.getElementById('headerdiv').style.height='".($this->topmargin)."pt';\n</script>\n";
		//-- body

//		$oldy = $this->Y;
		$this->Y=0;
		$this->maxY=0;
		$this->runPageHeader();
		print "<div id=\"bodydiv\" style=\"position: relative; top: auto; width: ".($this->noMarginWidth)."pt; height: 100%;\">\n";
		$this->currentStyle = "";
		foreach($this->bodyElements as $element) {
			if (is_string($element) && $element=="footnotetexts") $this->Footnotes();
			else if (is_string($element) && $element=="addpage") {
				$this->AddPage();
			}
			else if (is_object($element)) {
				$element->render($this);
			}
		}
		print "</div>\n";
		print "<script type=\"text/javascript\">\ndocument.getElementById('bodydiv').style.height='".($this->maxY)."pt';\n</script>\n";

/*		if (isset($waitTitle) && $waitTitle) {
			// We haven't found a page title: take default action
			$contents = ob_get_clean();
			echo "<title>Unknown title</title>\n";
			echo $contents;
			$waitTitle = false;
			unset ($contents);
		}
*/		//-- footer
//		$oldy = $this->Y;
		$this->Y=0;
		$this->X=0;
		$this->maxY=0;
		print "<div id=\"footerdiv\" style=\"position: relative; top: auto; width: ".$this->noMarginWidth."pt; height: auto;\">\n";
		$this->currentStyle = "footer";
		foreach($this->footerElements as $element) {
			if (is_string($element) && $element=="footnotetexts") $this->Footnotes();
			else if (is_string($element) && $element=="addpage") {
				$this->AddPage();
			}
			else if (is_object($element)) {
				$element->render($this);
			}
		}
		$this->currentStyle = $temp;
		print "</div>\n";

		print "<script type=\"text/javascript\">\ndocument.getElementById('footerdiv').style.height='".($this->maxY+2)."pt';\n</script>\n";
		print "</body>\n</html>\n";
	}

	/**
	* Create a new Cell object - PGVReportBaseHTML
	*
	* @param int $width cell width (expressed in points)
	* @param int $height cell height (expressed in points)
	* @param mixed $border Border style
	* @param string $align Text alignement
	* @param string $bgcolor Background color code
	* @param string $style The name of the text style
	* @param int $ln Indicates where the current position should go after the call
	* @param mixed $top Y-position
	* @param mixed $left X-position
	* @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
	* @param int $stretch Stretch carachter mode
	* @param string $bocolor Border color
	* @param string $tcolor Text color
	* @param boolean $reseth
	* @return object PGVRCellHTML
	*/
	function createCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth) {
		return new PGVRCellHTML($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth);
	}

	function createTextBox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth) {
		return new PGVRTextBoxHTML($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth);
	}

	function createText($style, $color) {
		return new PGVRTextHTML($style, $color);
	}

	function createFootnote($style="") {
		return new PGVRFootnoteHTML($style);
	}

	function createPageHeader() {
		return new PGVRPageHeaderHTML();
	}

	function createImage($file, $x, $y, $w, $h, $align, $ln) {
		return new PGVRImageHTML($file, $x, $y, $w, $h, $align, $ln);
	}

	function createLine($x1, $y1, $x2, $y2) {
		return new PGVRLineHTML($x1, $y1, $x2, $y2);
	}

	function createHTML($tag, $attrs) {
		return new PGVRHtmlHTML($tag, $attrs);
	}

	/**
	* Clear the Header - PGVReportBaseHTML
	*/
	function clearHeader() {
		$this->headerElements = array();
	}


	/****************************
	* Local HTML Report functions
	****************************/


	/**
	* Update the Page Number and set a new Y if max Y is larger - PGVReportBaseHTML
	* @todo add page break - <p style='page-break-before:always' />
	*/
	function AddPage() {
//		print("\n\n<p style=\"page-break-before:always;\" /><p/>\n");
		$this->pageN++;
		// Add a little margin to max Y "between pages"
		$this->maxY += 10;
		// If Y is still heigher by any reason...
		if ($this->maxY < $this->Y) {
			// ... update max Y
			$this->maxY = $this->Y;
		}
		// else update Y so that nothing will be overwritten, like images or cells...
		else $this->Y = $this->maxY;
	}

	/**
	* Uppdate max Y to keep track it incase of a pagebreak - PGVReportBaseHTML
	* @param float $y
	*/
	function addMaxY($y) {
		if ($this->maxY < $y) {
			$this->maxY = $y;
		}
	}

	function addPageHeader($element) {
		$this->pageHeaderElements[] = $element;
		return count($this->headerElements)-1;
	}

	/**
	* Checks the Footnote and numbers them - PGVReportBaseHTML
	* @param object &$footnote
	* @return boolen false if not numbered before | object if already numbered
	*/
	function checkFootnote(&$footnote) {
		$ct = count($this->printedfootnotes);
		$val = $footnote->getValue();
		for($i=0; $i < $ct; $i++) {
			if ($this->printedfootnotes[$i]->getValue() == $val) {
				// If this footnote already exist then set up the numbers for this object
				$footnote->setNum($i + 1);
				$footnote->setAddlink($i + 1);
				return $this->printedfootnotes[$i];
			}
		}
		// If this Footnote has not been set up yet
		$footnote->setNum($ct + 1);
		$footnote->setAddlink($ct + 1);
		$this->printedfootnotes[] = $footnote;
		return false;
	}

	/**
	* Clear the Page Header - PGVReportBaseHTML
	*/
	function clearPageHeader() {
		$this->pageHeaderElements = array();
	}

	/**
	* Count the number of lines - PGVReportBaseHTML
	* @param string &$str
	* @return int Number of lines. 0 if empty line
	*/
	function countLines(&$str) {
		if ($str == "")
			return 0;
		return (substr_count($str, "\n") + 1);
	}

	function getCurrentStyle() {
		return $this->currentStyle;
	}

	function getCurrentStyleHeight() {
		if (empty($this->currentStyle)) {
			return $this->defaultFontSize;
		}
		$style = $this->getStyle($this->currentStyle);
		return $style["size"];
	}

	function getFootnotesHeight() {
		$h=0;
		foreach($this->printedfootnotes as $element) {
			$h+=$element->getFootnoteHeight($this);
		}
		return $h;
	}

	/**
	* Get the maximum width from current position to the margin - PGVReportBaseHTML
	* @return float
	*/
	function getRemainingWidth() {
		return floor($this->noMarginWidth - $this->X);
	}

	function getPageHeight() {
		return $this->pageh - $this->topmargin;
	}

	function getStringWidth($text) {
		$style = $this->getStyle($this->currentStyle);
		return UTF8_strlen($text) * ($style['size']/2);
	}

	function getStyle($s) {
		if (!isset($this->PGVRStyles[$s]) || $s=='') {
			$s = $this->currentStyle;
			if (empty($s)) {
				$s = 'footer';
			}
			$this->PGVRStyles[$s] = $s;
		}
		return $this->PGVRStyles[$s];
	}

	/**
	* Get a text height in points - PGVReportBaseHTML
	* @param &$str
	* @return int
	*/
	function getTextCellHeight(&$str) {
		// Count the number of lines to calculate the height
		$nl = $this->countLines($str);
		// Calculate the cell height
		return ceil(($this->getCurrentStyleHeight() * $this->cellHeightRatio) * $nl);
	}

	/**
	* Get the current X position - PGVReportBaseHTML
	* @return float
	*/
	function GetX() {
		return $this->X;
	}

	/**
	* Get the current Y position - PGVReportBaseHTML
	* @return float
	*/
	function GetY() {
		return $this->Y;
	}

	/**
	* Get the current page number - PGVReportBaseHTML
	* @return int
	*/
	function PageNo() {
		return $this->pageN;
	}

	function setCurrentStyle($s) {
		$this->currentStyle = $s;
	}

	/**
	* Set the X position - PGVReportBaseHTML
	* @param float $x
	*/
	function SetX($x) {
		$this->X = $x;
	}

	/**
	* Set the Y position - PGVReportBaseHTML
	* Also updates Max Y position
	* @param float $y
	*/
	function SetY($y) {
		$this->Y = $y;
		if ($this->maxY < $y) {
			$this->maxY = $y;
		}
	}

	/**
	* Set the X and Y position - PGVReportBaseHTML
	* Also updates Max Y position
	* @param float $x
	* @param float $y
	*/
	function SetXY($x, $y) {
		$this->X = $x;
		// Don't reinvent the wheel, use this instead
		$this->SetY($y);
	}

	/**
	* Wrap text - PGVReportBaseHTML
	* @param string &$str Text to wrap
	* @param int $width Width in points the text has to fit into
	* @return string
	*/
	function textWrap(&$str, $width) {
	// Calculate the line width
	$lw = floor($width / ($this->getCurrentStyleHeight() / 2));
	// Wordwrap each line
	$lines = explode("\n", $str);
	// Line Feed counter
	$lfct = count($lines);
	$wraptext = '';
	foreach($lines as $line) {
		$wtext = '';
		$wtext = UTF8_wordwrap($line, $lw, "\n", true);
		$wraptext .= $wtext;
		// Add a new line as long as it's not the last line
		if ($lfct > 1) $wraptext.= "\n";
		$lfct--;
	}
	unset($lines, $wtext);
	return $wraptext;
	}

	/**
	* Write text - PGVReportBaseHTML
	* @param string $text Text to print
	* @param string $color HTML RGB color code (Ex: #001122)
	*/
	function write($text, $color='') {
//		global $waitTitle;

		$style = $this->getStyle($this->getCurrentStyle());

		// Look for first occurrence of a page header,
		// and use this to complete the HTML <title> tag
/*		if ((isset($waitTitle)) and ($waitTitle) and ($style['name']=='header')) {
			$contents = ob_get_clean();
			echo '<title>', PrintReady(strip_tags($text)), "</title>\n";
			echo $contents;
			$waitTitle = false;		// We're no longer waiting for a page header
			unset ($contents);
		}
*/		$styleAdd = "";
		if (!empty($color)) {
			$styleAdd .= "color: ".$color.";";
		}
		if ($style['font']=='') {
			$style['font'] = $this->defaultHtmlFont;
		}
		print "<span class=\"".$style['name']."\"";
		if (!empty($styleAdd)) {
			print " style=\"".$styleAdd."\"";
		}
		print ">";
		print nl2br(PrintReady($text, false, false));
		print "</span>";
	}

} //-- end PGVReport


/**
* Report Base class of PGVReportBaseHTML
*
* @global class $pgvreport
* @ignore
*/
$pgvreport = new PGVReportBaseHTML();

$PGVReportRoot = $pgvreport;


/**
* Cell element - HTML
*
* @package PhpGedView
* @subpackage Reports
* @todo add info and fix border and filling
*/
class PGVRCellHTML extends PGVRCell {
	/**
	* Create a class CELL for HTML
	* @param int $width cell width (expressed in points)
	* @param int $height cell height (expressed in points)
	* @param mixed $border Border style
	* @param string $align Text alignement
	* @param string $bgcolor Background color code
	* @param string $style The name of the text style
	* @param int $ln Indicates where the current position should go after the call
	* @param mixed $top Y-position
	* @param mixed $left X-position
	* @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
	* @param int $stretch Stretch carachter mode
	* @param string $bocolor Border color
	* @param string $tcolor Text color
	* @param boolean $reseth
	*/
	function PGVRCellHTML($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth) {
		parent::PGVRCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth);
	}

	/**
	* HTML Cell renderer
	* @param PGVReportBaseHTML &$html
	*/
	function render(&$html) {

		if (strstr($this->text, "{{nb}}") !== false) {
			return;
		}

		// Setup the style name
		if ($html->getCurrentStyle() != $this->styleName) {
			$html->setCurrentStyle($this->styleName);
		}
		$temptext = preg_replace("/#PAGENUM#/", $html->PageNo(), $this->text);

		/**
		* Keep the original values, use these local variables
		*/
		$cW = 0;		// Class Width
		$cP = 0;		// Class Padding

		// If (Future-feature-enable/disable cell padding)
		$cP = $html->cPadding;

		// Adjust the positions
		if ($this->left == ".") {
			$this->left = $html->GetX();
		}
		else $html->SetX($this->left);

		if ($this->top == ".") {
			$this->top = $html->GetY();
		}
		else $html->SetY($this->top);

		// Start collecting the HTML code
		$htmlcode = "<div style=\"position:absolute; top:".$this->top."pt; ";
		// Use Cell around padding to support RTL also
		$htmlcode .= "padding:".$cP."pt;";
		// LTR (left) or RTL (right)
		$htmlcode .= $html->rtlalign.":".$this->left."pt; ";
		// Background color
		if (!empty($this->bgcolor)) {
			$htmlcode .= "background-color:".$this->bgcolor."; ";
		}
		// Border setup
		$bpixX = 0;
		$bpixY = 0;
		if (!empty($this->border)) {
			// Border all around
			if ($this->border == 1) {
				$htmlcode .= " border:solid ";
				if (!empty($this->bocolor)) $htmlcode .= $this->bocolor;
				else $htmlcode .= "black";
				$htmlcode .= " 1pt;";
				$bpixX = 1;
				$bpixY = 1;
			}
			else {
				if (stristr($this->border, 'T') !== false) {
					$htmlcode .= " border-top:solid ";
					if (!empty($this->bocolor)) $htmlcode .= $this->bocolor;
					else $htmlcode .= "black";
					$htmlcode .= " 1pt;";
					$bpixY = 1;
				}
				if (stristr($this->border, 'B') !== false) {
					$htmlcode .= " border-bottom:solid ";
					if (!empty($this->bocolor)) $htmlcode .= $this->bocolor;
					else $htmlcode .= "black";
					$htmlcode .= " 1pt;";
					$bpixY = 1;
				}
				if (stristr($this->border, 'R') !== false) {
					$htmlcode .= " border-right:solid ";
					if (!empty($this->bocolor)) $htmlcode .= $this->bocolor;
					else $htmlcode .= "black";
					$htmlcode .= " 1pt;";
					$bpixX = 1;
				}
				if (stristr($this->border, 'L') !== false) {
					$htmlcode .= " border-left:solid ";
					if (!empty($this->bocolor)) $htmlcode .= $this->bocolor;
					else $htmlcode .= "black";
					$htmlcode .= " 1pt;";
					$bpixX = 1;
				}
			}
		}
		// Check the width if set to page wide OR set by xml to larger then page wide
		if (($this->width == 0) or $this->width > $html->getRemainingWidth()) {
			$this->width = $html->getRemainingWidth();
		}
		// We have to calculate a different width for the padding, counting on both side
		$cW = $this->width - ($cP * 2);

		// If there is any text
		if (!empty($temptext)) {
			// Wrap the text
			$temptext = $html->textWrap($temptext, $cW);
			$tmph = $html->getTextCellHeight($temptext);
			// Add some cell padding
			$this->height += $cP;
			if ($tmph > $this->height) {
				$this->height = $tmph;
			}
		}
		// Check the last cell height and ajust with the current cell height
		if ($html->lastCellHeight > $this->height) {
			$this->height = $html->lastCellHeight;
		}

		$htmlcode .= " width:".($cW - $bpixX)."pt; height:".($this->height - $bpixY)."pt;";

		// Text alignment
		switch($this->align) {
			case 'C':
				$htmlcode .= " text-align:center; ";
				break;
			case 'L':
				$htmlcode .= " text-align:left; ";
				break;
			case 'R':
				$htmlcode .= " text-align:right; ";
				break;
		}

		// Print the collected HTML code
		print $htmlcode."\">\n";
		unset($htmlcode);

		// Print URL
		if (!empty($this->url)) {
			print "<a href=\"$this->url\">";
		}
		// Print any text if exists
		if (!empty($temptext)) {
			$html->write($temptext, $this->tcolor);
		}
		if (!empty($this->url)) {
			print "</a>";
		}

		// Finish the cell printing and start to clean up
		print "</div>\n";

		// Where to place the next position
		// -> Next to this cell in the same line
		if ($this->newline == 0) {
			$html->SetXY($this->left + $this->width, $this->top);
			$html->lastCellHeight = $this->height;
		}
		// -> On a new line at the margin - Default
		else if ($this->newline == 1) {
			$html->SetXY(0, $html->GetY() + $this->height + ($cP * 2));
			// Reset the last cell height for the next line
			$html->lastCellHeight = 0;
		}
		// -> On a new line at the end of this cell
		else if ($this->newline == 2) {
			$html->SetXY($html->GetX() + $this->width, $html->GetY() + $this->height + ($cP * 2));
			// Reset the last cell height for the next line
			$html->lastCellHeight = 0;
		}
	}
}

/**
* HTML element - HTML Report
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRHtmlHTML extends PGVRHtml {

	function PGVRHtmlHTML($tag, $attrs) {
		parent::PGVRHtml($tag, $attrs);
	}

	/**
	*  @todo temporary fix
	*/
	function render(&$html, $sub = false, $inat=true) {

		if (!empty($this->attrs['pgvrstyle'])) $html->setCurrentStyle($this->attrs['pgvrstyle']);

		$this->text = $this->getStart().$this->text;
		foreach($this->elements as $element) {
			if (is_string($element) && $element=="footnotetexts") $html->Footnotes();
			else if (is_string($element) && $element=="addpage") {
				$html->AddPage();
			}
			else if ($element->get_type()=='PGVRHtml') {
				$this->text .= $element->render($html, true, false);
			}
			else $element->render($html);
		}
		$this->text .= $this->getEnd();
		if ($sub) return $this->text;

		// If not called by an other attribute
		if ($inat) {
			$startX = $html->GetX();
			$startY = $html->GetY();
			$width = $html->getRemainingWidth();
			print "<div style=\"position: absolute; top: ".$startY."pt; ".$html->rtlalign.": ".$startX."pt; width: ".$width."pt;\">";
			$startY += $html->getCurrentStyleHeight() + 2;
			$html->SetY($startY);
		}

		print $this->text;

		if ($inat) {
			print "</div>\n";
		}
	}
}

/**
* TextBox element - HTML Report
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRTextBoxHTML extends PGVRTextBox {

	function PGVRTextBoxHTML($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth) {
		parent::PGVRTextBox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth);
	}
	function render(&$html) {

		$newelements = array();
		$lastelement = "";
		// Element counter
		$cE = count($this->elements);
		//-- collapse duplicate elements
		for($i=0; $i < $cE; $i++) {
			$element = $this->elements[$i];
			if (is_object($element)) {
				if ($element->get_type() == "PGVRText") {
					if (empty($lastelement)) $lastelement = $element;
					else {
						// Checking if the PGVRText has the same style
						if ($element->getStyleName() == $lastelement->getStyleName()) {
							$lastelement->addText(preg_replace("/\n/", "<br />", $element->getValue()));
						}
						else {
							if (!empty($lastelement)) {
								$newelements[] = $lastelement;
								$lastelement = $element;
							}
						}
					}
				}
				//-- do not keep empty footnotes
				else if (($element->get_type()!="PGVRFootnote") || (trim($element->getValue())!="")) {
					if (!empty($lastelement)) {
						$newelements[] = $lastelement;
						$lastelement = "";
					}
					$newelements[] = $element;
				}
			}
			else {
				if (!empty($lastelement)) {
					$newelements[] = $lastelement;
					$lastelement = "";
				}
				$newelements[] = $element;
			}
		}
		if (!empty($lastelement)) $newelements[] = $lastelement;
		$this->elements = $newelements;
		unset($newelements);

		/**
		* Use these variables to update/manipulate values
		* Repeted classes would reupdate all their class variables again, Header/Page Header/Footer
		* This is the bugfree version
		*/
		$cH = 0;	// Class Height
		$cX = 0;	// Class Left
		// Protect height, width, lastheight from padding
		$cP = 0;	// Class Padding
		$cW = 0;	// Class Width
		// Used with line breaks and cell height calculation within this box only
		$html->largestFontHeight = 0;

		// Current position
		if ($this->left == ".") {
			$cX = $html->GetX();
		}
		else {
			$cX = $this->left;
			$html->SetX($cX);
		}
		// Current position (top)
		if ($this->top == ".") {
			$this->top = $html->GetY();
		}
		else $html->SetY($this->top);

		// Check the width if set to page wide OR set by xml to larger then page wide
		if (($this->width == 0) or ($this->width > $html->getRemainingWidth())) {
			$this->width = $html->getRemainingWidth();
		}
		// Setup the CellPadding
		if ($this->padding) {
			$cP = $html->cPadding;
		}

		// For padding, we have to use less wrap width
		$cW = $this->width - ($cP * 2);

		//-- calculate the text box height
		// Number of lines, will be converted to height
		$cHT = 0;
		// Element height (exept text)
		$eH = 0;
		$h = 0;
		$w = 0;
		//-- $lw is an array
		// 0 => last line width
		// 1 => 1 if text was wrapped, 0 if text did not wrap
		// 2 => number of LF
		$lw = array();
		// Element counter
		$cE = count($this->elements);
		// Buggy.. height is calculated only when there are more then 1 lines exists
		for($i = 0; $i < $cE; $i++) {
			if (is_object($this->elements[$i])) {
				$ew = $this->elements[$i]->setWrapWidth($cW - $w, $cW);
				if ($ew == $cW)
					$w = 0;
				$lw = $this->elements[$i]->getWidth($html);
				// Text is already gets the # LF
				$cHT += $lw[2];
				if ($lw[1] == 1)
					$w = $lw[0];
				else if ($lw[1] == 2) {
					$w = 0;
				}
				else $w += $lw[0];
				if ($w > $cW)
					$w = $lw[0];
				// For anything else but text (images), get the height
				$eH += $this->elements[$i]->getHeight($html);
			}
			else {
				$h += abs($html->getFootnotesHeight());
			}
		}
		// Add up what's the final height
		$cH = $this->height;
		// If any element exist
		if ($cE > 0) {
			// Check if this is text or some other element, like images
			if ($eH == 0) {
				// Number of LF but at least one line
				$cHT = ($cHT + 1) * $html->cellHeightRatio;
				// Calculate the cell hight with the largest font size used
				$cHT = $cHT * $html->largestFontHeight;
				if ($cH < $cHT) {
					$cH = $cHT;
				}
			}
			// This is any other element
			else {
				if ($cH < $eH) {
					$cH = $eH;
				}
			}
		}

		// Just in case, check it anyway
		if ($h > $cH) {
			$cH = $h;
		}
		unset($lw, $cHT, $h, $w);

		// Finaly, check the last cells height
		if ($html->lastCellHeight > $cH) {
			$cH = $html->lastCellHeight;
		}
		// Update max Y incase of a pagebreak
		// We don't want to over write any images or other stuff
		$html->addMaxY($this->top + $cH);

		// Start to print HTML
		$htmlcode = "<div style=\"position: absolute; top: ".$this->top."pt; ";
		// LTR (left) or RTL (right)
		$htmlcode .= $html->rtlalign.":".$cX."pt; ";
		// Background color
		if ($this->fill) {
			if (!empty($this->bgcolor)) {
				$htmlcode .= " background-color: ".$this->bgcolor."; ";
			}
		}
		// Print padding only when it's set
		if ($this->padding) {
			// Use Cell around padding to support RTL also
			$htmlcode .= "padding:".$cP."pt; ";
		}
		// Border setup
		if ($this->border) {
			$htmlcode .= " border: solid black 1pt; ";
		$htmlcode .= "width: ".($this->width - 1 - ($cP * 2))."pt; height: ".($cH - 1)."pt; ";
		}
		else {
			$htmlcode .= "width: ".($this->width - ($cP * 2))."pt; height: ".$cH."pt; ";
		}

		print $htmlcode."\">\n";

		// Do a little "margin" trick before print
		// to get the correct current position => "."
		$cXT = $html->GetX();
		$cYT = $html->GetY();
		$html->SetXY(0, 0);

		// Print the text elements
		foreach($this->elements as $element) {
			if (is_string($element) && $element=="footnotetexts") $html->Footnotes();
			else if (is_string($element) && $element == "addpage") {
				$html->AddPage();
			}
			else $element->render($html, $cX, false);
		}
		print "</div>\n";

		// Reset "margins"
		$html->SetXY($cXT, $cYT);
		// This will be mostly used to trick the multiple images last height
		if ($this->reseth) {
			$cH = 0;
		}
		// New line and some clean up
		if ($this->newline) {
			$html->SetXY(0, $this->top + $cH + ($cP * 2));
			$html->lastCellHeight = 0;
		}
		else {
			$html->SetXY($cX + $this->width, $this->top);
			$html->lastCellHeight = $cH;
		}
	}
}

/**
* Text element - HTML Report
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRTextHTML extends PGVRText {

	function PGVRTextHTML($style, $color) {
		parent::PGVRText($style, $color);
	}

	/**
	* @todo temporary fix
	* @param PGVReportBaseHTML &$html
	* @param int $curx
	* @param boolean $attrib Is is called from a different element?
	*/
	function render(&$html, $curx=0, $attrib=true) {

		// Setup the style name
		if ($html->getCurrentStyle() != $this->styleName) {
			$html->setCurrentStyle($this->styleName);
		}
		$temptext = preg_replace("/#PAGENUM#/", $html->PageNo(), $this->text);
		// If any text at all
		if (!empty($temptext)) {
			// If called by an other element
			if (!$attrib) {
				$html->write($temptext, $this->color);
			}
			else {
				// Save the start positions
				$startX = $html->GetX();
				$startY = $html->GetY();
				$width = $html->getRemainingWidth();
				// If text is wider then page width then wrap it
				if ($html->GetStringWidth($temptext) > $width) {
					$lines = split("\n", $temptext);
					foreach ($lines as $line) {
						print "<div style=\"position:absolute; top:".$startY."pt; ".$html->rtlalign.":".$startX."pt; width:".$width."pt;\">";
						$line = $html->textWrap($line, $width);
						$startY += $html->getTextCellHeight($line);
						$html->SetY($startY);
						$html->write($line, $this->color);
						print "</div>\n";
					}
				}
				else {
					print "<div style=\"position:absolute; top:".$startY."pt; ".$html->rtlalign.":".$startX."pt; width:".$width."pt;\">";
					$html->write($temptext, $this->color);
					print "</div>\n";
					$html->SetX($startX + $html->GetStringWidth($temptext));
					if ($html->countLines($temptext) != 1) {
						$html->SetXY(0, ($startY + $html->getTextCellHeight($temptext)));
					}
				}
			}
		}
	}

	function getHeight(&$html) {
		$ct = substr_count($this->text, "\n");
		if ($ct>0) {
			$ct += 1;
		}
		$style = $html->getStyle($this->styleName);
		return ($style["size"] * $ct) * $html->cellHeightRatio;
	}

	/**
	* Get the width of text and wrap it too
	* @param PGVReportBaseHTML &$html
	* @return array
	*/
	function getWidth(&$html) {
		// Setup the style name
		if ($html->getCurrentStyle() != $this->styleName) {
			$html->setCurrentStyle($this->styleName);
		}

		// Check for the largest font size in the box
		$fsize = $html->getCurrentStyleHeight();
		if ($fsize > $html->largestFontHeight) {
			$html->largestFontHeight = $fsize;
		}

		// Get the line width for the text in points
		$lw = $html->GetStringWidth($this->text);
		// Line Feed counter - Number of lines in the text
		$lfct = $html->countLines($this->text);
		// If there is still remaining wrap width...
		if ($this->wrapWidthRemaining > 0) {
			// Check with line counter too!
			if (($lw >= $this->wrapWidthRemaining) or ($lfct > 1)) {
				$newtext = "";
				$wrapWidthRemaining = $this->wrapWidthRemaining;
				$lines = explode("\n", $this->text);
				// Go throught the text line by line
				foreach($lines as $line) {
					// Line width in points + a little margin
					$lw = $html->GetStringWidth($line);
					// If the line has to be wraped
					if ($lw > $wrapWidthRemaining) {
						$words = explode(' ', $line);
						$lw = 0;
						foreach($words as $word) {
							$lw += $html->GetStringWidth($word." ");
							if ($lw <= $wrapWidthRemaining) {
								$newtext.=$word." ";
							}
							else {
								$lw = $html->GetStringWidth($word." ");
								$newtext .= "\n$word ";
								// Reset the wrap width to the cell width
								$wrapWidthRemaining = $this->wrapWidthCell;
							}
						}
					}
					else $newtext .= $line;
					// Check the Line Feed counter
					if ($lfct > 1) {
						// Add a new line feed as long as it's not the last line
						$newtext.= "\n";
						// Reset the line width
						$lw = 0;
						// Reset the wrap width to the cell width
						$wrapWidthRemaining = $this->wrapWidthCell;
					}
					$lfct--;
				}
				$this->text = $newtext;
				$lfct = substr_count($this->text, "\n");
				return array($lw, 1, $lfct);
			}
		}
		$l = 0;
		$lfct = substr_count($this->text, "\n");
		if ($lfct > 0) {
			$l = 2;
		}
		return array($lw, $l, $lfct);
	}
}

/**
* Footnote element
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRFootnoteHTML extends PGVRFootnote {

	function PGVRFootnoteHTML($style="") {
		parent::PGVRFootnote($style);
	}

	/**
	* HTML Footnotes number renderer
	* @param PGVReportBaseHTML &$html
	*/
	function render(&$html) {
		$html->setCurrentStyle("footnotenum");
		print "<sup><a href=\"#footnote".$this->num."\">";
		$html->write($this->numText);
		print "</a></sup>\n";
	}

	/**
	* Write the Footnote text
	* Uses style name "footnote" by default
	*
	* @param PGVReportBaseHTML &$html
	*/
	function renderFootnote(&$html) {

		if ($html->getCurrentStyle()!=$this->styleName)
			$html->setCurrentStyle($this->styleName);

		$temptext = preg_replace("/#PAGENUM#/", $html->PageNo(), $this->text);

		print "<a name=\"footnote".$this->num."\"><span class=\"footnote\">".$this->num.". ";
		print nl2br(PrintReady($temptext, false, false));
		print "</span></a>\n";

		$html->SetXY(0, $html->GetY() + $this->getFootnoteHeight($html));
	}

	function getFootnoteHeight(&$html) {
		$this->text = $this->text."\n\n";
		$ct = substr_count($this->text, "\n");
//		$ct += 1;
		$style = $html->getStyle($this->styleName);
//		return ($style["size"] * $ct) * $html->cellHeightRatio;
		return ($html->largestFontHeight * $ct) * $html->cellHeightRatio;
	}

	/**
	* Get the width of text
	* @param PGVReportBaseHTML &$html
	* @return array
	*/
	function getWidth(&$html) {
		// Setup the style name
		$html->setCurrentStyle("footnotenum");

		// Check for the largest font size in the box
		$fsize = $html->getCurrentStyleHeight();
		if ($fsize > $html->largestFontHeight) {
			$html->largestFontHeight = $fsize;
		}

		$html->checkFootnote($this);

		// Get the line width for the text in points + a little margin
		$lw = $html->GetStringWidth($this->numText);
		// Line Feed counter - Number of lines in the text
		$lfct = $html->countLines($this->numText);
		// If there is still remaining wrap width...
		if ($this->wrapWidthRemaining > 0) {
			// Check with line counter too!
			if (($lw >= $this->wrapWidthRemaining) or ($lfct > 1)) {
				$newtext = "";
				$wrapWidthRemaining = $this->wrapWidthRemaining;
				$lines = explode("\n", $this->numText);
				// Go throught the text line by line
				foreach($lines as $line) {
					// Line width in points + a little margin
					$lw = $html->GetStringWidth($line);
					// If the line has to be wraped
					if ($lw > $wrapWidthRemaining) {
						$words = explode(' ', $line);
						$lw = 0;
						foreach($words as $word) {
							$lw += $html->GetStringWidth($word." ");
							if ($lw <= $wrapWidthRemaining) {
								$newtext.=$word." ";
							}
							else {
								$lw = $html->GetStringWidth($word." ");
								$newtext .= "\n$word ";
								// Reset the wrap width to the cell width
								$wrapWidthRemaining = $this->wrapWidthCell;
							}
						}
					}
					else $newtext .= $line;
					// Check the Line Feed counter
					if ($lfct > 1) {
						// Add a new line feed as long as it's not the last line
						$newtext.= "\n";
						// Reset the line width
						$lw = 0;
						// Reset the wrap width to the cell width
						$wrapWidthRemaining = $this->wrapWidthCell;
					}
					$lfct--;
				}
				$this->numText = $newtext;
				$lfct = substr_count($this->numText, "\n");
				return array($lw, 1, $lfct);
			}
		}
		$l = 0;
		$lfct = substr_count($this->numText, "\n");
		if ($lfct > 0) {
			$l = 2;
		}
		return array($lw, $l, $lfct);
	}
}

/**
* PageHeader element
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRPageHeaderHTML extends PGVRPageHeader {
	function PGVRPageHeaderHTML() {
		parent::PGVRPageHeader();
	}

	function render(&$html) {
		$html->clearPageHeader();
		foreach($this->elements as $element) {
			$html->addPageHeader($element);
		}
	}
}

/**
* Image element
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRImageHTML extends PGVRImage {

	function PGVRImageHTML($file, $x, $y, $w, $h, $align, $ln) {
		parent::PGVRImage($file, $x, $y, $w, $h, $align, $ln);
	}

	/**
	* Image renderer
	* @param PGVReportBaseHTML &$html
	*/
	function render(&$html) {
		global $lastpicbottom, $lastpicpage, $lastpicleft, $lastpicright;

		// Get the current positions
		if ($this->x == ".") {
			$this->x=$html->GetX();
		}
		if ($this->y == ".") {
			//-- first check for a collision with the last picture
			if (isset($lastpicbottom)) {
				if (($html->PageNo() == $lastpicpage) && ($lastpicbottom >= $html->GetY()) && ($this->x >= $lastpicleft) && ($this->x <= $lastpicright))
					$html->SetY($lastpicbottom + ($html->cPadding * 2));
			}
			$this->y = $html->GetY();
		}

		// Image alignment
		switch($this->align) {
			case 'L':
				print "<div style=\"position:absolute; top:".$this->y."pt; left:0pt; width:".$html->getRemainingWidth()."pt; text-align:left;\">\n";
				print "<img src=\"$this->file\" style=\"width: ".$this->width."pt; height: ".$this->height."pt;\" alt=\"\" />\n</div>\n";
				break;
			case 'C':
				print "<div style=\"position:absolute; top:".$this->y."pt; left:0pt; width:".$html->getRemainingWidth()."pt; text-align:center;\">\n";
				print "<img src=\"$this->file\" style=\"width: ".$this->width."pt; height: ".$this->height."pt;\" alt=\"\" />\n</div>\n";
				break;
			case 'R':
				print "<div style=\"position:absolute; top:".$this->y."pt; left:0pt; width:".$html->getRemainingWidth()."pt; text-align:right;\">\n";
				print "<img src=\"$this->file\" style=\"width: ".$this->width."pt; height: ".$this->height."pt;\" alt=\"\" />\n</div>\n";
				break;
			default:
				print "<img src=\"$this->file\" style=\"position:absolute; ".$html->rtlalign.":".$this->x."pt; top:".$this->y."pt; width:".$this->width."pt; height:".$this->height."pt;\" alt=\"\" />\n";
		}

		$lastpicpage = $html->PageNo();
		$lastpicleft = $this->x;
		$lastpicright = $this->x + $this->width;
		$lastpicbottom = $this->y + $this->height;
		// Setup for the next line
		if ($this->line == 'N') {
			$html->SetY($lastpicbottom);
		}
		// Keep max Y updated
		$html->addMaxY($lastpicbottom);
	}

	/**
	* Get the image height
	* This would be called from the PGVRTextBox only for multiple images
	* so we add a bit bottom space between the images
	* @param PGVReportBaseHTML &$html
	* @return float
	*/
	function getHeight(&$html) {
		return $this->height + ($html->cPadding * 2);
	}

} //-- END PGVRImage

/**
* Line element - HTML Report
*
* @package PhpGedView
* @subpackage Reports
* @todo add info
*/
class PGVRLineHTML extends PGVRLine {
	/**
	* Create a line class -HTML
	* @param mixed $x1
	* @param mixed $y1
	* @param mixed $x2
	* @param mixed $y2
	*/
	function PGVRLineHTML($x1, $y1, $x2, $y2) {
		parent::PGVRLine($x1, $y1, $x2, $y2);
	}

	/**
	* HTML line renderer
	* @param PGVReportBaseHTML &$html
	*/
	function render(&$html) {
		if ($this->x1==".") $this->x1=$html->GetX();
		if ($this->y1==".") $this->y1=$html->GetY();
		if ($this->x2==".") {
			$this->x2 = $html->getRemainingWidth();
		}
		if ($this->y2==".") $this->y2=$html->GetY();
		// TODO Non verticle or horizontal lines can use a series of divs absolutely positioned
		// Vertical line
		if ($this->x1 == $this->x2) {
			print "<div style=\"position:absolute; overflow:hidden; border-left:solid black 1pt; ".$html->rtlalign.":".($this->x1)."pt; top:".($this->y1+1)."pt; width:1pt; height:".($this->y2-$this->y1)."pt;\"> </div>\n";
		}
		// Horizontal line
		if ($this->y1 == $this->y2) {
			print "<div style=\"position:absolute; overflow:hidden; border-top:solid black 1pt; ".$html->rtlalign.":".$this->x1."pt; top:".($this->y1+1)."pt; width:".($this->x2-$this->x1)."pt; height:1pt;\"> </div>\n";
		}
		// Keep max Y updated
		// One or the other will be higher... lasy mans way...
		$html->addMaxY($this->y1);
		$html->addMaxY($this->y2);
	}
} //-- END PGVRLine

?>
