<?php

namespace IMATHUZH\Qfq\Core\Renderer\FormElement\Bootstrap3;

use IMATHUZH\Qfq\Core\Form\FormElement\AbstractFormElement;
use IMATHUZH\Qfq\Core\Form\FormElement\CheckboxFormElement;
use IMATHUZH\Qfq\Core\Helper\HelperFormElement;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Renderer\BaseRenderer;
use IMATHUZH\Qfq\Core\Store\Store;

class Bootstrap3CheckboxRenderer extends \IMATHUZH\Qfq\Core\Renderer\FormElement\Base\CheckboxRenderer {

    /**
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return string
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderInput(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML): string {

        switch ($fe->attributes[FE_CHECKBOX_MODE]) {
            case FE_CHECKBOX_MODE_SINGLE:
                $html = $this->renderSingle($fe, $renderMode);
                break;
            case FE_CHECKBOX_MODE_MULTI;
                $html = $this->renderMulti($fe, $renderMode);
                break;
            case FE_CHECKBOX_MODE_MULTI_STATE;
                $html = $this->renderMultiStateCheckBox($fe);
                break;
            default:
                throw new \UserFormException('checkBoxMode: \'' . $fe->attributes[FE_CHECKBOX_MODE] . '\' is unknown.', ERROR_CHECKBOXMODE_UNKNOWN);
        }

        return $html . HelperFormElement::getHelpBlock() . $fe->attributes[FE_INPUT_EXTRA_BUTTON_INFO];
    }


    /**
     * Render a single Checkbox
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return string
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function renderSingle(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {

        $fe->htmlAttributes[HTML_ATTR_ID] = $fe->attributes[FE_HTML_ID] . '-0';
        $fe->htmlAttributes[HTML_ATTR_VALUE] = $fe->attributes[FE_CHECKBOX_CHECKED];
        if ($fe->attributes[FE_DYNAMIC_UPDATE] === 'yes') $fe->htmlAttributes[FE_DATA_LOAD] = FE_DATA_LOAD;
        $fe->htmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE];

        if ($fe->attributes[FE_CHECKBOX_CHECKED] === $fe->value) {
            $fe->htmlAttributes[HTML_ATTR_CHECKED] = 'checked';
        }

        if (isset($fe->attributes[FE_AUTOFOCUS])) $fe->htmlAttributes[FE_AUTOFOCUS] = $fe->attributes[FE_AUTOFOCUS];
        if (isset($fe->attributes[F_FE_DATA_REQUIRED_ERROR])) $fe->htmlAttributes[F_FE_DATA_REQUIRED_ERROR] = $fe->attributes[F_FE_DATA_REQUIRED_ERROR];

        if (isset($fe->attributes[FE_BUTTON_CLASS])) {
            // Buttons
            return $this->renderSingleButtons($fe, $renderMode);

        } else {
            // Plain Checkboxes
            return $this->renderSinglePlain($fe, $renderMode);
        }
    }


    /**
     * Build a single HTML plain checkbox based on two values.
     * Create a 'hidden' input field and a 'checkbox' input field - both with the same HTML 'name'.
     * HTML does not submit an unchecked checkbox. Then only the 'hidden' input field is submitted.
     *
     * <input name="$htmlFormElementName" type="radio" [autofocus="autofocus"]
     *            [required="required"] [disabled="disabled"] value="<value>" [checked="checked"] >
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderSinglePlain(AbstractFormElement $fe, string $renderMode) {

        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);

        $htmlHidden = HelperFormElement::buildNativeHidden($fe->htmlAttributes[HTML_ATTR_NAME], $fe->attributes[FE_CHECKBOX_UNCHECKED]);
        Store::getInstance()->setVar($fe->htmlAttributes[HTML_ATTR_NAME], $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false);

        // For inline filter mode: add data-unchecked attribute (hidden input not rendered in reports)
        $isFilterMode = $fe->attributes[FE_INLINE_FILTER] ?? false;
        if ($isFilterMode) {
            $fe->htmlAttributes['data-unchecked'] = $fe->attributes[FE_CHECKBOX_UNCHECKED];
        }

        $inputClass = implode(' ', $fe->cssClasses);
        $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
        $html = '<input ' . Support::arrayToXMLAttributes($fe->htmlAttributes) . $classAttr . '>';
        $html .= '<span class="checkmark" aria="hidden"></span>';

        if (isset($fe->attributes[FE_LABEL_2])) {
            $html .= Support::wrapTag("<span style='font-weight: 400; padding-bottom: 0.5em'>", $fe->attributes['label2']);
        }

        // Add filter count badge for inline filter mode (inside label, after checkmark)
        if ($isFilterMode && $fe->filterCount !== null) {
            $paramName = $fe->attributes[FE_NAME] ?? '';
            $html .= '<span class="qfq-inline-count-badge" data-count-for="' . htmlspecialchars($paramName) . '">(' . $fe->filterCount . ')</span>';
        }

        $fe->attributes[FE_BUTTON_CLASS] = 'checkbox';
        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $fe->attributes[FE_BUTTON_CLASS] .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled'
        }

        $labelAttribute = Support::doAttribute(HTML_ATTR_TITLE, $fe->attributes[FE_TOOLTIP]);
        $labelAttribute .= Support::doAttribute(HTML_ATTR_CLASS, $fe->attributes[FE_BUTTON_CLASS]);
        $labelAttribute .= Support::doAttribute(HTML_ATTR_ID, HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], 0, HTML_ID_EXTENSION_LABEL));


        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'checkbox-btn-group-single');


        $html = Support::wrapTag("<label $labelAttribute>", $html, true);

        if (($fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] ?? '') !== ''
            || (isset($fe->attributes[FE_INPUT_EXTRA_BUTTON_PASSWORD]) && $fe->attributes[FE_INPUT_EXTRA_BUTTON_PASSWORD] !== '')
            || (isset($fe->attributes[FE_INPUT_EXTRA_BUTTON_LOCK]) && $fe->attributes[FE_INPUT_EXTRA_BUTTON_LOCK] !== '')
            || (isset($fe->attributes[FE_INPUT_EXTRA_BUTTON_INFO]) && $fe->attributes[FE_INPUT_EXTRA_BUTTON_INFO] !== '')) {

            $html = Support::wrapTag("<div class='checkbox-btn-group'>", $html . $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML]);
        }

        if ($renderMode == RENDER_MODE_JSON) {
            $htmlInputId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_ELEMENT_TO_REPLACE] = FE_LABEL;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_SUB_ELEMENTS][] = $html;
            return $json;
        }
        return $html;
    }

    /**
     * Build a Checkbox based on two values with Bootstrap Button class.
     *
     * <div class="btn-group" data-toggle="buttons">
     *    <input type="hidden" name="$htmlFormElementName" value="$valueUnChecked">
     *    <label class="btn btn-primary active">
     *       <input type="checkbox" autocomplete="off" name="$htmlFormElementName" value="$valueChecked"checked>
     *       Checkbox 1 (pre-checked)
     *    </label>
     * </div>
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderSingleButtons(AbstractFormElement $fe, string $renderMode) {
        $html = '';
        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);

        if (!isset($fe->attributes[FE_BUTTON_CLASS]) || $fe->attributes[FE_BUTTON_CLASS] == '') {
            $fe->attributes[FE_BUTTON_CLASS] = 'btn-default';
        }
        $fe->attributes[FE_BUTTON_CLASS] = 'btn ' . $fe->attributes[FE_BUTTON_CLASS];

        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $fe->attributes[FE_BUTTON_CLASS] .= ' disabled';
        }

        $classActive = '';
        if ($fe->attributes[FE_CHECKBOX_CHECKED] === $fe->value) {
            $fe->attributes[FE_BUTTON_CLASS] .= ' active';
        }

        $htmlHidden = HelperFormElement::buildNativeHidden($fe->htmlAttributes[HTML_ATTR_NAME], $fe->attributes[FE_CHECKBOX_UNCHECKED]);
        Store::getInstance()->setVar($fe->htmlAttributes[HTML_ATTR_NAME], $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false);
        $html = '';

        $inputClass = implode(' ', $fe->cssClasses);
        $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
        $htmlElement = '<input ' . Support::arrayToXMLAttributes($fe->htmlAttributes) . $classAttr . '>';
        if (isset($fe->attributes[FE_LABEL_2])) {
            $htmlElement .= $fe->attributes[FE_LABEL_2];
        } else {
            $htmlElement .= $fe->attributes[FE_CHECKBOX_CHECKED];
        }

        $labelAttribute = Support::doAttribute(HTML_ATTR_TITLE, $fe->attributes[FE_TOOLTIP]);
        $labelAttribute .= Support::doAttribute(HTML_ATTR_CLASS, $fe->attributes[FE_BUTTON_CLASS]);
        $labelAttribute .= Support::doAttribute(HTML_ATTR_ID, HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], 0, HTML_ID_EXTENSION_LABEL));
        $html .= Support::wrapTag("<label $labelAttribute>", $htmlElement, true);

        $btnGroupId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_BUTTON_GROUP;
        if ($renderMode == RENDER_MODE_JSON) {
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_ELEMENT_TO_REPLACE] = HTML_LABEL;
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_SUB_ELEMENTS][] = $html;
            return $json;
        }

        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'extra-button-btn-group');
        $html .= $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML];
        $btnGroupClass = $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] === '' ? 'btn-group' : 'btn-group input-group';
        $html = Support::wrapTag('<div class="' . $btnGroupClass . '" data-toggle="buttons" id="' . $btnGroupId . '">', $html);

        return $html;
    }


    /**
     * Render CheckboxList
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return string
     */
    private function renderMulti(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {
        if (isset($fe->attributes[FE_BUTTON_CLASS])) {

            if ($fe->attributes[FE_BUTTON_CLASS] == '') {
                $fe->attributes[FE_BUTTON_CLASS] = 'btn-default';
            }
            $fe->attributes[FE_BUTTON_CLASS] = 'btn ' . $fe->attributes[FE_BUTTON_CLASS];

            if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
                $fe->attributes[FE_BUTTON_CLASS] .= ' disabled';
            }

            return $this->renderMultiButtons($fe, $renderMode);
        } else {
            return $this->renderMultiPlain($fe, $renderMode);
        }
    }


