/**
     * Creates a multiple-selector box (two boxes, side-by-side)
     *
     * @param string $table See getSingleField_typeSelect()
     * @param string $field See getSingleField_typeSelect()
     * @param array $row See getSingleField_typeSelect()
     * @param array $parameterArray See getSingleField_typeSelect()
     * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
     * @param array $selItems Items available for selection
     * @param string $noMatchingLabel Label for no-matching-value
     * @return string The HTML code for the item
     */
    protected function getSingleField_typeSelect_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel)
    {
        $languageService = $this->getLanguageService();
        $item = '';
        $disabled = '';
        if ($this->isGlobalReadonly() || $config['readOnly']) {
            $disabled = ' disabled="disabled"';
        }
        // Setting this hidden field (as a flag that JavaScript can read out)
        if (!$disabled) {
            $item .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />';
        }
        // Set max and min items:
        $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
        if (!$maxitems) {
            $maxitems = 100000;
        }
        // Get "removeItems":
        $removeItems = GeneralUtility::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], TRUE);
        // Get the array with selected items:
        $itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
        // Possibly filter some items:
        $itemArray = ArrayUtility::keepItemsInArray($itemArray, $parameterArray['fieldTSConfig']['keepItems'], function ($value) {
            $parts = explode('|', $value, 2);
            return rawurldecode($parts[0]);
        });
        // Perform modification of the selected items array:
        foreach ($itemArray as $tk => $tv) {
            $tvP = explode('|', $tv, 2);
            $evalValue = $tvP[0];
            $isRemoved = in_array($evalValue, $removeItems) || $config['type'] == 'select' && $config['authMode'] && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $evalValue, $config['authMode']);
            if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
                $tvP[1] = rawurlencode(@sprintf($noMatchingLabel, $evalValue));
            } else {
                if (isset($parameterArray['fieldTSConfig']['altLabels.'][$evalValue])) {
                    $tvP[1] = rawurlencode($languageService->sL($parameterArray['fieldTSConfig']['altLabels.'][$evalValue]));
                }
                if (isset($parameterArray['fieldTSConfig']['altIcons.'][$evalValue])) {
                    $tvP[2] = $parameterArray['fieldTSConfig']['altIcons.'][$evalValue];
                }
            }
            if ($tvP[1] == '') {
                // Case: flexform, default values supplied, no label provided (bug #9795)
                foreach ($selItems as $selItem) {
                    if ($selItem[1] == $tvP[0]) {
                        $tvP[1] = html_entity_decode($selItem[0]);
                        break;
                    }
                }
            }
            $itemArray[$tk] = implode('|', $tvP);
        }
        // size must be at least two, as there are always maxitems > 1 (see parent function)
        if (isset($config['size'])) {
            $size = (int) $config['size'];
        } else {
            $size = 2;
        }
        $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
        $itemsToSelect = '';
        $filterTextfield = '';
        $filterSelectbox = '';
        if (!$disabled) {
            // Create option tags:
            $opt = array();
            $styleAttrValue = '';
            foreach ($selItems as $p) {
                if ($config['iconsInOptionTags']) {
                    $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
                }
                $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . ' title="' . $p[0] . '">' . $p[0] . '</option>';
            }
            // Put together the selector box:
            $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : '';
            $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
            $multiSelectId = str_replace('.', '', uniqid('tceforms-multiselect-', TRUE));
            $itemsToSelect = '
				<select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '" id="' . $multiSelectId . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '_sel" ' . ' class="form-control t3js-formengine-select-itemstoselect" ' . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $parameterArray['onFocus'] . $this->getValidationDataAsDataAttribute($config) . $selector_itemListStyle . '>
					' . implode('
					', $opt) . '
				</select>';
            // enable filter functionality via a text field
            if ($config['enableMultiSelectFilterTextfield']) {
                $filterTextfield = '
					<span class="input-group input-group-sm">
						<span class="input-group-addon">
							<span class="fa fa-filter"></span>
						</span>
						<input class="t3js-formengine-multiselect-filter-textfield form-control" value="" />
					</span>';
            }
            // enable filter functionality via a select
            if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
                $filterDropDownOptions = array();
                foreach ($config['multiSelectFilterItems'] as $optionElement) {
                    $optionValue = $languageService->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1] : $optionElement[0]);
                    $filterDropDownOptions[] = '<option value="' . htmlspecialchars($languageService->sL($optionElement[0])) . '">' . htmlspecialchars($optionValue) . '</option>';
                }
                $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">
						' . implode('
						', $filterDropDownOptions) . '
					</select>';
            }
        }
        if (!empty(trim($filterSelectbox)) && !empty(trim($filterTextfield))) {
            $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
            $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . $filterTextfield . '</div>';
            $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
        } else {
            $selectBoxFilterContents = trim($filterSelectbox . ' ' . $filterTextfield);
        }
        // Pass to "dbFileIcons" function:
        $params = array('size' => $size, 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0), 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : '', 'dontShowMoveIcons' => $maxitems <= 1, 'maxitems' => $maxitems, 'info' => '', 'headers' => array('selector' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'), 'items' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'), 'selectorbox' => $selectBoxFilterContents), 'noBrowser' => 1, 'rightbox' => $itemsToSelect, 'readOnly' => $disabled);
        $item .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemArray, '', $params, $parameterArray['onFocus']);
        return $item;
    }
    /**
     * Creates a selectorbox list (renderMode = "singlebox")
     *
     * @param string $table See getSingleField_typeSelect()
     * @param string $field See getSingleField_typeSelect()
     * @param array $row See getSingleField_typeSelect()
     * @param array $parameterArray See getSingleField_typeSelect()
     * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
     * @param array $selItems Items available for selection
     * @param string $noMatchingLabel Label for no-matching-value
     * @return string The HTML code for the item
     */
    protected function getSingleField_typeSelect_singlebox($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel)
    {
        $languageService = $this->getLanguageService();
        // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
        $itemArray = array_flip(FormEngineUtility::extractValuesOnlyFromValueLabelList($parameterArray['itemFormElValue']));
        $item = '';
        $disabled = '';
        if ($this->isGlobalReadonly() || $config['readOnly']) {
            $disabled = ' disabled="disabled"';
        }
        // Traverse the Array of selector box items:
        $opt = array();
        // Used to accumulate the JS needed to restore the original selection.
        $restoreCmd = array();
        $c = 0;
        foreach ($selItems as $p) {
            // Selected or not by default:
            $sM = '';
            if (isset($itemArray[$p[1]])) {
                $sM = ' selected="selected"';
                $restoreCmd[] = 'document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '[]') . '].options[' . $c . '].selected=1;';
                unset($itemArray[$p[1]]);
            }
            // Non-selectable element:
            $nonSel = '';
            if ((string) $p[1] === '--div--') {
                $nonSel = ' onclick="this.selected=0;" class="formcontrol-select-divider"';
            }
            // Icon style for option tag:
            $styleAttrValue = '';
            if ($config['iconsInOptionTags']) {
                $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
            }
            // Compile <option> tag:
            $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . $nonSel . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE) . '</option>';
            $c++;
        }
        // Remaining values:
        if (!empty($itemArray) && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
            foreach ($itemArray as $theNoMatchValue => $temp) {
                // Compile <option> tag:
                array_unshift($opt, '<option value="' . htmlspecialchars($theNoMatchValue) . '" selected="selected">' . htmlspecialchars(@sprintf($noMatchingLabel, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE) . '</option>');
            }
        }
        // Compile selector box:
        $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
        $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : '';
        $size = (int) $config['size'];
        $cssPrefix = $size === 1 ? 'tceforms-select' : 'tceforms-multiselect';
        $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
        $selectBox = '<select id="' . str_replace('.', '', uniqid($cssPrefix, TRUE)) . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '[]" ' . 'class="form-control ' . $cssPrefix . '"' . ($size ? ' size="' . $size . '" ' : '') . ' multiple="multiple" onchange="' . htmlspecialchars($sOnChange) . '"' . $parameterArray['onFocus'] . ' ' . $this->getValidationDataAsDataAttribute($config) . $selector_itemListStyle . $disabled . '>
						' . implode('
						', $opt) . '
					</select>';
        // Add an empty hidden field which will send a blank value if all items are unselected.
        if (!$disabled) {
            $item .= '<input type="hidden" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="" />';
        }
        // Put it all into a table:
        $onClick = htmlspecialchars('document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '[]') . '].selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;');
        $width = $this->formMaxWidth($this->defaultInputWidth);
        $item .= '
			<div class="form-control-wrap" ' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>
				<div class="form-wizards-wrap form-wizards-aside">
					<div class="form-wizards-element">
						' . $selectBox . '
					</div>
					<div class="form-wizards-items">
						<a href="#" class="btn btn-default" onclick="' . $onClick . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection')) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>
					</div>
				</div>
			</div>
			<p>
				<em>' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.holdDownCTRL')) . '</em>
			</p>
			';
        return $item;
    }
    /**
     * Get a selector as used for the select type, to select from all available
     * records and to create a relation to the embedding record (e.g. like MM).
     *
     * @param array $selItems Array of all possible records
     * @param array $conf TCA configuration of the parent(!) field
     * @param array $PA An array with additional configuration options
     * @param array $uniqueIds The uids that have already been used and should be unique
     * @return string A HTML <select> box with all possible records
     */
    protected function renderPossibleRecordsSelectorTypeSelect($selItems, $conf, &$PA, $uniqueIds = array())
    {
        $foreign_table = $conf['foreign_table'];
        $foreign_selector = $conf['foreign_selector'];
        $PA = array();
        $PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$foreign_selector];
        $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($foreign_table, array(), $foreign_selector);
        $config = $PA['fieldConf']['config'];
        $item = '';
        // @todo $disabled is not present - should be read from config?
        $disabled = FALSE;
        if (!$disabled) {
            $nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->globalOptions['inlineFirstPid']);
            // Create option tags:
            $opt = array();
            $styleAttrValue = '';
            foreach ($selItems as $p) {
                if ($config['iconsInOptionTags']) {
                    $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
                }
                if (!in_array($p[1], $uniqueIds)) {
                    $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . htmlspecialchars($p[0]) . '</option>';
                }
            }
            // Put together the selector box:
            $itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : '';
            $size = (int) $conf['size'];
            $size = $conf['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $conf['autoSizeMax']) : $size;
            $onChange = 'return inline.importNewRecord(' . GeneralUtility::quoteJSvalue($nameObject . '-' . $conf['foreign_table']) . ')';
            $item = '
				<select id="' . $nameObject . '-' . $conf['foreign_table'] . '_selector" class="form-control"' . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($onChange) . '"' . $PA['onFocus'] . $itemListStyle . ($conf['foreign_unique'] ? ' isunique="isunique"' : '') . '>
					' . implode('', $opt) . '
				</select>';
            if ($size <= 1) {
                // Add a "Create new relation" link for adding new relations
                // This is necessary, if the size of the selector is "1" or if
                // there is only one record item in the select-box, that is selected by default
                // The selector-box creates a new relation on using a onChange event (see some line above)
                if (!empty($conf['appearance']['createNewRelationLinkTitle'])) {
                    $createNewRelationText = $this->getLanguageService()->sL($conf['appearance']['createNewRelationLinkTitle'], TRUE);
                } else {
                    $createNewRelationText = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:cm.createNewRelation', TRUE);
                }
                $item .= '
				<span class="input-group-btn">
					<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($onChange) . '">
						' . IconUtility::getSpriteIcon('actions-document-new', array('title' => $createNewRelationText)) . $createNewRelationText . '
					</a>
				</span>';
            } else {
                $item .= '
				<span class="input-group-btn btn"></span>';
            }
            // Wrap the selector and add a spacer to the bottom
            $item = '<div class="input-group form-group t3js-formengine-validation-marker ' . $this->inlineData['config'][$nameObject]['md5'] . '">' . $item . '</div>';
        }
        return $item;
    }