<?php
/*
$Id$

  This code is part of LDAP Account Manager (http://www.sourceforge.net/projects/lam)
  Copyright (C) 2003  Michael Drgner

  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


  LDAP Account Manager lamPDF class and some pdf functions
*/

define('FPDF_FONTPATH','font/');
define('LAMPDF_LINEWIDTH',190);
include_once("fpdf.php");
include_once('xml_parser.inc');

$key = false;
$line_width = LAMPDF_LINEWIDTH;

function getAvailablePDFStructures($scope='user') {
	$return = array();
	$dirHandle = opendir($_SESSION['lampath'] . '/config/pdf/' . $scope . '/');
	while($file = readdir($dirHandle)) {
		if(!is_dir($file) && $file != '.' && $file != '..') {
			array_push($return,$file);
		}
	}
	sort($return);
	return $return;
}

function createModulePDF($accounts,$pdf_structure="default.xml") {
	
	global $key;
	
	// Get account type from account container if none was specified or
	// if it is different to the submitted or previous stored
	if($account_type == "" || $account_type != $accounts[0]->get_type()) {
		$account_type = $accounts[0]->get_type();
	}
	
	// Get PDF structure from xml file
	$load = getStructure($account_type,$pdf_structure);
	$structure = $load['structure'];
	
	// The decimal separator must be a dot in order to write pdf-files
	setlocale(LC_NUMERIC, "C");
	
	// Create a new PDF file acording to the account type
	$pdf = new LamPDF($account_type,$load['page_definitions']);
	
	// Loop over each account and add a new page in the PDF file for it 
	foreach($accounts as $account) {
		
		// Start a new page for each account
		$pdf->AddPage();
		
		// Get PDF entries for the current account
		$entries = $account->get_pdfEntries($account_type);
		
		// Now create the PDF file acording to the structure with the submitted values 
		foreach($structure as $entry) {
			// We have a new section to start
			if($entry['tag'] == "SECTION" && $entry['type'] == "open") {
				$name = $entry['attributes']['NAME'];
				if(preg_match("/^\_[a-zA-Z\_]+/",$name)) {
					$section_headline = getSectionHeadline($entries[substr($name,1)][0]);
				}
				else {
					$section_headline = '- ' . _($name);
				}
				$pdf->setFont("arial","B",12);
				$pdf->Write(5,$section_headline . ":");
				$pdf->Ln(6);
			}
			// We have a section to end
			elseif($entry['tag'] == "SECTION" && $entry['type'] == "close") {
				$pdf->Ln(9);
			}
			// We have to include a static text.
			elseif($entry['tag'] == "TEXT") {
				// Load PDF text from structure array
				$info_string = $entry['value'];
				// Get all allowed vairables from account-object
				$values = get_object_vars($account);
				$values = array_keys($values);
				// Replace $varstring in string with variable
				foreach ($values as $value) {
					// replace string
					if (is_string($account->$value)) {
						$info_string = str_replace('$'.$value, $account->$value, $info_string);
					}
					// replace object
					elseif (is_object($account->$value)) {
						$values2 = get_object_vars($account->$value);
						$values2 = array_keys($values2);
						foreach ($values2 as $value2) {
							$info_string = str_replace('$'.$value.'->'.$value2, $account->$value->$value2, $info_string);
							}
						}
					// replace array
					elseif (is_array($account->$value)) {
						foreach ($account->$value as $sub_array2) {
							$sub_array .= $sub_array2.", ";
						}
						$sub_array = substr($sub_array, 0, -2);
						$info_string = str_replace('$'.$value, $sub_array, $info_string);
					}
				}
				// Split string in array
				$info_array = explode("\n", $info_string);
				// Set font for text
				$pdf->setFont("times","",10);
				// Print each entry in array (each line in the text) as new line
				foreach ($info_array as $info) {
					$pdf->Cell(50,5,$info,0,1,"L",0);
				}
				// Print linebreak afterwards
				$pdf->Ln(6);
			}
			// We have to include an entry from the account
			elseif($entry['tag'] == "ENTRY") {
				// Get name of current entry
				$name = $entry['attributes']['NAME'];
				
				// Get current entry
				$value_entry = $entries[$name];
				
				// Print entry only when module sumitted values for it
				if(is_array($value_entry)) {
					// Loop over all rows of this entry (most of the time this will be just one)
					foreach($value_entry as $line) {
						// Substitue XML syntax with valid FPDF methods
						$methods = processLine($line);
						// Call every method
						foreach($methods as $method) {
							call_user_func_array(array(&$pdf,$method[0]),$method[1]);
						}
					}
				}
				$key = false;
			}
		}
	}
	
	// Close PDF
	$pdf->Close();
	// Get relative url path
	$fullpath = realpath('.');
	$subdirs = explode('/', str_replace($_SESSION['lampath'], '', $fullpath));
	for ($i=0; $i<count($subdirs); $i++ ) $filename .= '../';
	// use timestamp and random number from ldap.inc as filename so it should be unique.
	$filename .= 'tmp/' . $_SESSION['ldap']->rand . time() .'.pdf';
	// Save PDF
	$pdf->Output($filename);
	// Output meta refresh to pdf-file
	metaRefresh($filename);
	// Return relative path of pdf-file
	return $filename;
}

