<?php

/*
 * Bartrack Barcode Generator frontend class
 *
 * @author	Martijn Polak
 * @version	1.00
 * @since	24-03-2004
 * 
 * !! SVP Wijzigingen aan deze class ook doorvoeren in BO module stc_preview.php !!
 */

define('FONT_BOLD', 1);
define('FONT_ITALIC', 2);
define('FONT_UNDERLINE', 4);

require_once 'class.stdModule.php';
require_once 'barcode/transcoder/class.transcode_code128.php';
require_once 'class.svg_v1_0.php';

class barcodeGenerator extends stdModule {

	var $_bct;
	var $_cache_register;

	// Constructor
	function barcodeGenerator() {

		$this->stdModule('abbg0210');
		$this->_bct = new transcode_code128('A');

		//if (!isset($this->_settings->dpi)) $this->_settings->dpi = 97.56;
		if (!isset($this->_settings->dpi)) $this->_settings->dpi = 78;
		$this->_settings->templates->selector = 'selector.tpl';

		$this->_variables->public->ip = base64_encode($_SERVER['REMOTE_ADDR'].':'.mktime());
		$this->_variables->public->secured = true;
		$this->_variables->public->disposition = 'inline';

	}


	// Make sure the referring site is allowed to use the generator
	function _get_site(&$values, $ip, $pag_code = null, $stc_code = null) {

		$rst = $this->_db->Query("
			select
				sit_id as id,
				sit_name as name,
				sit_ip as ip
			from
				tbl_bbg_sites
			".($pag_code ? "
			inner join
				tbl_bbg_pag_connections
			on
				pcn_sit_id = sit_id
			inner join
				tbl_bbg_pages
			on
				pag_id = pcn_pag_id
				and pag_code = '".$pag_code."'
			" : "")."
			".($stc_code ? "
			inner join
				tbl_bbg_stc_connections
			on
				scn_sit_id = sit_id
			inner join
				tbl_bbg_stickers
			on
				stc_id = scn_stc_id 
				and stc_code = '".$stc_code."' 
			" : "")."
			where
				'".$ip."' like sit_ip 
			");

		// or sit_ip = '%.%.%.%' 

		$values = $rst->Row();
		$rst->Close();

	}


	// Get page names and codes allowed for a specific site/referer
	function get_valid_pages(&$values, $ip) {

		$rst = $this->_db->Query("
			select
				pag_name as name,
				pag_code as code,
				pag_width as width,
				pag_height as height 
			from
				tbl_bbg_pages
			inner join
				tbl_bbg_pag_connections
			on
				pag_id = pcn_pag_id
			inner join
				tbl_bbg_sites
			on
				pcn_sit_id = sit_id
			where
				'".$ip."' like sit_ip 
			order by
				pag_name
		");

		while($rst->Row()) {
			$values[$rst->Row('code')] = $rst->Row();
			$rst->MoveNext();
		}
		$rst->Close();

	}


	// Get sticker names and codes allowed for a specific site/referer
	function get_valid_stickers(&$values, $ip) {

		$rst = $this->_db->Query("
			select
				stc_name as name,
				stc_code as code,
				stc_width as width,
				stc_height as height 
			from
				tbl_bbg_stickers
			inner join
				tbl_bbg_stc_connections
			on
				stc_id = scn_stc_id
			inner join
				tbl_bbg_sites
			on
				scn_sit_id = sit_id
			where
				'".$ip."' like sit_ip and 
				stc_version = 100 
			order by
				stc_name
		");

		while($rst->Row()) {
			$values[$rst->Row('code')] = $rst->Row();
			$rst->MoveNext();
		}
		$rst->Close();

	}


	// Convert hex color to rgb elements
	function _hex2rgb($color, $default = '000000') {

		$value['hex'] = str_replace('#', '', ($color ? $color : $default));
		$value['r'] = hexdec(substr($value['hex'], 0, 2));
		$value['g'] = hexdec(substr($value['hex'], 2, 2));
		$value['b'] = hexdec(substr($value['hex'], 4, 2));
		return $value;

	}


	function _units2pixels($amt, $units) {

		switch ($units) {
			case 'cm':
				$inch = ($amt / 2.54);
				break;
			case 'mm':
				$inch = ($amt / 25.4);
				break;
			case 'pt':
				//$inch = ($amt / 72);
				$inch = ($amt / 1.27); // <- ??
				break;
			case 'in':
				$inch = $amt;
				break;
			default:
				return $amt;
		}

		return round($this->_settings->dpi * $inch, 2);

	}


	function _pixels2units($amt, $units) {

		$inch = $amt / $this->_settings->dpi;

		switch ($units) {
			case 'cm':
				$return = ($inch * 2.54);
				break;
			case 'mm':
				$return = ($inch * 25.4);
				break;
			case 'in':
				$return = $inch;
				break;
			case 'pt':
				//$return = ($inch * 72);
				$return = ($inch * 1.27); // <- ??
				break;
			default:
				$return = $amt;
		}

		return round($return, 2);

	}


	function _stripunits(&$amt) {

		$units = trim(preg_replace('/[0-9.%]/','',$amt));
		$amt = trim(preg_replace('/[a-z]/','',$amt));

		return $units;

	}


	function parseunits($value) {

		return $this->_units2pixels($value, $this->_stripunits($value));

	}
	
	function _get_metrics($value) {
		
		return array('value' => $value, 'pixels' => $this->_units2pixels($value, ($tmp_units = $this->_stripunits($value))), 'units' => $tmp_units);
		
	}
	
	// Get page settings
	function _get_page(&$values, $code) {

		$rst = $this->_db->Query("select pag_id as id, pag_name as name, pag_code as code, pag_width as width, pag_height as height, pag_margin_left as margin_left, pag_margin_top as margin_top, pag_margin_right as margin_right, pag_margin_bottom as margin_bottom from tbl_bbg_pages where pag_code = '".$code."'");

		if (!$rst->EOF()) {

			$values = $rst->Row();
			$values['width'] = $this->parseunits($values['width']);
			$values['height'] = $this->parseunits($values['height']);
			$values['margin_left'] = $this->parseunits($values['margin_left']);
			$values['margin_top'] = $this->parseunits($values['margin_top']);
			$values['margin_right'] = $this->parseunits($values['margin_right']);
			$values['margin_bottom'] = $this->parseunits($values['margin_bottom']);

		}

		$rst->Close();

	}


	// Get sticker settings
	function _get_sticker(&$values, $code) {

		$rst = $this->_db->Query("select stc_id as id, stc_name as name, stc_code as code, stc_width as width, stc_height as height, stc_scale as scale, stc_leftspace as leftspace, stc_bottomspace as bottomspace from tbl_bbg_stickers where stc_code = '".$code."'");
		$values = false;

		if (!$rst->EOF()) {

			$values = $rst->Row();

			$zne = $this->_db->Query("select zne_id as id, zne_name as name, zne_code as code, zne_type as type, zne_halign as halign, zne_valign as valign, zne_x as x, zne_y as y, zne_width as width, zne_height as height, zne_respectbounds as respectbounds, zne_data as data, zne_fontfile as fontfile, zne_fontfamily as fontfamily, zne_fontflags as fontflags, zne_fontsize as fontsize, zne_fcolor as fcolor, zne_bcolor as bcolor, zne_opacity as opacity from tbl_bbg_stc_zones where zne_stc_id = ".$rst->Row('id')." order by zne_order desc, zne_name");
			while ($tmp_row = &$zne->Row()) {

				$tmp_row['fontsize'] = $this->parseunits($tmp_row['fontsize']);
				$tmp_row['width'] = $this->parseunits($tmp_row['width']);
				$tmp_row['height'] = $this->parseunits($tmp_row['height']);
				$tmp_row['x'] = $this->parseunits($tmp_row['x']);
				$tmp_row['y'] = $this->parseunits($tmp_row['y']);

				$values['zones'][] = $tmp_row;
				$zne->MoveNext();

			}
			$zne->Close();

			$values['width'] = $this->parseunits($values['width']);
			$values['height'] = $this->parseunits($values['height']);
			$values['width_scaled'] = ($values['width'] * $values['scale']);
			$values['height_scaled'] = ($values['height'] * $values['scale']);
			$values['leftspace'] = $this->parseunits($values['leftspace']);
			$values['bottomspace'] = $this->parseunits($values['bottomspace']);

		}

		$rst->Close();

	}


	// Checks validity of ip address or domain
	function _get_ip() {

		$tmp = explode(':', base64_decode($this->_variables->public->ip));
		//if ($tmp && count($tmp) == 2 && $tmp[1] == 'abtsig') return $tmp[0];
		if ($tmp && count($tmp) == 2 && is_numeric($tmp[1]) && $tmp[1] > mktime(date('H') - 24)) return $tmp[0];

		return false;

	}


	// Encode barcode(s)
	function bc_encode(&$codes) {

		if (!is_string($codes) || substr($codes, 0, 6) != 'base64') $codes = 'base64'.base64_encode(serialize($codes));
		elseif (substr($codes, 0, 6) != 'base64') $codes = 'base64'.base64_encode($codes);

	}
	

	// Decode barcode(s)
	function bc_decode(&$codes) {

		if (is_string($codes) && substr($codes, 0, 6) == 'base64') $codes = unserialize(base64_decode(substr($codes, 6)));

	}

	
	// Get website permitted to use the generator based on ip address
	function _authorize($pag_code = null, $stc_code = null) {

		if (!$this->_variables->public->secured) return true;

		if (($ip = $this->_get_ip())) {

			$this->_get_site($site, $ip, $pag_code, $stc_code);
			if ($site) return true;

			trigger_error('Request refused from '.$ip.' using '.($pag_code ? 'page "'.$pag_code.'" and ' : '').'sticker "'.$stc_code.'"', E_USER_ERROR);
			//$this->_svg_error('Request refused from '.$ip.' using page "'.$pag_code.'" & sticker "'.$stc_code.'"');

		} else {

			trigger_error('Invalid ip address or domain');
			//$this->_svg_error('Invalid ip address or domain');

		}

		return false;

	}


	// Displays the print selector
	function show_selector(&$codes) {

		set_error_handler(array(&$this, '_error_handler'));

		$pages = array();
		$stickers = array();

		if (!($ip = $this->_get_ip()) && $this->_variables->public->secured) {
			trigger_error('Invalid ip address or domain');
			//$this->_svg_error('Invalid ip address or domain');
			return false;
		}

		$this->get_valid_pages($pages, $ip);
		$this->get_valid_stickers($stickers, $ip);

		$this->bc_encode($codes);
		$this->_smrt->assign('codes', $codes);
		
		$this->_smrt->assign('pages', $pages);
		$this->_smrt->assign('stickers', $stickers);
		$this->_smrt->assign('pag_count', count($pages));
		$this->_smrt->assign('stc_count', count($stickers));

		restore_error_handler();

		$this->assignTemplateGlobals();
		$this->_smrt->display($this->_settings->templates->selector);

	}


	// Print a barcode svg image or sheet
	// @param $codes:		array containing barcodes, text values, etc
	// @param $stc_code:	sticker code to use
	// @param @pag_code:	optional page code to use (omit to print just one sticker instead of a sheet)
	// @param @line:		optional line to start printing on when printing a sheet
	// @param @format:		output format
	function make(&$codes, $stc_code, $page = null, $line = 0, $format = null) {

		set_error_handler(array(&$this, '_error_handler'));

		// Init & defaults
		$sticker = false;
		
		// Codes can be submitted as a serialized, base64 encoded string
		//if (is_string($codes) && substr($codes, 0, 6) == 'base64') $codes = unserialize(base64_decode($codes));
		$this->bc_decode($codes);
		
		if (is_string($page)) $page = array('code' => $page);
		elseif (!is_array($page)) $page = array();

		if (!isset($page['code'])) $page['code'] = null;
		else $page['code'] = strtoupper($page['code']);

		$stc_code = strtoupper($stc_code);
		if (!is_numeric($line)) $line = 0;

		// Clear cache register
		$this->_cache_register = array();

		// Get sticker and page
		if ($page['code']) $this->_get_page($page, $page['code']);
		$this->_get_sticker($sticker, $stc_code);

		if (!$sticker) {
			if (!$stc_code) trigger_error('No sticker code supplied');
			else trigger_error('Invalid sticker code: '.$stc_code);
			return false;
		}

		if (!$codes) {
			trigger_error('Nothing to print', E_USER_ERROR);
			return false;
		}
			
		// Authorize ip address
		if (!$this->_authorize($page['code'], $stc_code)) return false;

		// Page code supplied and page found: generate sheet from barcodes
		if ($page['code']) {

			// Create new SVG document object
			$svg = new svg_document($page['width'], $page['height']);

			// Initial coordinates
			$c_x = 0;
			$c_y = ($line * ($sticker['height'] + $sticker['bottomspace']));
			$page_x = $page['margin_left'];
			$page_y = $page['margin_top'];


			// Process codes
			foreach((array)$codes as $code) {

				// A single code can be base64 encoded
				//if (substr($code, 0, 6) == 'base64') $code = base64_decode($code);
				$this->bc_decode($code);

				// Replace html chars, slashes and (PLUS) with a + character since these can't be POSTed
				$code['code'] = htmlentities(stripslashes(str_replace('(PLUS)', '+', $code['code'])));

				// Add SVG symbol to definitions
				$svg->defs[0]->add($this->_svg_symbol($code, $sticker));

				// Each image can be added multiple times
				if (!isset($code['num']) || !is_numeric($code['num'])) $code['num'] = 1;
				for ($lp = 0; $lp < $code['num']; ++$lp) {
	
					// Add SVG use tag
					$tmp_use = new svg_use('stc_'.$sticker['id'].'_'.$code['code'], ($page_x + $c_x), ($page_y + $c_y));
					$tmp_use->set_attribute('width', $sticker['width_scaled']);
					$tmp_use->set_attribute('height', $sticker['height_scaled']);
					//$tmp_use->set_attribute('transform', 'scale('.$sticker['scale'].')');
					$svg->add($tmp_use);
					unset($tmp_use);

					// Increase X position
					$c_x += $sticker['width_scaled'];

					// If next X position is outside of document, reset X position and increase Y position
					if ($page_x + $c_x + $sticker['width_scaled'] >= $page['width'] - $page['margin_right']) {

						$c_x = 0;
						$c_y += ($sticker['height_scaled'] + $sticker['bottomspace']);

					} else {

						// Not at end of row yet; add spacing
						$c_x += $sticker['leftspace'];

					}

					// If Y position is outside of document, start new page
					if ($c_y + $sticker['height_scaled'] >= $page['height'] - $page['margin_bottom']) {

						$page_y += ($page['margin_bottom'] + $page['height']);
						$c_y = 0;

						$svg->set_attribute('height', ($svg->attribute('height') + $page['height']));

					}

				}

			}

		} else {

			if (is_array($codes)) $code = current($codes);
			else $code = $codes;

			// A single code can be base64 encoded
			//if (substr($code, 0, 6) == 'base64') $code = base64_decode($code);
			$this->bc_decode($code['code']);

			// Replace html chars, slashes and (PLUS) with a + character since these can't be POSTed
			$code['code'] = htmlentities(stripslashes(str_replace('(PLUS)', '+', $code['code'])));
			
			$width = (isset($page['width']) ? $this->parseunits($page['width']) : $sticker['width_scaled']);
			$height = (isset($page['height']) ? $this->parseunits($page['height']) : $sticker['height_scaled']);

			$svg = new svg_document($width, $height);
			//$svg->set_attribute('viewBox', '0 0 '.$sticker['width_scaled'].' '.$sticker['height_scaled'].'');
			//$svg->set_attribute('viewBox', '0 0 '.$sticker['width'].' '.$sticker['height'].'');
			$svg->defs[0]->add($this->_svg_symbol($code, $sticker));

			$tmp_use = new svg_use('stc_'.$sticker['id'].'_'.$code['code'], 0, 0);
			$tmp_use->set_attribute('width', $width);
			$tmp_use->set_attribute('height', $height);
			$svg->add($tmp_use);
			unset($tmp_use);

		}

		$this->_svg_out($svg, $format);
		unset($svg);

		restore_error_handler();

	}


	// Generate barcode sheet
	// This is a wrapper function to preserve backward compatibility
	function generate(&$codes, $pag_code, $stc_code, $line = 0, $format = null) {

		$this->make($codes, $stc_code, $pag_code, $line, $format);

	}


	// Create sticker svg symbol
	function &_svg_symbol(&$code, &$sticker) {

		$svg_symbol = new svg_symbol('stc_'.$sticker['id'].'_'.$code['code']);
		$svg_symbol->set_attribute('viewBox', '0 0 '.$sticker['width'].' '.$sticker['height']);
		//$svg_symbol->set_attribute('width', $sticker['width_scaled']);
		//$svg_symbol->set_attribute('height', $sticker['height_scaled']);
		//$svg_symbol->set_attribute('preserveAspectRatio', 'none');
		//$svg_symbol->set_attribute('opacity', .1);
		//$svg_symbol->set_attribute('fill-opacity', .1);
		
		// Create rectangle to act as a background color
		//$svg_object = new svg_rect(0, 0, '100%', '100%');
		//$svg_object->set_attribute('fill', '#EEEEEE');
		//$svg_object->set_attribute('stroke', '#888888');
		//$svg_object->set_attribute('stroke-width', '1px');
		//$svg_symbol->add($svg_object);
		//unset($svg_object);

		// Create image from zones
		foreach((array)$sticker['zones'] as $zone) {

			// Default zone id
			$zone_id = 'zne_'.$sticker['id'].'_'.$zone['code'];
			
			if (isset($this->_cache_register[$zone_id]) && ($zone['type'] == 'blk' || $zone['type'] == 'txt' || $zone['type'] == 'img' || $zone['type'] == 'scp' || $zone['type'] == 'svg')) {
			
				// Object has already been added and isn't dynamic so we'll just add a use tag for it
				$svg_object = new svg_use($this->_cache_register[$zone_id]);

			} else {

				// Add barcode
				if ($zone['type'] == 'bar' || $zone['type'] == 'bcf') {
	
					// Create svg path object
					$svg_object = new svg_path($zone['x'], $zone['y']);
					
					// Set fill color
					$svg_object->set_attribute('fill', ($zone['fcolor'] ? $zone['fcolor'] : '#000000'));
					
					// Create bar sequence from barcode and set path coordinates accordingly
					$svg_object->barcode($this->_bct->create_sequence($code['code']), $zone['width'], $zone['height']);

				// Add rectangle
				} elseif ($zone['type'] == 'blk') {
	
					// Create svg rectangle object
					$svg_object = new svg_rect($zone['x'], $zone['y'], $zone['width'], $zone['height']);
	
					// Set fill color
					$svg_object->set_attribute('fill', ($zone['bcolor'] ? $zone['bcolor'] : 'none'));
	
					// Set stroke parameters
					$svg_object->set_attribute('stroke', ($zone['fcolor'] ? $zone['fcolor'] : 'none'));
					$svg_object->set_attribute('stroke-width', 1);
					$svg_object->set_attribute('stroke-linecap', 'square');
					$svg_object->set_attribute('stroke-linejoin', 'miter');
	
				// Add text
				} elseif ($zone['type'] == 'txt' || $zone['type'] == 'dyn') {
	
					// Set text
					if ($zone['type'] == 'txt') {
	
						// Static text (from db)
						$text = $zone['data'];
	
					} else {
	
						// Dynamic text (from posted data)
						$tmp_code = array_change_key_case($code ,CASE_UPPER);
						$text = (isset($tmp_code[$zone['code']]) ? $tmp_code[$zone['code']] : '');
						unset($tmp_code);

					}

					// Calculate text position within image based on the vertical and horizontal alignment
					switch ($zone['halign']) {
						case 0:	// Left
							$txt_x = $zone['x'];
							$txt_anchor = 'start';
							break;
						case 1: // Center
							$txt_x = $zone['x'] + ($zone['width'] / 2);
							$txt_anchor = 'middle';
							break;
						case 2:	// Right
							$txt_x = ($zone['x'] + $zone['width']);
							$txt_anchor = 'end';
							break;
					}
	
					switch ($zone['valign']) {
						case 0:	// Top
							$txt_y = $zone['y'] + ($zone['fontsize'] / 2);
							$txt_baseline = 'sub';
							break;
						case 1: // Middle
							$txt_y = $zone['y'] + ($zone['height'] / 2) + ($zone['fontsize'] / 2);
							$txt_baseline = 'baseline';
							break;
						case 2:	// Bottom
							$txt_y = ($zone['y'] + $zone['height']) + ($zone['fontsize'] / 2);
							$txt_baseline = 'super';
							break;
					}
	
					// Create svg text object
					$svg_object = new svg_text($text, $zone['fontfamily'], $zone['fontsize'], $txt_x, $txt_y);

					// Set additional font parameters
					$svg_object->set_attribute('fill', $zone['fcolor']);
					$svg_object->set_attribute('font-weight', (($zone['fontflags'] & FONT_BOLD) == FONT_BOLD ? 'bold' : 'normal'));
					$svg_object->set_attribute('font-style', (($zone['fontflags'] & FONT_ITALIC) == FONT_ITALIC ? 'italic' : 'normal'));
					$svg_object->set_attribute('text-decoration', (($zone['fontflags'] & FONT_UNDERLINE) == FONT_UNDERLINE ? 'underline' : 'none'));
					$svg_object->set_attribute('text-anchor', $txt_anchor);
					$svg_object->set_attribute('baseline-shift', $txt_baseline);
	
				} elseif ($zone['type'] == 'img' || $zone['type'] == 'dni') {
	
					// Get dynamic image contents
					if ($zone['type'] == 'dni') {

						$tmp_code = array_change_key_case($code ,CASE_UPPER);
						if (($tmp_img_loc = (isset($tmp_code[$zone['code']]) ? $tmp_code[$zone['code']] : ''))) {
							
							if (strpos($tmp_img_loc, '://') !== false) {

								// Get image from url
								$zone['data'] = file_get_contents($tmp_img_loc);

							} elseif (is_object($this->_tcc)) {
								
								// Get image as URI from content core
								$tmp_uri_data = $this->_tcc->getResourceByURI($tmp_img_loc, 'N', true);
								$zone['data'] = $tmp_uri_data['data'];
								unset($tmp_uri_data);

							}
						}

						unset($tmp_code);
						unset($tmp_url);
						
					}

					$img_width = null;
					$img_height = null;

					// Align 3 = stretch
					if ($zone['data'] && ($zone['halign'] != 3 || $zone['valign'] != 3)) {

						// Get size from image itself for non stretched dimensions
						$tmp_img = imagecreatefromstring($zone['data']);
						if ($zone['halign'] != 3) $img_width = imagesx($tmp_img);
						if ($zone['valign'] != 3) $img_height = imagesy($tmp_img);
						imagedestroy($tmp_img);

					}

					// Fallback to zone width/height
					if (!$img_width) $img_width = $zone['width'];
					if (!$img_height) $img_height = $zone['height'];
					
					// Keep within zone bounds
					if ($zone['respectbounds']) {

						// Width is not stretched and exceeds zone bounds; resize to fit zone
						if ($zone['halign'] != 3 && $img_width > $zone['width']) {

							$x_ratio = $img_height / $img_width;
							$img_width = $zone['width'];

							// If height is not stretched maintain aspect ratio
							if ($zone['valign'] != 3) $img_height = $img_width * $x_ratio;

						}

						// Height is not stretched and exceeds zone bounds; resize to fit zone
						if ($zone['valign'] != 3 && $img_height > $zone['height']) {

							$y_ratio = $img_width / $img_height;
							$img_height = $zone['height'];

							// If width is not stretched maintain aspect ratio
							if ($zone['halign'] != 3) $img_width = $img_height * $y_ratio;

						}

					}

					// Calculate image position within image based on the vertical and horizontal alignment
					// Use plain coordinates for stretched images
					if ($zone['halign'] == 3) {

						$img_x = $zone['x'];

					} else {

						switch ($zone['halign']) {
							case 0:	// Left
								$img_x = $zone['x'];
								break;
							case 1: // Center
								$img_x = $zone['x'] + (($zone['width'] / 2) - ($img_width / 2));
								break;
							case 2:	// Right
								$img_x = (($zone['x'] + $zone['width']) - $img_width);
								break;
							case 3: // Stretch
								$img_x = 0;
								break;
						}

					}
	
					if ($zone['valign'] == 3) {
						
						$img_y = $zone['y'];
						
					} else {

						switch ($zone['valign']) {
							case 0:	// Top
								$img_y = $zone['y'];
								break;
							case 1: // Middle
								$img_y = $zone['y'] + (($zone['height'] / 2) - ($img_height / 2));
								//echo "middle: ".$zone['y']." + (".$zone['height']." / 2) - ($img_height / 2) = $img_y<br>";
								break;
							case 2:	// Bottom
								$img_y = (($zone['y'] + $zone['height'])  - $img_height);
								break;
							case 3: // Stretch
								$img_y = 0;
								break;
						}

					}

					// Create svg image object
					$svg_object = new svg_image($img_x, $img_y, $img_width, $img_height);
					$svg_object->set_data($zone['data']);
					//$svg_object->set_attribute('xlink:href', 'data:;base64,'.base64_encode($zone['data']));
	
				} elseif ($zone['type'] == 'scp') {
					
					$svg_object = new svg_script($zone['data']);
				
				} elseif ($zone['type'] == 'svg') {

					// Enclose the svg tag within another svg tag to fool Illustrator
					$tmp_svg_object = new svg_svg($zone_id, $zone['x'], $zone['y'], $zone['width'], $zone['height']);
					$tmp_svg_object->set_attribute('preserveAspectRatio', 'none');
					$tmp_svg_object->import($zone['data']);
					
					$svg_object = new svg_svg($zone_id.'_aifix');
					$svg_object->add($tmp_svg_object);
					unset($tmp_svg_object);

					/*$svg_object = new svg_svg($zone_id, $zone['x'], $zone['y'], $zone['width'], $zone['height']);
					$svg_object->set_attribute('preserveAspectRatio', 'none');
					$svg_object->import($zone['data']);*/
					
				}

				// Set additional properties and add to cache register
				if (isset($svg_object)) {

					$svg_object->set_attribute('opacity', $zone['opacity']);
					$this->_cache_register[$zone_id] = $svg_object->id;

				}

			}

			// Add object to symbol
			if (isset($svg_object)) $svg_symbol->add($svg_object);
			unset($svg_object);

		}

		return $svg_symbol;

	}


	function _svg_out(&$svg, $format = null) {

		// Defaults
		if (!$format) $format = 'svg';
		$mimetype = 'image/svg+xml';

		// Input / output files
		$tmp_file = $this->_settings->paths->temp.'abbg_'.uniqid('');
		$tmp_file_svg = $tmp_file.'.svg';
		$tmp_file_out = $tmp_file.'.'.$format;

		// Get svg data
		$data = &$svg->generate();

		// Convert SVG file
		if ($format != 'svg') {
			
			if (!isset($this->_settings->converters->$format)) {
				trigger_error('No converter specified for output format '.$format, E_USER_ERROR);
				return false;
			}

			// Write SVG data to temp file
			$fp = fopen($tmp_file_svg, 'w');
			fwrite($fp, $data);
			fclose($fp);
			unset($data);

			// Convert temp file
			$response = shell_exec(preg_replace(array('/\[file_in\]/i','/\[file_out\]/i'), array($tmp_file_svg, $tmp_file_out), $this->_settings->converters->$format));

			if (!file_exists($tmp_file_out)) {
				unlink($tmp_file_svg);
				trigger_error('File '.$tmp_file_svg.' was not converted to '.$format.': '.$response, E_USER_ERROR);
				return false;
			}

			// Get contents of converted file
			$data = &file_get_contents($tmp_file_out);

			// Get mimetype for output format
			$mimetype = mime_content_type($tmp_file_out);

			// Delete temp files
			unlink($tmp_file_svg);
			unlink($tmp_file_out);

		}

		// Due to a bug in IE we can't directly display svg files (resets entire request buffer and hangs on larger or more complex files, FF works like a charm)
		//if (preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT'])) Header("Content-Disposition: attachment; filename=".uniqid('').".svg");
		//else Header("Content-Disposition: inline; filename=".uniqid('').".svg");

		//Header("Pragma: public");
		//Header("Expires: 0");
		Header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		//Header("Accept-Ranges: bytes");
		Header("Content-length: ".strlen($data));
		Header("Content-Disposition: ".$this->_variables->public->disposition."; filename=".uniqid('').'.'.$format);
		Header("Content-type: ".$mimetype);
		//Header("Connection: close");
		echo $data;

	}


	function _error_handler($no, $str, $file, $line) {

		if ($no != E_USER_NOTICE && $no != E_NOTICE) {

			//$msg = "Error: ".$str." in ".$file." on line ".$line;
			$msg = "Error: ".$str;
			error_log('ABBG: '.$str);
			
			$svg = new svg_document(strlen($msg) * 6, 50);
			$svg->add(new svg_text($msg, 'Verdana', 10, 5, 20));
			$this->_svg_out($svg);
			unset($svg);
		
		}
		
	}

}


?>
