<?php
/**
* @version	$Id: pdf_text.php 12734 2009-10-20 19:28:11Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

defined('FULL_PATH') or die('restricted access!');

class kPDFTextElement extends kPDFElement {

	protected $Data;
	public $Ascent;
	public $Descent;
	public $Gap;

	public $ContentMinWidth;
	public $ContentMaxWidht;

	function __construct($data='', $node, $helper)
	{
		parent::__construct($node, $helper);
		$this->SetData($data, 0);
	}

	function SetData($data)
	{
		$this->Data = $data;
	}

	function Init()
	{
		parent::Init();
		$this->SetCSSProperty('display', 'inline');
	}

	function ComputeCSSProperties()
	{
		parent::ComputeCSSProperties();
		// http://manual.prod.intechnic.lv/css21/text.html#q8

		$whitespace = str_replace('-', '', $this->GetCSSProperty('white-space')); // remove "-" to avoid confusion
		if ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline') {
			$this->Data = preg_replace('/[\n]{1}[\t\\r ]{1}|[\t\\r ]{1}[\n]{1}/', "\n", $this->Data);
		}
		if ($whitespace == 'pre' || $whitespace == 'prewrap') {
			$this->Data = preg_replace('/ /', '&nbsp;', $this->Data);
		}
		if ($whitespace == 'normal' || $whitespace == 'nowrap') {
			$this->Data = preg_replace('/[\r\n]/', ' ', $this->Data);
		}
		if ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline') {
			$this->Data = preg_replace('/\t/', ' ', $this->Data);
			$this->Data = preg_replace('/ [ ]+/', ' ', $this->Data);
		}

		$transform = $this->GetCSSProperty('text-transform');
		if ($transform == 'uppercase') {
			$this->Data = strtoupper($this->Data);
		}
		if ($transform == 'lowercase') {
			$this->Data = strtolower($this->Data);
		}
		if ($transform == 'capitalize') {
			$this->Data = ucwords($this->Data);
		}
	}

	function CheckDimensions()
	{
		$font_size = $this->GetCSSProperty('font-size');
		$this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $font_size, $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
		$this->Ascent = $this->Helper->PDF->GetAscent();
		$this->Descent = -$this->Helper->PDF->GetDescent(); // ((-$font->getDescent() / $units) * $size);
		$this->Gap = $this->Helper->PDF->GetLineGap(); // (($font->getLineGap() / $units) * $size);

		// proportionally fit ascent & descent into font-size. Wiered why they are greater...
		if ($this->Ascent + $this->Descent > $font_size) {
			$this->Ascent = $this->Ascent/($this->Ascent+$this->Descent)*$font_size;
			$this->Descent = $this->Descent/($this->Ascent+$this->Descent)*$font_size;
		}

		if ($this->Helper->DimensionsMode == kPDFHelper::DM_SKIP) {
			return ;
		}

		if  ($this->Node->Name  == 'BR') {
			$this->ContentHeight = $this->Ascent + $this->Descent + $this->Gap;
			$this->SetCSSProperty('height', $this->ContentHeight);
			$this->NextLine('');
			$this->GetLineBox()->Closed();
			return ;
		}

		$whitespace = str_replace('-', '', $this->GetCSSProperty('white-space')); // remove "-" to avoid confusion

		if (!$this->Data) {
			parent::CheckDimensions();
			return;
		}

		$this->Wrap2($whitespace);

		$this->GetLineBox()->Closed();
		parent::CheckDimensions();
	}

	function CalcMinMaxContentWidth()
	{
		$font_size = $this->GetCSSProperty('font-size');
		$this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $font_size, $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
		$data = $this->Data;
		$this->MaxContentWidth = ceil($this->Helper->PDF->GetStringWidth($data));
		$words = preg_split('/([ \[\]\+\(\)]{1})/u', $data, null, PREG_SPLIT_NO_EMPTY);
		$min_w = $this->MaxContentWidth;
		foreach ($words as $word) {
			$word_w = ceil($this->Helper->PDF->GetStringWidth($word));
			if ($word_w < $min_w) {
				$min_w = $word_w;
			}
		}
		$this->MinContentWidth = $min_w;
		parent::CalcMinMaxContentWidth();
	}

	function Wrap2($whitespace) {
		$start = $this->GetLineBox()->CurX;

		$data = $this->Data;

		if ($this->Parent->FirstChild === $this && ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline')) {
			$data = ltrim($data);
		}

		$words = preg_split('/([ \[\]\+\(\)]{1})/u', $data, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
		$words_count = count($words);
		$i = 0;
		$elem_w = 0;
		$max_width = $this->GetLineBox()->GetCSSProperty('width');
		$line_break = false;
		while ($i < $words_count) {
			$word_w = $this->Helper->PDF->GetStringWidth($words[$i]);
			if ( (floor($max_width - $start - $elem_w - $word_w) < 0) && ($i > 0 || $start > 0) ) {
				$line_break = true;
				break;
			}
			$elem_w += $word_w;
			$i++;
		}
		// remove space at the end of line
		// @todo Find a way to detect a space at the end of last line, which is NOT wrapped
		// otherwise right-aligned blocks will have a space at the end of last line
		if ( ($i > 0 && $words[$i-1]) == ' ' && $line_break &&
				($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline')
				) {
			$i--;
			$elem_w -= $this->Helper->PDF->GetStringWidth($words[$i]);
			array_splice($words, $i, 1);
		}
		$this->Data = join( array_splice($words, 0, $i) ); //$i here is the number of last word (starting with 0) + 1, so it's fine for splice
		if (!$this->Data) { // nothing fitted on current line
			$this->Ascent = 0;
			$this->Descent = 0;
			$this->Gap = 0;
			$this->NextLine(join( $words ));
		}
		else {
			$h = $this->Ascent + $this->Descent + $this->Gap;
			$elem = $this;
			if (preg_match_all('/( )/', $this->Data, $regs, PREG_PATTERN_ORDER)) {
				$spacers = count($regs[1]);
			}
			else {
				$spacers = 0;
			}
			do {
				$elem->SetCSSProperty('width', $elem->GetCSSProperty('width') + $elem_w);
				$elem->Spacers = $elem->Spacers + $spacers;
				$elem->ContentHeight = $h;
				$elem->SetCSSProperty('height', $h);
				$elem = $elem->Parent;
			} while ($elem && $elem->GetDisplayLevel() == 'inline');
			$elem->Spacers += $spacers;
			$this->GetLineBox()->CurX = $start + $elem_w;

			if ($i < $words_count) {
				$this->NextLine(join( $words ));
			}
		}
	}

	function GetFollowingSiblings()
	{
		$cur_line = $this->GetLineBox();
		$elem = $this;
		$cur_pos = 0;
		do {
			$cur_pos = $elem->Position;
			$elem = $elem->Parent;
		} while ( $elem && !($elem instanceof kPDFLine) );
		return $cur_line->RemoveChildren($cur_pos+1);
	}

	function CreateNextLine()
	{
		$cur_line = $this->GetLineBox();
		$cur_line->Closed();
		if ($this->Node->Name != 'BR') $cur_line->LastLine = false;
		return $cur_line->Parent->AddChild( new kPDFLine($cur_line->Parent->Node, $this->Helper), true, $cur_line);
	}

	function NextLine($words)
	{
		$removed = $this->GetFollowingSiblings();
		$next_line = $this->CreateNextLine();
		if ($words) {
			$new_elem = $next_line->AddChild( new kPDFTextElement( $words, $this->Node, $this->Helper ));
			$new_elem->Closed();
		}

		foreach ($removed as $elem) {
			$next_line->AddChild( $elem, false ); //don't init
		}
	}

	function DrawAt($page, $x, $y, $spacer_w=0)
	{
		$page->SetLineWidth(0.1);

		$y += $this->Ascent; //finding baseline
		$this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $this->GetCSSProperty('font-size'), $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
		if ($color = $this->GetCSSProperty('color')) {
			$page->SetFillColor($color);
		}

		if (defined('PDF_DEBUG_NO_TEXT')) return ;
		if ($spacer_w == 0) {
			$data = preg_replace('/\xA0/u', ' ', $this->Data);
			 $page->drawText($data, $x, $y);
		}
		else {
			$spacer_w += $page->GetStringWidth(' ');
			$words = explode(' ', $this->Data);
			foreach ($words as $word) {
				$word = preg_replace('/\xA0/u', ' ', $word);
				$page->drawText($word, $x, $y);
				$x += $page->GetStringWidth($word);
				$x += $spacer_w;
			}
		}
		$this->CurX = $x;
	}

}