/**
	 * renders one parameter and its children
	 *
	 * @param  SimpleXMLElement  $param           The param to render
	 * @param  string              $control_name    The control name
	 * @param  cbTabs              $tabs            CB tab if applicable
	 * @param  string              $viewType        The view type ( 'view', 'param', 'depends': means: <param> tag => param, <field> tag => view )
	 * @param  string              $htmlFormatting  The HTML formatting ( 'table', 'td', 'span', 'none', 'fieldsListArray' )
	 * @return string HTML
	 */
	function renderOneParamAndChildren( &$param, $control_name='params', $tabs=null, $viewType = 'depends', $htmlFormatting = 'table' ) {
		static $tabpaneCounter			=	0;				// level of tabs (for nested tabs)
		// static $tabpaneNames			=	array();		// names of the tabpanes of level [tabpaneCounter] for the tabpanetabs

		// Check if ACL authorizes to view and to use that element:
		if ( ( ! Access::authorised( $param ) ) && ( ! ( ( $param->getName() == 'if' ) && ( $param->attributes( 'type' ) == 'permission' ) ) ) ) {
			return null;
		}

		$html							=	array();

		$viewMode						=	$param->attributes( 'mode' );
		switch ( $viewMode ) {
			// case 'view':
			case 'show':
				$viewType				=	'view';
				break;
			// case 'param':
			case 'edit':
				$viewType				=	'param';
				break;
			default:
				break;
		}

		// treat any <attributes> below the tag to add attributes to the tag as needed:
		$this->extendParamAttributes( $param, $control_name, ( $viewType == 'view' ) );

		switch ( $param->getName() ) {
			case 'param':
				$result				=	$this->renderParam( $param, $control_name, ( $viewType == 'view' ), $htmlFormatting );
				$dynamic			=	( ( ! ( $viewType == 'view' ) ) && ( $param->attributes( 'onchange' ) == 'evaluate' ) );
				if ( $dynamic && ( $viewType == 'param' ) && ( $htmlFormatting != 'fieldsListArray' ) ) {
					$result[1]		.=	'<noscript><button type="submit" name="cbdoevalpostagain" value="" class="button cbregOnChange">' . CBTxt::Th("Change") . '</button></noscript>';
				}
				if ( $result[1] || ( $viewType != 'view' ) || ( ! in_array( $param->attributes( 'hideblanktext' ), array( 'true', 'always' ) ) ) ) {
					$html[]			=	$this->_renderLine( $param, $result, $control_name, $htmlFormatting, true, ( $viewType == 'view' ) );
					if ( $dynamic ) {
						$ifName		=	$this->_htmlId( $control_name, $param );
						$this->_jsif[$ifName]['element']					=	$param;
						$this->_jsif[$ifName]['control_name']				=	$control_name;
						$this->_jsif[$ifName]['ifname']						=	$ifName;
						$this->_jsif[$ifName]['onchange']					=	$param->attributes( 'onchange' );
					}
				}
				break;

			case 'params':
				$paramsName					=	$param->attributes( 'name' );
				$paramsType					=	$param->attributes( 'type' );

				if ( ( ( $paramsType == 'params' ) && $paramsName ) || ( $paramsType == 'pluginparams' ) ) {
					$repeat					=	( $param->attributes( 'repeat' ) == 'true' );
					$repeatOrdering			=	( $param->attributes( 'repeatordering' ) != 'false' );
					$repeatMax				=	(int) $param->attributes( 'repeatmax' );

					if ( $control_name ) {
						$parent_cname		=	$control_name . '[' . $paramsName . ']';
					} else {
						$parent_cname		=	$paramsName;
					}

					if ( $paramsType == 'params' ) {
						$valueObj			=	$this->_parseParamsColumn( $paramsName, $parent_cname );
					} else {
						$valueObj			=	$this->_pluginParams;
					}

					$this->pushModelOfData( $valueObj );

					if ( $repeat ) {
						$this->_jsrepeat	=	true;

						$valueArray			=	$valueObj->asArray();

						if ( ! $valueArray  ) {
							$valueArray		=	array( 0 => null );
						}

						$result				=	$this->renderParam( $param, $control_name, ( $viewType == 'view' ), $htmlFormatting );
						$return				=	null;

						foreach ( $valueArray as $index => $value ) {
							if ( $control_name ) {
								$child_cnam	=	$control_name . '[' . $paramsName . '][' . $index . ']';
							} else {
								$child_cnam	=	$paramsName . '[' . $index . ']';
							}

							// Grab child params from index:
							if ( $paramsType == 'params' ) {
								$valueObj	=	$this->_parseParamsColumn( $index, $child_cnam );
							} else {
								$valueObj	=	$this->_pluginParams;
							}

							$this->pushModelOfData( $valueObj );

							if ( in_array( $htmlFormatting, array( 'div', 'span', 'none' ) ) ) {
								$return		.=		'<div class="panel panel-default cbRepeatRow">'
											.			'<div class="panel-body">';

								if ( $repeatOrdering ) {
									$return	.=				'<div class="text-center cbRepeatRowSort">'
											.					'<div class="cbRepeatRowMove fa fa-sort fa-block btn btn-default" title="' . htmlspecialchars( CBTxt::T( 'Click and drag to move this row.' ) ) . '"></div>'
											.				'</div>';
								}

								$return		.=				'<div class="cbRepeatRowParams">'
											.					$this->renderAllParams( $param, $child_cnam, $tabs, $viewType, $htmlFormatting )
											.				'</div>'
											.				'<div class="text-right cbRepeatRowIncrement">'
											.					'<div class="cbRepeatRowAddRemove">'
											.						'<div class="cbRepeatRowRemove fa fa-minus btn btn-danger" title="' . htmlspecialchars( CBTxt::T( 'Click to remove this row.' ) ) . '"></div>'
											.						'<div class="cbRepeatRowAdd fa fa-plus btn btn-success" title="' . htmlspecialchars( CBTxt::T( 'Click to add new row.' ) ) . '"></div>'
											.					'</div>'
											.				'</div>'
											.			'</div>'
											.		'</div>';
							} elseif ( in_array( $htmlFormatting, array( 'table', 'td' ) ) ) {
								$return		.=		'<table class="table table-bordered cbRepeatRow">'
											.			'<tbody>'
											.				'<tr>';

								if ( $repeatOrdering ) {
									$return	.=					'<td class="text-center cbRepeatRowSort" style="width: 1%; vertical-align: middle;">'
											.						'<div class="cbRepeatRowMove fa fa-sort btn btn-default" title="' . htmlspecialchars( CBTxt::T( 'Click and drag to move this row.' ) ) . '"></div>'
											.					'</td>';
								}

								$return		.=					'<td class="text-right cbRepeatRowParams">'
											.						'<table class="table table-noborder">'
											.							( $htmlFormatting == 'td' ? '<tr>' : null )
											.							$this->renderAllParams( $param, $child_cnam, $tabs, $viewType, $htmlFormatting )
											.							( $htmlFormatting == 'td' ? '<tr>' : null )
											.						'</table>'
											.					'</td>'
											.					'<td class="text-center cbRepeatRowIncrement" style="width: 10%; vertical-align: middle;">'
											.						'<div class="cbRepeatRowRemove fa fa-minus btn btn-danger" title="' . htmlspecialchars( CBTxt::T( 'Click to remove this row.' ) ) . '"></div>'
											.						'<div class="cbRepeatRowAdd fa fa-plus btn btn-success" title="' . htmlspecialchars( CBTxt::T( 'Click to add new row.' ) ) . '"></div>'
											.					'</td>'
											.				'</tr>'
											.			'</tbody>'
											.		'</table>';
							} else {
								// Nothing; we need some formatting for the repeat usage
							}

							$this->popModelOfData();
						}

						if ( $return ) {
							// Options parsing is pretty slow so lets shut it off by default:
							$repeatIgnore							=	'option';

							// Lets check if this repeat has any of its options being conditioned and if it is we need to allow them to parse (slow!):
							if ( $this->_jsif ) {
								foreach ( $this->_jsif as $ifCondition ) {
									if ( isset( $ifCondition['element']->option ) ) {
										if ( isset( $ifCondition['control_name'] ) && ( strpos( $ifCondition['control_name'], $paramsName ) !== false ) ) {
											$repeatIgnore			=	null;
											break;
										} elseif ( isset( $ifCondition['ifname'] ) && ( strpos( $ifCondition['ifname'], $paramsName ) !== false ) ) {
											$repeatIgnore			=	null;
											break;
										} elseif ( isset( $ifCondition['show'] ) && $ifCondition['show'] ) {
											foreach ( $ifCondition['show'] as $showCondition ) {
												if ( strpos( $showCondition, $paramsName ) !== false ) {
													$repeatIgnore	=	null;
													break;
												}
											}
										} elseif ( isset( $ifCondition['hide'] ) && $ifCondition['hide'] ) {
											foreach ( $ifCondition['hide'] as $hideCondition ) {
												if ( strpos( $hideCondition, $paramsName ) !== false ) {
													$repeatIgnore	=	null;
													break;
												}
											}
										}
									}
								}
							}

							$result[1]		=	'<div class="cbRepeat"' . ( ! $repeatOrdering ? ' data-cbrepeat-sortable="false"' : null ) . ( $repeatIgnore ? ' data-cbrepeat-ignore="' . htmlspecialchars( $repeatIgnore ) . '"' : null ) . ( $repeatMax ? ' data-cbrepeat-max="' . (int) $repeatMax . '"' : null ) . '>'
											.		$return
											.	'</div>';
						}

						$html[]				=	$this->_renderLine( $param, $result, $control_name, $htmlFormatting, true, ( $viewType == 'view' ) );
					} else {
						$html[]				=	$this->renderAllParams( $param, $parent_cname, $tabs, $viewType, $htmlFormatting );
					}

					$this->popModelOfData();
				}
				break;
			case 'field':
				$result				=	$this->renderParam( $param, $control_name, ( $viewType != 'param' ) );

				$task				=	$param->attributes( 'task' );
				$link				=	$param->attributes( 'link' );
				$target				=	$param->attributes( 'target' );
				$title				=	$param->attributes( 'title' );

				if ( $title ) {
					$title			= ' title="' . htmlspecialchars( CBTxt::T( $title ) ) . '"';
				} else {
					$title			= '';
				}

				$class				=	$param->attributes( 'cssclasslink' );

				if ( $class ) {
					$class			= ' class="' . htmlspecialchars( $class ) . '"';
				} else {
					$class			= '';
				}

				if ( $htmlFormatting != 'fieldsListArray' ) {
					if ( $link || $task ) {
						if ( $link ) {
							if ( $target == 'popup' ) {
								$linkhref = $this->_controllerView->drawUrl( $link, $param, $this->_modelOfData[0], $this->_modelOfData[0]->get( 'id' ), true, false );		//TODO NOT URGENT: hardcoded id column name 'id'
								$onclickJS	=	'window.open(\'' . htmlspecialchars( cbUnHtmlspecialchars( $linkhref ) )
									.	'\', \'cbtablebrowserpopup\', \'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no\'); return false;';
								$rowAttributes	=	' onclick="' . $onclickJS . '"';
							} else {
								$linkhref = $this->_controllerView->drawUrl( $link, $param, $this->_modelOfData[0], $this->_modelOfData[0]->get( 'id' ), true );		//TODO NOT URGENT: hardcoded id column name 'id'
								$rowAttributes	=	( $target ? ' target="' . htmlspecialchars( $target ) . '"' : '' );
							}
						} elseif ( $task ) {
							$linkhref	=	'#';
							$onclickJS	=	"submitbutton( '" . addslashes( $task ) . "' );";
							$rowAttributes	=	' onclick="' . $onclickJS . '"';
						} else {
							$linkhref	=	null;
							$rowAttributes	=	'';
						}

						if ( $linkhref ) {
							$result[1]	= '<a href="' . $linkhref .'"' . $title . $class . $rowAttributes . '>' . ( trim( $result[1] ) ? $result[1] : '---' ) . '</a>';
						} else {
							$result[1]	= '<span' . $title . $class . '>' . ( trim( $result[1] ) ? $result[1] : '---' ) . '</span>';
						}
					} elseif ( $title ) {
						$result[1]		= '<span' . $title . $class . '>' . $result[1] . '</span>';
					}
				}
				$html[]	= $this->_renderLine( $param, $result, $control_name, $htmlFormatting, false, ( $viewType == 'view' ) );
				break;

			case 'fieldset':
				$htid				=	$this->_outputIdEqualHtmlId( $control_name, $param );

				$legend				=	$param->attributes( 'label' );
				$description		=	$param->attributes( 'description' );
				$name				=	$param->attributes( 'name' );
				$class				=	RegistryEditView::buildClasses( $param );

				$fieldsethtml		=	'<fieldset' . ( $class ? ' class="' . htmlspecialchars( $class ) . '"' : ( $name ? ( ' class="cbFieldset cbfieldset_' . $name . '"' ) : '' ) ) . '>';
				if ( $htmlFormatting == 'table' ) {
					$html[] 		=	'<tr' . $htid . '><td colspan="3" width="100%">' . $fieldsethtml;
				} elseif ( $htmlFormatting == 'td' ) {
					$html[]			=	"\t\t\t<td" . $htid . ">" . $fieldsethtml;
				} elseif ( $htmlFormatting == 'span' ) {
					$html[]			=	'<div' . $htid . '>' . $fieldsethtml;
				} elseif ( $htmlFormatting == 'fieldsListArray' ) {
					// nothing
				} else {
					$html[]			=	'<fieldset' . $htid . ( $class ? ' class="' . htmlspecialchars( $class ) . '"' : ( $name ? ( ' class="cbFieldset cbfieldset_' . $name . '"' ) : '' ) ) . '>';
				}
				if ( $legend && ( $htmlFormatting != 'fieldsListArray' ) ) {
					$html[]			=	'<legend' . ( $class ? ' class="' . htmlspecialchars( $class ) . '"' : '' ) . '>' . CBTxt::Th( $legend ) . '</legend>';
				}
				if ( $htmlFormatting == 'table' ) {
					$html[]			=	'<table class="table table-noborder">';
					if ( $description ) {
						$html[]		=	'<tr><td colspan="3" width="100%"><strong>' . CBTxt::Th( $description ) . '</strong></td></tr>';
					}
				} elseif ( $htmlFormatting == 'td' ) {
					if ( $description ) {
						$html[] 	=	'<td colspan="3" width="100%"><strong>' . CBTxt::Th( $description ) . '</strong></td>';
					}
				} elseif ( $htmlFormatting == 'span' ) {
					if ( $description ) {
						$html[]		=	'<span class="cbLabelSpan">' . CBTxt::Th( $description ) . '</span> ';
					}
					$html[]			=	'<span class="cbFieldSpan">';
				} elseif ( $htmlFormatting == 'fieldsListArray' ) {
					// nothing
				} else {
					if ( $description ) {
						$html[] 	=	'<strong>' . CBTxt::Th( $description ) . '</strong>';
					}
				}
				$html[]				=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				if ( $htmlFormatting == 'table' ) {
					$html[]			=	"\n\t</table>";
					$html[]			=	'</fieldset></td></tr>';
				} elseif ( $htmlFormatting == 'td' ) {
					$html[]			=	'</fieldset></td>';
				} elseif ( $htmlFormatting == 'span' ) {
					$html[]			=	'</span></fieldset></div>';
				} elseif ( $htmlFormatting == 'fieldsListArray' ) {
					// nothing
				} else {
					$html[]			=	'</fieldset>';
				}
				break;

			case 'fields':
			case 'status':
				$html[]				=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );
				break;

			case 'if':
				$ifType								=	$param->attributes( 'type' );
				if ( ( $ifType == 'showhide' ) && ( ! ( $viewType == 'view' ) ) ) {
					$ifName							=	$this->_htmlId( $control_name, $param ) . $param->attributes( 'operator' ) . $param->attributes( 'value' ). $param->attributes( 'valuetype' );
					// $this->_jsif[$ifName]		=	array();
					// $this->_jsif[$ifName]['show']=	array();
					// $this->_jsif[$ifName]['set']	=	array();
					if ( count( $param->children() ) > 0 ) {
						foreach ( $param->children() as $subParam ) {
							/** @var  SimpleXMLElement  $subParam */
							$repeat											=	( ( $subParam->getName() == 'params' ) && ( $subParam->attributes( 'repeat' ) == 'true' ) );

							if ( in_array( $subParam->getName(), array( 'showview', 'params', 'fields', 'status', 'if' ) ) && ( ! $repeat ) ) {
								if ( $subParam->getName() == 'showview' ) {
									$viewName								=	$subParam->attributes( 'view' );
									$viewModel								=	$this->_views->getChildByNameAttributes( 'view', array( 'ui' => 'admin', 'name' => $viewName ) );

									if ( ! $viewModel ) {
										echo 'Extended renderAllParams:showview: View ' . $viewName . ' not defined in XML';
										return false;
									}

									$children								=	$viewModel->children();
								} else {
									$children								=	$subParam->children();
								}

								if ( count( $children ) > 0 ) {
									if ( $subParam->getName() == 'params' ) {
										$paramsName							=	$subParam->attributes( 'name' );
										if ( $control_name ) {
											$child_cnam						=	$control_name . '[' . $paramsName . ']';
										} else {
											$child_cnam						=	$paramsName;
										}
									} else {
										$child_cnam							=	$control_name;
									}

									foreach ( $children as $vChild ) {
										/** @var  SimpleXMLElement  $vChild */
										if ( ! in_array( $vChild->getName(), array( 'showview', 'if', 'else' ) ) ) {													//TBD	//FIXME: this avoids JS error but still shows sub-view ! recursive function needed here
											$this->_jsif[$ifName]['show'][]		=	$this->_htmlId( $child_cnam, $vChild );
										} elseif ( $vChild->getName() == 'if' ) {
											foreach ( $vChild->children() as $vvChild ) {
												/** @var  SimpleXMLElement  $vvChild */
												if ( ! in_array( $vvChild->getName(), array( 'showview', 'if', 'else', 'params', 'fields', 'status' ) ) ) {													//TBD	//FIXME: this avoids JS error but still shows sub-view ! recursive function needed here
													$this->_jsif[$ifName]['show'][]		=	$this->_htmlId( $child_cnam, $vvChild );
												} elseif ( $vvChild->getName() == 'if' ) {
													foreach ( $vvChild->children() as $vvvChild ) {
														/** @var  SimpleXMLElement  $vvvChild */
														if ( ! in_array( $vvvChild->getName(), array( 'showview', 'if', 'else', 'params', 'fields', 'status' ) ) ) {													//TBD	//FIXME: this avoids JS error but still shows sub-view ! recursive function needed here
															$this->_jsif[$ifName]['show'][]		=	$this->_htmlId( $child_cnam, $vvvChild );
														}
													}
												}
											}
										}
									}
								}
							} elseif ( $subParam->getName() == 'else' ) {
								if ( $subParam->attributes( 'action' ) == 'set' ) {
									$correspondingParam						=	$param->getAnyChildByNameAttr( 'param', 'name', $subParam->attributes( 'name' ) );
									if ( $correspondingParam ) {
										$this->_jsif[$ifName]['set'][]		=	$this->_htmlId( $control_name, $correspondingParam )
											.	'=' . $this->control_id( $control_name, $subParam->attributes( 'name' ) )
											.	'=' . $subParam->attributes( 'value' );
									} else {
										echo 'No corresponding param to the else statement for name ' . $subParam->attributes( 'name' ) . ' !';
									}
								}
							} else {
								$this->_jsif[$ifName]['show'][]				=	$this->_htmlId( $control_name, $subParam );
							}
						}
						$this->_jsif[$ifName]['element']					=	$param;
						$this->_jsif[$ifName]['control_name']				=	$control_name;
						$this->_jsif[$ifName]['ifname']						=	$this->_htmlId( $control_name, $param );
					}

					$html[] = $this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				} elseif ( ( $ifType == 'condition' ) || ( $ifType == 'permission' ) || ( $viewType == 'view' ) ) {
					if ( $ifType == 'permission' ) {
						$showInside					=	Access::authorised( $param );
					} else {
						$showInside					=	$this->_evalIf( $param );
					}
					if ( $showInside ) {
						$then						=	$param->getChildByNameAttributes( 'then' );
						if ( $then ) {
							$insideParamToRender	=	$then;
						} else {
							$insideParamToRender	=	$param;
						}
					} else {
						$insideParamToRender		=	$param->getChildByNameAttributes( 'else' );

						if ( $insideParamToRender && $insideParamToRender->attributes( 'action' ) == 'set' ) {
							$correspondingParam		=	$param->getAnyChildByNameAttr( 'param', 'name', $insideParamToRender->attributes( 'name' ) );
							if ( $correspondingParam ) {
								$this->_modelOfData[0]->set( $insideParamToRender->attributes( 'name' ), $insideParamToRender->attributes( 'value' ));

								$insideParamToRender = null;
							} else {
								echo 'No corresponding param to the else statement for name ' . $insideParamToRender->attributes( 'name' ) . ' !';
							}
						}
					}
					if ( $insideParamToRender ) {
						$htmlElse					=	$this->renderAllParams( $insideParamToRender, $control_name, $tabs, $viewType, $htmlFormatting );
						if ( $htmlElse != '' ) {
							$html[]				=	$htmlElse;
						}
					}
				}
				break;
			case 'else':
				break;		// implemented in if above it

			case 'toolbarmenu':
				$newToolBarMenu					=	new SimpleXMLElement( '<?xml version="1.0" encoding="UTF-8"?><cbxml></cbxml>');
				/** @var $toolbarMenu SimpleXMLElement */
				/** @var $menu SimpleXMLElement */
				foreach ( $param->children() as $menu ) {
					$menuLink					=	$menu->attributes( 'link' );
					$menuAccess					=	true;
					$link						=	null;

					if ( $menuLink ) {
						$link					=	$this->_controllerView->drawUrl( $menuLink, $menu, $this->_modelOfData[0], null );

						if ( ! $link ) {
							$menuAccess			=	false;
						}
					}

					if ( $menuAccess ) {
						/** @var $menu SimpleXMLElement */
						$child					=	$newToolBarMenu->addChildWithAttr( 'menu', null, null, $menu->attributes() );

						if ( $link ) {
							$child->addAttribute( 'urllink', $link );
						}
					}
				}
				global $_CB_Backend_Menu;
				$_CB_Backend_Menu->menuItems[]	=	$newToolBarMenu;
				break;

			case 'grid':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$htid					=	$this->_outputIdEqualHtmlId( $control_name, $param );

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<tr' . $htid . '><td colspan="3" style="width: 100%;">';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'<td' . $htid . '>';
					}

					$fluid					=	( $param->attributes( 'fluid' ) == 'true' ? true : false );

					$html[]					=	'<div class="' . htmlspecialchars( RegistryEditView::buildClasses( $param, array( ( $fluid ? 'container-fluid' : 'container' ) ) ) ) . '">';

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<table class="table table-noborder">';
					}
				}

				$html[]						=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				if ( $htmlFormatting != 'fieldsListArray' ) {
					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</table>';
					}

					$html[]					=	'</div>';

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</td></tr>';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'</td>';
					}
				}
				break;

			case 'gridrow':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$htid					=	$this->_outputIdEqualHtmlId( $control_name, $param );

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<tr' . $htid . '><td colspan="3" style="width: 100%;">';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'<td' . $htid . '>';
					}

					$html[]					=	'<div class="' . htmlspecialchars( RegistryEditView::buildClasses( $param, array( 'row' ) ) ) . '">';
				}

				$html[]						=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				if ( $htmlFormatting != 'fieldsListArray' ) {
					$html[]					=	'</div>';

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</td></tr>';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'</td>';
					}
				}
				break;

			case 'gridcol':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$classes				=	array();
					$size					=	explode( ',', $param->attributes( 'size' ) );
					$colSizes				=	array( 'xs', 'sm', 'md', 'lg' );

					if ( count( $size ) > 1 ) for ( $i = 0; $i < 4; $i++ ) {
						if ( isset( $size[$i] ) && $size[$i] ) {
							$classes[]		=	'col-' . $colSizes[$i] . '-' . (int) $size[$i];
						}
					} elseif ( isset( $size[0] ) && $size[0] ) {
						$classes[]			=	'col-sm-' . (int) $size[0];
					} else {
						$classes[]			=	'col-sm-12';
					}

					$offset					=	explode( ',', $param->attributes( 'offset' ) );

					if ( count( $offset ) > 1 ) for ( $i = 0; $i < 4; $i++ ) {
						if ( isset( $offset[$i] ) && $offset[$i] ) {
							$classes[]		=	'col-' . $colSizes[$i] . '-offset-' . (int) $offset[$i];
						}
					} elseif ( isset( $offset[0] ) && $offset[0] ) {
						$classes[]			=	'col-sm-offset-' . (int) $offset[0];
					}

					$push					=	explode( ',', $param->attributes( 'push' ) );

					if ( count( $push ) > 1 ) for ( $i = 0; $i < 4; $i++ ) {
						if ( isset( $push[$i] ) && $push[$i] ) {
							$classes[]		=	'col-' . $colSizes[$i] . '-push-' . (int) $push[$i];
						}
					} elseif ( isset( $push[0] ) && $push[0] ) {
						$classes[]			=	'col-sm-push-' . (int) $push[0];
					}

					$pull					=	explode( ',', $param->attributes( 'pull' ) );

					if ( count( $pull ) > 1 ) for ( $i = 0; $i < 4; $i++ ) {
						if ( isset( $pull[$i] ) && $pull[$i] ) {
							$classes[]		=	'col-' . $colSizes[$i] . '-pull-' . (int) $pull[$i];
						}
					} elseif ( isset( $pull[0] ) && $pull[0] ) {
						$classes[]			=	'col-sm-pull-' . (int) $pull[0];
					}

					$html[]					=	'<div class="' . htmlspecialchars( RegistryEditView::buildClasses( $param, $classes ) ) . '">';

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<table class="table table-noborder">';
					}
				}

				$html[]						=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				if ( $htmlFormatting != 'fieldsListArray' ) {
					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</table>';
					}

					$html[]					=	'</div>';
				}
				break;

			case 'tabpane':
				// first render all tabpanetabs (including nested tabpanes):
				$tabpaneCounter++;

				$this->tabpaneNames[$tabpaneCounter]	=	$param->attributes( 'name' );
				$subhtml								=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				unset( $this->tabpaneNames[$tabpaneCounter] );

				$tabpaneCounter--;

				if ( $htmlFormatting != 'fieldsListArray' ) {
					// then puts them together:
					$htid					=	$this->_outputIdEqualHtmlId( $control_name, $param );

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<tr' . $htid . '><td colspan="3" style="width: 100%;">';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'<td' . $htid . '>';
					}

					$html[]					=	$tabs->startPane( $param->attributes( 'name' ) );
				}

				$html[]						=	$subhtml;

				if ( $htmlFormatting != 'fieldsListArray' ) {
					$html[]					=	$tabs->endPane();

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</td></tr>';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[]				=	'</td>';
					}
				}
				break;

			case 'tabpanetab':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$this->_i++;

					$idtab					=	$this->tabpaneNames[$tabpaneCounter] . $this->_i;
					$html[]					=	$tabs->startTab( $this->tabpaneNames[$tabpaneCounter], CBTxt::Th( $param->attributes( 'label' ) ), $idtab );

					$tabTitle				=	$param->attributes( 'title' );
					$tabDescription			=	$param->attributes( 'description' );

					$tabResult				=	array(	( $tabTitle && $tabDescription ? CBTxt::Th( $tabTitle ) : '' ),
														'<strong>' . CBTxt::Th( ( $tabDescription ? $tabDescription : $tabTitle ) ) . '</strong>',
														null
													);

					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'<table class="table table-noborder">';

						if ( $tabTitle || $tabDescription ) {
							$html[]			=	$this->_renderLine( $param, $tabResult, $control_name, $htmlFormatting, true, ( $viewType == 'view' ) );
						}
					} elseif ( $htmlFormatting == 'div' ) {
						if ( $tabTitle || $tabDescription ) {
							$html[]			=	$this->_renderLine( $param, $tabResult, $control_name, $htmlFormatting, true, ( $viewType == 'view' ) );
						}
					}
				}

				$html[]						=	$this->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );

				if ( $htmlFormatting != 'fieldsListArray' ) {
					if ( $htmlFormatting == 'table' ) {
						$html[]				=	'</table>';
					}

					$html[]					=	$tabs->endTab();
				}
				break;

			case 'inherit':
				$from				=	$param->attributes( 'from' );
				if ( $from ) {
					/** @var  SimpleXMLElement[] $fromXml */
					$fromXml		=	$param->xpath( $from );
					if ( $fromXml && ( count( $fromXml ) > 0 ) ) {
						array_unshift( $this->_extenders, array( &$param ) );
						foreach ( $fromXml as $fmx ) {
							$html[]	=	$this->renderAllParams( $fmx, $control_name, $tabs, $viewType, $htmlFormatting );
						}
					}
				}
				break;

			case 'extend':
				$errorText			=	self::extendXMLnode( $param, $param, null, $this->_pluginObject, $this );
				if ( $errorText ) {
					$html[]			=	$errorText;
				}
				break;
			/*
			 * This is in future going to be the new implementation for inherit in CB as it auto-loads: could also be named "extends".
			case 'extends':
				$from				=	$param->attributes( 'from' );
				if ( $from ) {
					$fromXml		=	cbpaidViewExtended::xpathWithAutoLoad( $param, $from );			// same as $fromXml = $param->xpath( $from );
					if ( $fromXml && ( count( $fromXml ) > 0 ) ) {
						$param->{0}	=	'inherit';
						array_unshift( $this->_parent->_extenders, array( &$param ) );
						foreach ( $fromXml as $fmx ) {
							$html[]	=	$this->_parent->renderAllParams( $fmx, $control_name, $tabs, $viewType, $htmlFormatting );
						}
					}
				}
				break;
			*/
			case 'trigger':
				$isSaving			=	( $htmlFormatting == 'fieldsListArray' );
				$errorText			=	$this->triggerXML( $param, $this->_pluginObject, $this, $isSaving );
				if ( $errorText ) {
					$html[]			=	$errorText;
				}
				break;
			case 'css':
			case 'js':
			case 'jquery':
				$fromFile					=	$param->attributes( 'file' );

				if ( $fromFile ) {
					global $_CB_framework;

					$this->substituteName( $fromFile, true );

					$fromFile				=	static::pathFromXML( $fromFile, $param, $this->_pluginObject, 'live' );

					switch ( $param->getName() ) {
						case 'css':
							$_CB_framework->document->addHeadStyleSheet( $fromFile );
							break;
						case 'js':
							$_CB_framework->document->addHeadScriptUrl( $fromFile );
							break;
						case 'jquery':
							$_CB_framework->addJQueryPlugin( $param->attributes( 'name' ), $fromFile );
							break;
					}
				}
				break;
			case 'menugroup':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$id				=	$this->_htmlId( $control_name, $param );

					$tb		= new Menu( $this->input, $param, $this->_options, $this->_pluginParams, $this->_types, $this->_actions, $this->_views, $this->_pluginObject, $this->_tabid, $this->_db, $this );
					if ( $htmlFormatting == 'table' ) {
						$html[] = '<tr id="' . $id . '"><td colspan="3" style="width: 100%;">';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[] = '<td id="' . $id . '">';
					}
					$html[]	= $tb->draw();
					if ( $htmlFormatting == 'table' ) {
						$html[] = '</td></tr>';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[] = '</td>';
					}
					unset($tb);
				}
				break;
			case 'tablebrowser':
				if ( $htmlFormatting != 'fieldsListArray' ) {
					$id				=	$this->_htmlId( $control_name, $param );

					$tb		= new TableBrowser( $this->input, $param, $this->_options, $this->_pluginParams, $this->_types, $this->_actions, $this->_views, $this->_pluginObject, $this->_tabid, $this->_db, $this );
					if ( $htmlFormatting == 'table' ) {
						$html[] = '<tr id="' . $id . '"><td colspan="3" style="width: 100%;">';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[] = '<td id="' . $id . '">';
					}
					$html[]	= $tb->draw( $viewType );
					if ( $htmlFormatting == 'table' ) {
						$html[] = '</td></tr>';
					} elseif ( $htmlFormatting == 'td' ) {
						$html[] = '</td>';
					}
					unset($tb);
				}
				break;
			case 'showview':
				$name						=	$param->attributes( 'name' );
				$viewName					=	$param->attributes( 'view' );
				$showviewType				=	$param->attributes( 'type' );
				$viewMode					=	$param->attributes( 'mode' );
				$htmlFormattingView			=	$param->attributes( 'formatting' );
				$tabbed						=	( $htmlFormattingView == 'tab' );

				if ( ( $htmlFormattingView == '' ) || $tabbed ) {
					$htmlFormattingView		=	$htmlFormatting;
				}

				switch ( $viewMode ) {
					// case 'view':
					case 'show':
						$viewType			=	'view';
						break;
					// case 'param':
					case 'edit':
						$viewType			=	'param';
						break;
					default:
						break;
				}

				// MODEL: load data to view:
				/** @var $dataModel SimpleXMLElement|null */
				$dataModel					=	$param->getElementByPath( 'data' );
				if ( $dataModel ) {
					if ( $name ) {
						if ( $control_name ) {
							$parent_cname	=	$control_name . '[' . $name . ']';
						} else {
							$parent_cname	=	$name;
						}
					} else {
						$parent_cname		=	$control_name;
					}
					$dataModelType			=  $dataModel->attributes( 'type' );
					switch ( $dataModelType ) {
						case 'sql:string':			// <data name="params" type="sql:string" default="" />
							$name			=	$param->attributes( 'name' );
							$value			=	$this->get( $name, $param->attributes( 'default' ) );
							$sqlParams		=	new Registry( $value );
							$sqlParams->setNamespaceRegistry( 'parent', $this->getModelOfData() );
							$data			=	$sqlParams;
							break;
						case 'sql:field':			// <data name="params" type="sql:field" table="#__cbsubs_config" class="cbpaidConfig" key="id" value="1" valuetype="sql:int" />
							global $_CB_database;
							$xmlsql			=	new XmlQuery( $_CB_database, null, $this->_pluginParams );
							$xmlsql->process_data( $dataModel );
							$sqlRow			=	$xmlsql->queryloadResult();			// get the resulting field
							if ( $sqlRow !== null ) {
								$sqlParams	=	new Registry( $sqlRow );
								$sqlParams->setNamespaceRegistry( 'parent', $this->getModelOfData() );
								$data		=	$sqlParams;
							} else {
								// echo 'ERROR'; // error in query...
								$data		=	null;
							}
							break;
						case 'parameters':			// <data name="pluginparams" type="parameters" />
							$data			=		$this->_pluginParams;
							break;
						default:
							$data			=	null;
							trigger_error( 'Extended renderAllParams:showview: Data model type ' . $dataModelType . ' is not implemented !', E_USER_NOTICE );
							break;
					}
				} else {
					$parent_cname			=	$control_name;
					if ( $name && ( $showviewType == 'private' ) ) {
						$value				=	$this->get( $name, $param->attributes( 'default' ) );
						$sqlParams			=	new Registry( $value );
						$sqlParams->setNamespaceRegistry( 'parent', $this->getModelOfData() );
						$data				=	$sqlParams;
					} else {
						// No data child found and not private type then use the current data model for params:
						$data				=	null;
					}
				}
				// VIEW: select view:
				if ( $viewName && ( ( ! $showviewType ) || ( $showviewType == 'view' ) ) ) {
					$this->substituteName( $viewName, false );
					//	$allViewsModels		=	$param->xpath( '/cbxml/views' );		// $param->xpath( '/cbxml/views[@test="haha"]' );		// $param->xpath( '/cbxml/views[1][@test="haha"]' );		// $param->xpath( '/cbxml/views[1]' );		// $param->xpath( '//views' );		//
					//	$viewModel			=	$allViewsModels[0]->getChildByNameAttributes( 'view', array( 'ui' => 'admin', 'name' => $viewName ) );
					//		$allViewsModels		=	$param->xpath( '//views[test="haha"]/view[@name="' . $viewName . '"]' );		// $param->xpath( '../../../../../../../../views[test="haha"]/view[@name="' . $viewName . '"]' );		// $param->xpath( '/*/views[test="haha"]/*[@name="' . $viewName . '"]' );		// $param->xpath( '/cbxml/views[test="haha"]/view[@name="' . $viewName . '"]' );		//
					//		$viewModel			=	$allViewsModels[0];
					$viewModel			=	$this->_views->getChildByNameAttributes( 'view', array( 'ui' => 'admin', 'name' => $viewName ) );
					if ( !$viewModel ) {
						if ( $param->attributes( 'mandatory' ) == 'false' ) {
							return null;
						}
						trigger_error( 'Extended renderAllParams:showview: View ' . $viewName . ' not defined in XML. ', E_USER_NOTICE );
						return false;
					}
					if ( $data ) {
						$this->pushModelOfData( $data );
					}

					if ( $tabbed ) {
						$this->_i++;

						$idtab			=	$this->tabpaneNames[$tabpaneCounter] . $this->_i;

						$html[]			=	$tabs->startTab( $idtab, CBTxt::Th( $viewModel->attributes( 'label' ) ), $idtab );

						if ( $htmlFormattingView == 'table' ) {
							$html[]		=	'<table class="table table-noborder">';
						}
					}

					$html[]				=	$this->renderAllParams( $viewModel, $parent_cname, $tabs, $viewType, $htmlFormattingView );

					if ( $tabbed ) {
						if ( $htmlFormattingView == 'table' ) {
							$html[]		=	'</table>';
						}

						$html[]			=	$tabs->endTab();
					}

					if ( $data ) {
						$this->popModelOfData();
					}
				} elseif ( $showviewType == 'xml' ) {
					// e.g.: <showview name="gateway_paymentstatus_information" mode="view" type="xml" file="processors/{payment_method}/edit.gateway" path="/*/views/view[@name=&quot;paymentstatusinformation&quot;]" mandatory="false" />
					$fromNode			=	$param->attributes( 'path' );
					$fromFile			=	$param->attributes( 'file' );
					$mandatory			=	$param->attributes( 'mandatory' );
					if ( $fromNode && ( $fromFile !== null ) ) {
						$this->substituteName( $fromFile, true );
						$this->substituteName( $fromNode, false );
						if ( $fromFile !== '' ) {
							$fromFile		=	static::pathFromXML( $fromFile . '.xml', $param, $this->_pluginObject );
						}
						if ( ( $fromFile === '' ) || is_readable( $fromFile ) ) {
							if ( $fromFile === '' ) {
								$fromRoot	=	$param;
							} else {
								$fromRoot	=	new SimpleXMLElement( $fromFile, LIBXML_NONET | ( defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0 ), true );
							}

							/** @var SimpleXMLElement[] $viewModels */
							$viewModels		=	$fromRoot->xpath( $fromNode );

							if ( $viewModels && count( $viewModels ) ) {
								if ( $data ) {
									$this->pushModelOfData( $data );
								}

								foreach ( $viewModels as $viewModel ) {
									if ( $tabbed ) {
										$this->_i++;

										$idtab			=	$this->tabpaneNames[$tabpaneCounter] . $this->_i;

										$html[]			=	$tabs->startTab( $idtab, CBTxt::Th( $viewModel->attributes( 'label' ) ), $idtab );

										if ( $htmlFormattingView == 'table' ) {
											$html[]		=	'<table class="table table-noborder">';
										}
									}

									$html[]				=	$this->renderAllParams( $viewModel, $parent_cname, $tabs, $viewType, $htmlFormattingView );

									if ( $tabbed ) {
										if ( $htmlFormattingView == 'table' ) {
											$html[]		=	'</table>';
										}

										$html[]			=	$tabs->endTab();
									}
								}

								if ( $data ) {
									$this->popModelOfData();
								}
							} elseif ( $mandatory == 'false' ) {
								return null;
							} else {
								trigger_error( 'Extended renderAllParams:showview: View ' . $viewName . ': file ' . $fromFile . ', path: ' . $fromNode . ' does not exist or is empty.', E_USER_NOTICE );
							}
						} elseif (  $param->attributes( 'mandatory' ) == 'false' ) {
							return null;
						} else {
							trigger_error( 'Extended renderAllParams:showview: View ' . $viewName . ': file ' . $fromFile . ' does not exist or is not readable.', E_USER_NOTICE );
							return false;
						}
					}
				} elseif ( $showviewType == 'plugins' ) {
					$groups							=	explode( ',', $param->attributes( 'groups' ) );
					$action							=	$param->attributes( 'action' );
					$path							=	$param->attributes( 'path' );

					$this->substituteName( $action, false );
					$this->substituteName( $path, false );

					if ( $data ) {
						$this->pushModelOfData( $data );
					}

					foreach ( $groups as $group ) {
						$matches						=	null;

						if ( preg_match( '/^([^\[]+)\[(.+)\]$/', $group, $matches ) ) {
							$classId					=	$matches[2];
							$group						=	$matches[1];
						} else {
							$classId					=	null;
						}

						global $_PLUGINS;

						$_PLUGINS->loadPluginGroup( $group, $classId, 0 );

						$loadedPlugins					=	$_PLUGINS->getLoadedPluginGroup( $group );

						foreach ( $loadedPlugins as /* $id => */ $plugin ) {
							$element					=	$_PLUGINS->loadPluginXML( 'action', $action, $plugin->id );

							/** @var SimpleXMLElement[] $viewModels */
							$viewModels					=	$element->xpath( $path );

							if ( $viewModels && count( $viewModels ) ) {
								foreach ( $viewModels as $viewModel ) {
									if ( $tabbed ) {
										$this->_i++;

										$idtab			=	$this->tabpaneNames[$tabpaneCounter] . $this->_i;
										$tabTite		=	CBTxt::Th( $viewModel->attributes( 'label' ) );

										if ( ! $tabTite ) {
											$tabTite	=	$plugin->name;
										}

										$html[]			=	$tabs->startTab( $idtab, $tabTite, $idtab );

										if ( $htmlFormattingView == 'table' ) {
											$html[]		=	'<table class="table table-noborder">';
										}
									}

									$html[]				=	$this->renderAllParams( $viewModel, $parent_cname, $tabs, $viewType, $htmlFormattingView );

									if ( $tabbed ) {
										if ( $htmlFormattingView == 'table' ) {
											$html[]		=	'</table>';
										}

										$html[]			=	$tabs->endTab();
									}
								}
							}
						}
					}

					if ( $data ) {
						$this->popModelOfData();
					}
				} elseif ( $showviewType == 'private' ) {
					$dataModelClass					=	$param->attributes( 'class' );
					$methodName						=	$param->attributes( 'method' );
					$dataKey						=	$param->attributes( 'key' );
					if ( $dataModelClass && $methodName ) {
						if ( $data && $dataKey && isset( $data->$dataKey ) ) {
							$dataModelValue			=	$data->$dataKey;
						} elseif ( ! $dataKey ) {
							$dataModelValue			=	0;
						} else {
							trigger_error( sprintf( "Missing key field %s in data", htmlspecialchars( $dataKey ) ), E_USER_NOTICE );
							return null;
						}
						if ( strpos( $dataModelClass, '::' ) === false ) {
							if ( class_exists( $dataModelClass ) ) {
								/** @var $viewerClass TableInterface */
								global $_CB_database;
								$viewerClass		=	new $dataModelClass( $_CB_database );		// normal clas="className"
								if ( $dataModelValue ) {
									$viewerClass->load( $dataModelValue );
								}
							} else {
								trigger_error( "Missing private class " . htmlspecialchars( $dataModelClass ), E_USER_NOTICE );
								return null;
							}
						} else {
							$dataModelSingleton		=	explode( '::', $dataModelClass );	// class object loader from singleton: class="loaderClass::loadStaticMethor" with 1 parameter, the key value.
							if ( is_callable( $dataModelSingleton ) ) {
								$rows				=	call_user_func_array( $dataModelSingleton, array( $dataModelValue ) );
								$viewerClass		=	$rows[0];
							} else {
								trigger_error( "Missing singleton class creator " . htmlspecialchars( $dataModelClass ), E_USER_NOTICE );
								return null;
							}
						}
						if ( $viewerClass ) {
							if ( method_exists( $viewerClass, $methodName ) ) {
								/*
													$row	=	$this->_modelOfData[0];				//TBD: checked....
													foreach (get_object_vars($data) as $key => $v) {
														if( substr( $key, 0, 1 ) != '_' ) {			// internal attributes of an object are ignored
															if (isset($row->$key)) {
																$data->$key = $row->$key;
															}
														}
													}
								*/
								// this parameter is missing here ?: $control_name_name	=	$this->control_name( $control_name, $name );
								$html[]				=	$viewerClass->$methodName( $param, $data, $this->_pluginParams, $parent_cname, $tabs, $viewType, $htmlFormattingView, $tabbed );
								// shouldn't this be this? : $html[]				=	$viewerClass->$methodName( $value, $this->_pluginParams, $name, $node, $control_name, $control_name_name, $this->_view, $this->_modelOfData[0], $this->_modelOfDataRows, $this->_modelOfDataRowsNumber );

							} else {
								trigger_error( "Missing private xml method " . htmlspecialchars( $methodName ), E_USER_NOTICE );
								return null;
							}
						} else {
							trigger_error( "No data found !", E_USER_NOTICE );
							return null;
						}
					} else {
						trigger_error( "Missing private class or method attributes in xml", E_USER_NOTICE );
						return null;
					}
				}
				break;
			case 'hidden':
				if ( $viewType == 'view' ) {
					trigger_error( 'Type hidden in non-view mode not implemented in GUI.', E_USER_NOTICE );
				}
				break;
			case 'comment':
				break;

			case 'extendxmlparser':
				$this->setExtendedViewParser( $param );
				break;

			case 'extendparser':
				// old CBSubs GPL 3.0.0 case: ignore if not needed (but keep reference in case:
				$this->oldExtendParserNode		=	$param;
				break;

			case 'attributes':
				// Implemented above by ->extendParamAttributes
				break;

			default:
				if ( $this->_extendViewParser ) {
					$html[]						=	$this->_extendViewParser->renderAllParams( $param, $control_name, $tabs, $viewType, $htmlFormatting );
				} else {
					echo 'Method to render XML view element ' . $param->getName() . ' is not implemented !';
				}
				break;
		}
		return ( $htmlFormatting == 'fieldsListArray' ? $this->arrayValuesMerge( $html ) : implode( "\n", $html ) );
	}