    /**
     * Build as many Checkboxes as items.
     *
     * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with
     *         <div class=checkbox> depending on if they aligned horizontal or vertical
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function renderMultiButtons(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {
        if ($fe->attributes[FE_DYNAMIC_UPDATE] === 'yes') $fe->htmlAttributes[FE_DATA_LOAD] = 'data-load';

        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $fe->htmlAttributes[ATTRIBUTE_DISABLED] = 'disabled';
        }

        $html = '';
        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);
        $btnGroupId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_BUTTON_GROUP;

        for ($ii = 0, $jj = 1; $ii < count($fe->itemKeys); $ii++, $jj++) {

            $attribute = $fe->htmlAttributes;
            $classActive = '';

            $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($fe->htmlAttributes[HTML_ATTR_NAME], $ii, true);
            $attribute[HTML_ATTR_ID] = HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii);
            $attribute[HTML_ATTR_NAME] = $htmlFormElementNameUniq;
            $attribute[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE] . '-' . $ii;
            $attribute = Support::arrayToXMLAttributes($attribute);

            if (isset($fe->attributes[FE_AUTOFOCUS])) {
                $attribute .= Support::doAttribute(FE_AUTOFOCUS, $fe->attributes[FE_AUTOFOCUS]);
                unset ($fe->attributes[FE_AUTOFOCUS]);
            }

            $attribute .= Support::doAttribute(HTML_ATTR_VALUE, $fe->itemKeys[$ii], false);

            // Check if the given key is found in field.
            $values = explode(',', $fe->value); // Defines which of the checkboxes will be checked.
            if (false !== array_search($fe->itemKeys[$ii], $values)) {
                $attribute .= Support::doAttribute(HTML_ATTR_CHECKED, HTML_ATTR_CHECKED);
                $classActive = ' active';
            }

            // '&nbsp;' - This is necessary to correctly align an empty input.
            $valueShow = ($fe->itemValues[$ii] === '') ? '&nbsp;' : $fe->itemValues[$ii];

            $inputClass = implode(' ', $fe->cssClasses);
            $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
            $htmlElement = '<input ' . $attribute . $classAttr . '>' . $valueShow . '<span class="checkmark" aria="hidden"></span>';

            $labelAttribute = Support::doAttribute('title', $fe->attributes[FE_TOOLTIP]);
            $labelAttribute .= Support::doAttribute('class', $fe->attributes[FE_BUTTON_CLASS] . $classActive);
            $labelAttribute .= Support::doAttribute('id', HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL));
            $htmlElement = Support::wrapTag("<label $labelAttribute>", $htmlElement, true);

            $html .= $htmlElement;
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_SUB_ELEMENTS][$ii] = $htmlElement;
        }
        if ($renderMode === RENDER_MODE_JSON) {
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_ELEMENT_TO_REPLACE] = HTML_LABEL;
            return $json;
        }
        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'extra-button-btn-group');
        $html .= $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML];
        $btnGroupClass = $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] === '' ? 'btn-group' : 'btn-group input-group';
        $html = Support::wrapTag('<div class="' . $btnGroupClass . '" data-toggle="buttons" id="' . $btnGroupId . '">', $html);

        return $html;
    }

    /**
     * Build as many Checkboxes as items.
     *
     * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with <div
     * class=checkbox> depending on if they aligned horizontal or vertical.
     *
     *  <div class="col-md-6" required="required">
     *    <label class="checkbox-inline" id="1039-21332-1-0-0-l">
     *      <input checked="checked" id="1039-21332-1-0-0" name="groups-1[]" required="required" type="checkbox" value="1">
     *        label1
     *        <span aria="hidden" class="checkmark"></span>
     *      </label>
     *
     *    <label class="checkbox-inline" id="1039-21332-1-0-2-l">
     *      <input id="1039-21332-1-2-0" name="groups-1[]"
     *        required="required" type="checkbox" value="2">
     *        label2
     *        <span aria="hidden" class="checkmark"></span>
     *    </label>
     *  </div>
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function renderMultiPlain(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {
        if ($fe->attributes[FE_DYNAMIC_UPDATE] === 'yes') $fe->htmlAttributes[FE_DATA_LOAD] = 'data-load';

        $minWidth = $fe->attributes[F_FE_MIN_WIDTH] ?? 0;
        $attributeBaseLabel = $minWidth > 0 ? Support::doAttribute('style', 'min-width: ' . $minWidth . 'px;') : '';

        $html = '';
        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);
        $htmlInputId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT;

        $orientation = ($fe->attributes[FE_MAX_LENGTH] > 1) ? ALIGN_HORIZONTAL : ALIGN_VERTICAL;
        $checkboxClass = ($orientation === ALIGN_HORIZONTAL) ? 'checkbox-inline' : 'checkbox';
        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $checkboxClass .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled'
        }


        $br = '';
        $replaceBrFlag = false;

        for ($ii = 0, $jj = 1; $ii < count($fe->itemKeys); $ii++, $jj++) {
            $attribute = $fe->htmlAttributes;
            $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($fe->htmlAttributes['name'], $ii, true);
            $attribute[HTML_ATTR_ID] = HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii);
            $attribute[HTML_ATTR_NAME] = $htmlFormElementNameUniq;
            $attribute[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE] . '-' . $ii;

            if (isset($fe->attributes[FE_AUTOFOCUS])) {
                $attribute[FE_AUTOFOCUS] = $fe->attributes[FE_AUTOFOCUS];
                unset ($fe->attributes[FE_AUTOFOCUS]);
            }

            $attribute[HTML_ATTR_VALUE] = $fe->itemKeys[$ii];

            // Check if the given key is found in field.
            $values = explode(',', $fe->value); // Defines which of the checkboxes will be checked.
            if (false !== array_search($fe->itemKeys[$ii], $values)) {
                $attribute[FE_CHECKBOX_CHECKED] = FE_CHECKBOX_CHECKED;
            }

            // '&nbsp;' - This is necessary to correctly align an empty input.
            $valueShow = ($fe->itemValues[$ii] === '') ? '&nbsp;' : $fe->itemValues[$ii];

            $inputClass = implode(' ', $fe->cssClasses);
            $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
            $htmlElement = '<input ' . Support::arrayToXMLAttributes($attribute) . $classAttr . '>' . $valueShow . '<span class="checkmark" aria="hidden"></span>';

            $checkboxLabelId = HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL);
            $htmlElement = Support::wrapTag("<label class=\"$checkboxClass\" $attributeBaseLabel id=\"$checkboxLabelId\">", $htmlElement, true);

            // control orientation
            if ($fe->attributes[FE_MAX_LENGTH] > 1) {
                if ($jj == $fe->attributes[FE_MAX_LENGTH]) {
                    $jj = 0;
                    $br = '<br>';
                    $replaceBrFlag = true;
                } else {
                    $br = '';
                }
            }
            $html .= $htmlElement . $br;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_SUB_ELEMENTS][$ii] = $htmlElement . $br;
        }

        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'btn-group-plain-bottom-right');
        $html .= $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML];

        if ($fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] !== '') {
            $html = Support::wrapTag('<div class="btn-group-plain-wrapper">', $html);
        }

        // Wrap in container div for inline filter mode (qfq-inline-filter class for data attributes)
        $isFilterMode = $fe->attributes[FE_INLINE_FILTER] ?? false;
        if ($isFilterMode) {
            $html = Support::wrapTag('<div class="qfq-inline-multi-checkbox qfq-inline-filter">', $html);
        }

        if ($renderMode == RENDER_MODE_JSON) {
            $apiElementToReplace = ($replaceBrFlag) ? HTML_LABEL . ', ' . HTML_BR : HTML_LABEL;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_ELEMENT_TO_REPLACE] = $apiElementToReplace;
            return $json;
        }
        return $html;
    }

    /** Build a single 'checkbox' like element where there can be more than 2 states
     * All the option are in the element attribute 'data-options' and the actual switching happens with JS when a div with the class 'multiStateCheckbox' is found.
     * <label class="multiStateCheckboxLabel">
     *      <input id="qfq-form-99-9999-9-9999-9" name="Input1-1" data-hidden="no" data-disabled="no" data-required="no">
     *      <div class="multiStateCheckbox"
     *          data-options='[{"value":"no","label":"No","icon":"fa-times","iconColor":"white","color":"#2196f3"}]'
     *          data-current-index="0"
     *          data-selected-value="no"
     *          style="background-color: #2196f3;"
     *          >
     *          <i class="multiStateCheckboxIcon fas fa-times" style="color: white"></i>
     *      </div>
     *      <span class="multiStateCheckboxSpan">No</span>
     * </label>
     *
     * @throws \UserFormException
     * @throws \CodeException
     * @throws \UserReportException
     */
    private function renderMultiStateCheckBox($fe): string {

        if ($fe->attributes[FE_DYNAMIC_UPDATE] === 'yes') $fe->htmlAttributes[FE_DATA_LOAD] = 'data-load';
        $fe->htmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE];