function getStructure($scope,$pdf_structure) {
	$parser = new xmlParser();
	$xml = $parser->parse($_SESSION['lampath'] . '/config/pdf/' . $scope . '/' . $pdf_structure);
	
	$border = array();
	$structure = array();
	$complete_page_definitions = array('filename' => 'printLogo.jpg', 'headline' => 'LDAP Account Manager', 'margin-top' => '10.0', 'margin-bottom' => '20.0', 'margin-left' => '10.0', 'margin-right' => '10.0');
	if($xml[0][$xml[1]['PDF'][0]]['attributes']['TYPE'] == $scope) {
		$border['start'] = $xml[1]['PDF'][0];
		$page_definitions = $xml[0][$xml[1]['PDF'][0]]['attributes'];
		foreach($page_definitions as $key => $value) {
			$complete_page_definitions[strtolower($key)] = $value;
			unset($page_definitions[$key]);
		}
		$border['end'] = $xml[1]['PDF'][1];
	}
	$structure = array_slice($xml[0],$border['start'] + 1,$border['end'] - ($border['start'] + 1));
	return array('structure' => $structure, 'page_definitions' => $complete_page_definitions);
}

function getSectionHeadline($line) {
	$headline_pattern = '/<block>.*<value>(.*)<\/value><\/block>/';
	if(preg_match($headline_pattern,$line,$matches)) {
		$valueStyle = processFormatTags($matches[1],'');
		return $valueStyle[1];
	}
	else {
		return '';
	}
}

function processLine($line,$first_td = true) {
	global $key, $line_width;
	
	// PCRE matching <block> tag
	$block_pattern = '/<block><\/block>/';
	// PCRE matching a <key> tag
	$key_pattern = '/(<block>)<key>(.+)<\/key>(.*<\/block>)/';
	// PCRE matching a <value> tag
	// !!FIXME!! value must contain at least one character
	$value_pattern = '/(<block>.*)<value>(.*)<\/value>(<\/block>)/';
	// PCRE matching a <td> tag
	$td_pattern = '/(<block>.*?)<td(.*?)>(.+?)<\/td>(.*<\/block>)/';
	// PCRE matching a <p> tag
	$p_pattern = '/(<block>.*)<p>(.+)<\/p>(.*<\/block>)/';
	// PCRE matching a <br> tag
	$br_pattern = '/<br \/>/';
	
	$return = array();
	if(preg_match($key_pattern,$line,$matches)) {
		$key = true;
		$line_width = $line_width - 50;
		$format = processFormatTags($matches[2],'B');
		$return[] = array('setFont',array('times',$format[0],10));
		$return[] = array('Cell',array(50,5,$format[1] . ':',0,0,'R',0));
		$return[] = array('setFont',array('times','',10));
		return array_merge($return,processLine($matches[1] . $matches[3],false));
	}
	elseif(preg_match($value_pattern,$line,$matches)) {
		$format = processFormatTags($matches[2],'');
		$return[] = array('setFont',array('times',$format[0],10));
		$return[] = array('Cell',array(50,5,$format[1],0,0,'L',0));
		$return[] = array('setFont',array('times','',10));
		return array_merge($return,processLine($matches[1] . $matches[3]));
	}
	elseif(preg_match($p_pattern,$line,$matches)) {
		$format = processFormatTags($matches[2],'');
		$return[] = array('setFont',array('times',$format[0],10));
		$return[] = array('Write',array(5,$format[1]));
		$return[] = array('setFont',array('times','',10));
		return array_merge($return,processLine($matches[1] . $matches[3]));
	}
	elseif(preg_match($td_pattern,$line,$matches)) {
		if($first_td && $key) {
			$first_td = !$first_td;
			$return[] = array('Cell',array(50,5,'',0,0,'L',0));
		}
		$format = processFormatTags($matches[3],'');
		$attrs = processAttributes($matches[2],array('width' => $line_width,'height' => 5,'align' => 'L'));
		$return[] = array('setFont',array('times',$format[0],10));
		$return[] = array('Cell',array($attrs['width'],$attrs['height'],$format[1],0,0,$attrs['align'],0));
		$return[] = array('setFont',array('times','',10));
		return array_merge($return,processLine($matches[1] . $matches[4],$first_td));
	}
	elseif(preg_match($br_pattern,$line,$matches)) {
		return array(array('Ln',array(5)));
	}
	elseif(preg_match($block_pattern,$line,$matches)) {
		$line_width = LAMPDF_LINEWIDTH;
		return array(array('Ln',array(5)));
	}
}

