src/ets.php
function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)
	{
		$built = array();
		// array
		if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {
			$lindex = 0;
			$count = count($datatree) - 1; // don't count parent element
			foreach ($datatree as $dk => $dv) {
				if (!is_scalar($dv) && $dk !== '_parent') {
					if (is_object($dv)) {
						// For some reason, PHP 5 is throwing 500's when the parent datatree has an array in the object. Retarded.
						if (version_compare(phpversion(), '5.0.0', '>')){
						$my_datatree = new stdClass;
							foreach($datatree['_parent'] as $k => $v){
								if(is_array($v)){continue;}
								$my_datatree->{$k} = $v;
							}
							$dv->_parent = $my_datatree;
						} else {
							$dv->_parent = &$datatree['_parent'];
						}
					} elseif (is_array($dv)) {
						$dv['_parent'] = &$datatree['_parent'];
					}
					$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);
				}
				++$lindex;
			}
			return implode('', $built);
		}
		// define system variables
		if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {
			$this->add_system_var($datatree, $index, $last, $key);
		}
		// loop through each child element
		foreach ($masktree as $maskinfo => $child) {
			// save array information
			$cindex = $index;
			$clast = $last;
			$ckey = $key;
			// retrieve info from index
			list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);
			// in safe mode, only a subset of elements are available
			if ($safemode) {
				// retrieve datatype and direction and define parent property if necessary
				$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// simple tag element are only used to place scalar values
					case _ETS_TAG:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->protect_spaces($currentdata);
						}
						break;
					// set element
					case _ETS_SET:
						if ($datatype != _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// mis element
					case _ETS_MIS:
						if ($datatype == _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// set val element
					case _ETS_SETVAL:
						if ($datatype == _ETS_SCALAR) {
							if ($currentdata == $maskvalue) {
								$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
							}
						}
						break;
					// mis val element
					case _ETS_MISVAL:
						if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// template element
					case _ETS_TEMPLATE:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						} elseif ($datatype == _ETS_COMPLEX) {
							$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// other element: error
					default:
						$this->error(15, 53, '', 0, $masktype);
						break;
				}
			// normal mode
			} else {
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// php element
					case _ETS_PHP:
						$return = NULL;
						@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');
						if (isset($return)) {
							$built[] = $return;
						}
						break;
					// const element
					case _ETS_CONST:
						$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return])) {
							$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// call element
					case _ETS_CALL:
						$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {
							$argdatatree = $datatree;
							foreach ($child['args'] as $arginfo => $argchild) {
								list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);
								$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
							}
							$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// include element
					case _ETS_PLACE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$included = $this->read_container($return, _ETS_ROOT);
							if ($included === FALSE) {
								$this->error(13, 54, $return);
							} else {
								$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);
							}
						}
						break;
					// insert element
					case _ETS_INSERT:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$inserted = $this->read_container($return, _ETS_TEXT);
							if ($inserted === FALSE) {
								$this->error(12, 55, $return);
							} else {
								$built[] = $inserted;
							}
						}
						break;
					// eval and safe elements or include
					case _ETS_EVAL:
					case _ETS_SAFE:
					case _ETS_INCLUDE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);
							if ($evaluated === FALSE) {
								$this->error(14, 56, $return);
							} else {
								$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);
							}
						}
						break;
					// other types of element
					default:
						// retrieve datatype and direction and define parent property if necessary
						$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);
						switch ($masktype) {
							// simple tag element
							case _ETS_TAG:
								if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_SCALAR) {
									if ($incode) {
										if ($currentdata === TRUE) {
											$built[] = 'TRUE';
										} elseif ($currentdata === FALSE) {
											$built[] = 'FALSE';
										} elseif (is_string($currentdata)) {
											$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';
										} else {
											$built[] = $currentdata;
										}
									} else {
										$built[] = $this->protect_spaces($currentdata);
									}
								} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = 'NULL';
								}
								break;
							// alternate tag element
							case _ETS_ALT_TAG:
								$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(string)(' . $template . ');');
								if (isset($return)) {
									if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_SCALAR) {
										$built[] = $currentdata;
									}
								}
								break;
							// template element
							case _ETS_TEMPLATE:
								if ($datatype == _ETS_SCALAR) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// if element
							case _ETS_IF:
								$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(bool)(' . $test . ');');
								if ($return === TRUE) {
									$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// repeat element
							case _ETS_REPEAT:
								$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(int)(' . $loop . ');');
								for ($i = 0; $i < $return; ++$i) {
									if (is_object($datatree)) {
										$datatree->_count = $i + 1;
									}
									$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose element
							case _ETS_CHOOSE:
								$notfound = TRUE;
								if (isset($child['when'])) {
									foreach ($child['when'] as $grandchild)  {
										$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
										$return = NULL;
										@eval('$return=(bool)(' . $test . ');');
										if ($return === TRUE) {
											$notfound = FALSE;
											$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
											break;
										}
									}
								}
								if ($notfound && isset($child['else'])) {
									$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose variable element
							case _ETS_CHOOSEVAR:
								if ($datatype == _ETS_SCALAR) {
									$notfound = TRUE;
									if (isset($child['when'])) {
										foreach ($child['when'] as $gcmaskinfo => $grandchild)  {
											list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);
											if ($currentdata == $gcmaskvalue) {
												$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
												$notfound = FALSE;
											}
										}
									}
									if ($notfound && isset($child['else'])) {
										$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// set element
							case _ETS_SET:
								if ($datatype != _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis element
							case _ETS_MIS:
								if ($datatype == _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// set val element
							case _ETS_SETVAL:
								if ($datatype == _ETS_SCALAR) {
									if ($currentdata == $maskvalue) {
										$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// mis val element
							case _ETS_MISVAL:
								if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis mask element
							case _ETS_MIS_TEMPLATE:
								if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
						}
						break;
				}
			}
		}
		// done
		return implode('', $built);
	}
function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)
	{
		$built = array();
		// array
		if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {
			$lindex = 0;
			$count = count($datatree) - 1; // don't count parent element
			foreach ($datatree as $dk => $dv) {
				if (!is_scalar($dv) && $dk !== '_parent') {
					if (is_object($dv)) {
						// For some reason, PHP 5 is throwing 500's when the parent datatree has an array in the object. Retarded.
						if (version_compare(phpversion(), '5.0.0', '>')){
						$my_datatree = new stdClass;
							foreach($datatree['_parent'] as $k => $v){
								if(is_array($v)){continue;}
								$my_datatree->{$k} = $v;
							}
							$dv->_parent = $my_datatree;
						} else {
							$dv->_parent = &$datatree['_parent'];
						}
					} elseif (is_array($dv)) {
						$dv['_parent'] = &$datatree['_parent'];
					}
					$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);
				}
				++$lindex;
			}
			return implode('', $built);
		}
		// define system variables
		if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {
			$this->add_system_var($datatree, $index, $last, $key);
		}
		// loop through each child element
		foreach ($masktree as $maskinfo => $child) {
			// save array information
			$cindex = $index;
			$clast = $last;
			$ckey = $key;
			// retrieve info from index
			list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);
			// in safe mode, only a subset of elements are available
			if ($safemode) {
				// retrieve datatype and direction and define parent property if necessary
				$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// simple tag element are only used to place scalar values
					case _ETS_TAG:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->protect_spaces($currentdata);
						}
						break;
					// set element
					case _ETS_SET:
						if ($datatype != _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// mis element
					case _ETS_MIS:
						if ($datatype == _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// set val element
					case _ETS_SETVAL:
						if ($datatype == _ETS_SCALAR) {
							if ($currentdata == $maskvalue) {
								$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
							}
						}
						break;
					// mis val element
					case _ETS_MISVAL:
						if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// template element
					case _ETS_TEMPLATE:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						} elseif ($datatype == _ETS_COMPLEX) {
							$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// other element: error
					default:
						$this->error(15, 53, '', 0, $masktype);
						break;
				}
			// normal mode
			} else {
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// php element
					case _ETS_PHP:
						$return = NULL;
						@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');
						if (isset($return)) {
							$built[] = $return;
						}
						break;
					// const element
					case _ETS_CONST:
						$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return])) {
							$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// call element
					case _ETS_CALL:
						$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {
							$argdatatree = $datatree;
							foreach ($child['args'] as $arginfo => $argchild) {
								list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);
								$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
							}
							$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// include element
					case _ETS_PLACE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$included = $this->read_container($return, _ETS_ROOT);
							if ($included === FALSE) {
								$this->error(13, 54, $return);
							} else {
								$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);
							}
						}
						break;
					// insert element
					case _ETS_INSERT:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$inserted = $this->read_container($return, _ETS_TEXT);
							if ($inserted === FALSE) {
								$this->error(12, 55, $return);
							} else {
								$built[] = $inserted;
							}
						}
						break;
					// eval and safe elements or include
					case _ETS_EVAL:
					case _ETS_SAFE:
					case _ETS_INCLUDE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);
							if ($evaluated === FALSE) {
								$this->error(14, 56, $return);
							} else {
								$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);
							}
						}
						break;
					// other types of element
					default:
						// retrieve datatype and direction and define parent property if necessary
						$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);
						switch ($masktype) {
							// simple tag element
							case _ETS_TAG:
								if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_SCALAR) {
									if ($incode) {
										if ($currentdata === TRUE) {
											$built[] = 'TRUE';
										} elseif ($currentdata === FALSE) {
											$built[] = 'FALSE';
										} elseif (is_string($currentdata)) {
											$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';
										} else {
											$built[] = $currentdata;
										}
									} else {
										$built[] = $this->protect_spaces($currentdata);
									}
								} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = 'NULL';
								}
								break;
							// alternate tag element
							case _ETS_ALT_TAG:
								$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(string)(' . $template . ');');
								if (isset($return)) {
									if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_SCALAR) {
										$built[] = $currentdata;
									}
								}
								break;
							// template element
							case _ETS_TEMPLATE:
								if ($datatype == _ETS_SCALAR) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// if element
							case _ETS_IF:
								$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(bool)(' . $test . ');');
								if ($return === TRUE) {
									$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// repeat element
							case _ETS_REPEAT:
								$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(int)(' . $loop . ');');
								for ($i = 0; $i < $return; ++$i) {
									if (is_object($datatree)) {
										$datatree->_count = $i + 1;
									}
									$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose element
							case _ETS_CHOOSE:
								$notfound = TRUE;
								if (isset($child['when'])) {
									foreach ($child['when'] as $grandchild)  {
										$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
										$return = NULL;
										@eval('$return=(bool)(' . $test . ');');
										if ($return === TRUE) {
											$notfound = FALSE;
											$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
											break;
										}
									}
								}
								if ($notfound && isset($child['else'])) {
									$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose variable element
							case _ETS_CHOOSEVAR:
								if ($datatype == _ETS_SCALAR) {
									$notfound = TRUE;
									if (isset($child['when'])) {
										foreach ($child['when'] as $gcmaskinfo => $grandchild)  {
											list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);
											if ($currentdata == $gcmaskvalue) {
												$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
												$notfound = FALSE;
											}
										}
									}
									if ($notfound && isset($child['else'])) {
										$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// set element
							case _ETS_SET:
								if ($datatype != _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis element
							case _ETS_MIS:
								if ($datatype == _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// set val element
							case _ETS_SETVAL:
								if ($datatype == _ETS_SCALAR) {
									if ($currentdata == $maskvalue) {
										$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// mis val element
							case _ETS_MISVAL:
								if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis mask element
							case _ETS_MIS_TEMPLATE:
								if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
						}
						break;
				}
			}
		}
		// done
		return implode('', $built);
	}
Recursively match the template tree with the data tree