        // Set Defaults for the first shown option
        $hasValue = !empty($fe->value);
        $defaultBg = $hasValue ? MULTI_STATE_CHECKBOX_COLOR_BLUE : MULTI_STATE_CHECKBOX_COLOR_WHITE;
        $defaultIconColor = $hasValue ? "" : MULTI_STATE_CHECKBOX_COLOR_WHITE;

        $parsedOptions = $fe->attributes[FE_MULTI_CHECKBOX_ITEMS];
        $divID = $fe->htmlAttributes[HTML_ATTR_ID] . HTML_ID_EXTENSION_DIV;
        $readOnly = $fe->attributes[FE_MODE] == FE_MODE_READONLY ? ' qfq-disabled' : '';

        if (!is_array($parsedOptions) || empty($parsedOptions)) {
            throw new \UserFormException('FormElement: checkboxMode=multiState - requires ' . FE_MULTI_CHECKBOX_ITEMS . ' parameter or ENUM/SET column.');
        }

        // If a value has been selected then move that to the first position in the array
        if ($hasValue) {
            $storedValue = $fe->value;
            foreach ($parsedOptions as $index => $option) {
                if (trim($option[MULTI_STATE_CHECKBOX_VALUE]) === $storedValue) {
                    $selectedOption = $parsedOptions[$index];
                    unset($parsedOptions[$index]);
                    array_unshift($parsedOptions, $selectedOption);
                    break;
                }
            }
        }