function processFormatTags($line,$style) {
	// PCRE matching a <i> tag
	$i_pattern = '/(.*)<i>(.+)<\/i>(.*)/';
	// PCRE matching a <b> tag
	$b_pattern = '/(.*)<b>(.+)<\/b>(.*)/';
	// PCRE matching a <u> tag
	$u_pattern = '/(.*)<u>(.+)<\/u>(.*)/';
	// Replacement pattern when one of the above pattern matched
	$replace = "\$1\$2\$3";
	
	if(preg_match($i_pattern,$line,$matches)) {
		$style .= "I";
		$line = preg_replace($i_pattern,$replace,$line);
	}
	if(preg_match($b_pattern,$line,$matches)) {
		$style .= "B";
		$line = preg_replace($b_pattern,$replace,$line);
	}
	if(preg_match($u_pattern,$line,$matches)) {
		$style .= "U";
		$line = preg_replace($u_pattern,$replace,$line);
	}
	return array($style,$line);
}

function processAttributes($attrs,$return = array()) {
	global $line_width;
	
	// PCRE matching width attribute
	$width_pattern = '/(.*)width\=\"(\\d+)(\%?)\"(.*)/';
	// PCRE matching height attribute
	$height_pattern = '/(.*)height\=\"(\\d+)\"(.*)/';
	// PCRE matching align attribute
	$align_pattern = '/(.*)align\=\"(L|R|C)\"(.*)/';
	
	// Remove leading and trailing whitespaces
	$attrs = trim($attrs);
	
	if(preg_match($width_pattern,$attrs,$matches)) {
		if($matches[3] == '%') {
			$return['width'] = ceil($line_width * $matches[2] / 100);
		}
		else {
			$return['width'] = ceil($matches[2]);
		}
		return processAttributes($matches[1] . $matches[4],$return);
	}
	elseif(preg_match($height_pattern,$attrs,$matches)) {
		$return['height'] = $matches[2];
		return processAttributes($matches[1] . $matches[3],$return);
	}
	elseif(preg_match($align_pattern,$attrs,$matches)) {
		$return['align'] = $matches[2];
		return processAttributes($matches[1] . $matches[3],$return);
	}
	else {
		return $return;
	}
}


// lamPDF class || For defining own a Header and Footer
class lamPDF extends FPDF {
	
	var $page_definitions;
	
	function lamPDF($account_type = "User",$page_definitions = array()) {
		// Call constructor of superclass
		$this->FPDF('P','mm','A4');
		
		$this->page_definitions = $page_definitions;
		
		echo "<pre>";
		print_r($this->page_definitions);
		echo "</pre>";
		
		// Decide which PDF file type we shall use
		switch($account_type) {
			case "user":
				$subject = _("User information page");
				break;
			case "group":
				$subject = _("Group information page");
				break;
			case "host":
				$subject = _("Samba-Host information page");
				break;
		}
		
		// Open PDF file and write some basic information
		$this->Open();
		$this->setFont("arial","",12);
		$this->setTitle($this->page_definitions['headline']);
		$this->setSubject($subject);
		$this->setAuthor("LDAP Account Manager Devel-Team -Michael Duergner-");
		$this->setCreator("LDAP Account Manager (pdf.inc)");
		//$this->setMargins(10.0,10.0,10.0);
		$this->setMargins($this->page_definitions['margin-left'],$this->page_definitions['margin-top'],$this->page_definitions['margin-right']);
		$this->setAutoPageBreak(true,$this->page_definitions['margin-bottom']);
	}
	
	// Print page header
	function header() {
		if($this->page_definitions['filename'] != 'none') {
			$imageFile = substr(__FILE__,0,strlen(__FILE__)- 11) . "config/pdf/logos/" . $this->page_definitions['filename'];
			$width = $this->page_definitions['logo-width'];
			$height = $this->page_definitions['logo-height'];
			if($this->page_definitions['logo-max'] == true) {
				if(($width / $height) <= 2.5) {
					$factor = 20 / $height;
					$width = $factor * $width;
					$height = 20;
				}
				else {
					$factor = 50 / $width;
					$height = $factor * $height;
					$width = 50;
				}
			}
			$this->Image($imageFile,10,10,$width,$height,"JPG");
		}
		$this->SetFont("arial","B",22);
		$this->Cell(170,5,$this->page_definitions['headline'],0,1,"R",0);
		$this->Ln(3);
		$this->SetFont("times","",14);
		$this->Cell(170,5,"- " . $this->subject . " -",0,0,"R",0);
		$this->SetLineWidth(0.8);
		$this->Line(10,$this->page_definitions['margin-top'] + 30,200,$this->page_definitions['margin-top'] + 30);
		$this->Line(10,$this->page_definitions['margin-top'] + 32,200,$this->page_definitions['margin-top'] + 32);
		$this->SetY(50);
	}

	// Print page footer
	function footer() {
		$this->SetLineWidth(0.8);
		$this->Line(10,280,200,280);
		$this->Line(10,282,200,282);
		$this->SetY(285);
		$this->Cell(0,5,_("This document was automatically created by LDAP Account Manager"),0,0,"C",0);
	}
}