        $optionsJson = htmlspecialchars(json_encode($parsedOptions, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        // Get First option specs
        $firstOption = $parsedOptions[0];
        $firstBg = empty($firstOption[MULTI_STATE_CHECKBOX_BACKGROUND_COLOR]) ? $defaultBg : $firstOption[MULTI_STATE_CHECKBOX_BACKGROUND_COLOR];
        $firstIcon = $firstOption[MULTI_STATE_CHECKBOX_ICON];
        $firstValue = $firstOption[MULTI_STATE_CHECKBOX_VALUE];
        $firstLabel = $firstOption[MULTI_STATE_CHECKBOX_LABEL];
        $firstIconColor = empty($firstOption[MULTI_STATE_CHECKBOX_ICON_COLOR]) ? $defaultIconColor : $firstOption[MULTI_STATE_CHECKBOX_ICON_COLOR];

        // Create hidden input element
        $htmlHidden = HelperFormElement::buildNativeHidden($fe->htmlAttributes[HTML_ATTR_NAME], $firstOption[MULTI_STATE_CHECKBOX_VALUE]);
        Store::getInstance()->setVar($fe->htmlAttributes[HTML_ATTR_NAME], $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false);
        $htmlElement = '<input ' . Support::arrayToXMLAttributes($fe->htmlAttributes) . '>';

        // Build HTML with given specs
        $html = <<<EOD
<label class="multiStateCheckboxLabel">
    $htmlElement
    <div class="multiStateCheckbox $readOnly"
         id="$divID"
         data-options='$optionsJson'
         data-current-index="0"
         data-selected-value="{$firstValue}"
         style="background-color: {$firstBg};">
        <i class="multiStateCheckboxIcon fas {$firstIcon}" style="color: {$firstIconColor}"></i>
    </div>
    <span class="multiStateCheckboxSpan">{$firstLabel}</span>
</label>
EOD;

        return $html;
    }


    /**
     * @param AbstractFormElement $fe
     * @return array
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderJson(AbstractFormElement $fe): array {
        $formJson = array();

        switch ($fe->attributes[FE_CHECKBOX_MODE]) {

            case FE_CHECKBOX_MODE_SINGLE:
                $formJson = $this->renderSingle($fe, RENDER_MODE_JSON);
                break;
            case FE_CHECKBOX_MODE_MULTI:
                $formJson = $this->renderMulti($fe, RENDER_MODE_JSON);
                break;
            case FE_CHECKBOX_MODE_MULTI_STATE:
                $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
                $json = HelperFormElement::getFormElementForJson($fe, $wrap);

                $json[API_ELEMENT_UPDATE][$fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_DIV][API_ELEMENT_ATTRIBUTE]['class'] = 'multiStateCheckbox';

                if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
                    $json[API_ELEMENT_UPDATE][$fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_DIV][API_ELEMENT_ATTRIBUTE]['class'] .= ' qfq-disabled';
                }

                $formJson = $json;
                break;
            default:
                $formJson = parent::renderJson($fe);
                break;
        }
        return $formJson;
    }
}