<?php

namespace TwigExtension;

use Helpers\Outil\Roles;
use Psr\Container\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Helpers\Trad\ITrad;
use PDO;
use Twig\TwigFunction;
use ReflectionClass;
use Helpers\Pagination\PaginatorGestion;
use Helpers\Additional\Specifique\Specifique;
use Modules\Outil\Repository\Multiselect;
use Entity\Model\Sectimpu;
use Entity\Model\Codecomp;
use Entity\Model\Sscptana;
use stdClass;
use Entity\Model\Paravrac;
use GuzzleHttp\Utils;
use Helpers\Form\FormBuilder;
use Helpers\Outil\ArrayHelper;
use Helpers\Outil\Date;
use Helpers\Outil\FloatHelper;
use Helpers\Outil\ZoomHelper;
use Helpers\Parametres\Constante;
use Modules\Evaluation\Data\Parametre;
use Modules\GlobalApplication\Repository\Societe;
use Skeleton\Renderer\RendererInterface;
use Skeleton\Router;
use DI\Container;
use Helpers\Outil\Sql;
use Modules\Ajax\Repository\Listes;
use Entity\Entity;
use Helpers\Form\AbsFormService;

class FormExtension extends AbstractExtension
{
    protected ITrad $trad;


    public function __construct(protected Router $router, protected PDO $pdo, protected ContainerInterface $container)
    {
        $this->trad = $container->get(ITrad::class);
    }

    public function getFunctions()
    {
        return [
            new TwigFunction('input', $this->input(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputText', $this->inputText(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputPassword', $this->inputPassword(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputDate', $this->inputDate(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputDevise', $this->inputDevise(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputZoom', $this->inputZoom(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputSelect', $this->inputSelect(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputTextarea', $this->inputTextarea(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputSwitch', $this->inputSwitch(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputTreeview', $this->inputTreeview(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputZoomAdvance', $this->inputZoomAdvance(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputAdvance', $this->inputAdvance(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('multiSelect', $this->multiSelect(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('inputHeure', $this->inputHeure(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            new TwigFunction('updateValue', $this->updateValue(...), [
                'is_safe' => [
                    'html'
                ]
            ]),
            
            new TwigFunction(
                'formInput',
                $this->formInput(...),
                ['is_safe' => ['html']]
            ),
            new TwigFunction(
                'labelSuffixe',
                $this->labelSuffixe(...),
                ['is_safe' => ['html']]
            ),
            new TwigFunction(
                'createInputGroup',
                $this->createInputGroup(...)
            ),
            new TwigFunction(
                'getFileSizeMax',
                $this->getFileSizeMax(...)
            ),
            //             new \Twig\TwigFunction('sessionGet', [
            //                 $this,
            //                 'sessionGet'
            //             ], [
            //                 'is_safe' => [
            //                     'html'
            //                 ]
            //             ]),



        ];
    }

    // TODO : ajouter l'inputAttr sur les input pour lesquels ça n'existe pas encore

    /**
     * Array :
     *  global attribut
     *      titre           : label input
     *      *name            : name + id input   (obli)
     *      value           : value input
     *      placeholder     : placeholder input
     *      myFunction      : fonction js supplementaire
     *      myParams        : attribut de la fonction js
     *      option          : readOnly ou Disabled
     *      ________
     * text attribut
     *      length          : taille maximum possible dans un input (a la saisie)
     *      ________
     * share attribut
     *      pathValidator   : validator
     *      paramsValidator : valeur validator
     *      addClass        : classe CSS supplementaire
     *      addStyle        : style supplumentaire
     *      focusOut
     *      numerique       : active la fonction numerique (separateur de milier)
     *      obligatoire     : active l'étoile si oblig
     *      bulle           : active le bulle filter pour les filtres
     *      iconeLabel      : nom de l'icone (repertoire)
     *      idIconeLabel    : l'id de l'icone
     *      obligatoire     : si le champs est obligatoire (false par defaut)
     *      myFuncValidator : fonction js supplémentaire apres le validator (si celuic si est correcte).
     *      paramFuncValidator : attribut de la fonction js supplémentaire
     *      ________
     * select attribut
     *      *listeValue     : liste value select (obli)
     *      optionVide      : active un attribut vide ou non
     *      textVide        : donne eventuellement un nom au champs vide
     *      affichageId     : Affiche ou non le code d'un libelle dans la liste
     *      ________
     * switch attribut
     *      textCheck       : Value de l'input switch si il est check   (Oui par defaut)
     *      textUnCheck     : Value de l'input switch si il est uncheck (Non par defaut)
     *      ________
     * textArea attribut
     *      paramTextArea   : ajout un attribut 'rows' ou 'cols'
     *      ________
     * zoom attribut
     *      pahtZoom        : path de la liste
     *      valueTextZoom   : ??
     *      titleZoom       : titre de la popup
     *      idChamp         : id du champs a remplire (facultatif : uniquement si le champs est different de input_)
     *      paramZoom       : parametre du zoom
     *      idText          : id du champs texte a remplire (uniquement si ...)
     *      widthPopup      : taille de la popup (par defaut petite)
     *      Entity          : Entité de du zoom
     *      ________
     * File
     *      format          : format accepté (excel, image)
     *      ________
     * Multiselect attribut
     *     listeValue       : liste des valeurs
     *     listeObligatoire : liste des qui sont dans la colonne de droite (selectionné) et pas déplacable vers la liste de gauche.
     *     Entity           : en cas de multiselect entity
     *      ________
     * zoomAdvance attribut
     *     convertLibelle   : permet de charger une fonction pour convertir le code en LIBELLE a l'inialisation de l'input
     *     pathConvert      : path de convertion CODE en LIBELLE d'une entité
     *     entity           : Entité a convertir CODE/LIBELLE
     *     paramZoom        : parametre pour un zoom (exemple: HASTUTIL avec ACHETEUR=0x54)
     *     codeBDD          : CODE de l'entité  **
     *     libelleBDD       : LIBELLE de l'entité **
     *     ** si l'entité a une PrimaryKey & un PrimaryKey de déclaré, ils ne sont pas obligatoire
     * treeview
     *     siLink           : permet lié un code gestion a #sectiondimp (siLink)
     *     codeSte          : soit le code société, soit $('#<idInput societe>').val()
     *
     * @param array<mixed> $array
     **/
    public function inputAdvance(string $type, array $array): ?string
    {
        if (($array['paramsValidator'] ?? '') == '') {
            $array['paramsValidator'] = '{}';
        }

        if (($array['iconeLabel'] ?? '') == 'createur.png') {
            $array['iconeLabel'] = 'createur.svg';
        }

        if (strtoupper($type) == 'TEXT' || strtoupper($type) == 'TEXTE') {
            return $this->inputText(
                $array['titre'] ?? '',
                $array['name'],
                $array['value'] ?? '',
                $array['placeholder'] ?? '',
                $array['pathValidator'] ?? '',
                $array['paramsValidator'],
                $array['myFunction'] ?? '',
                $array['myParams'] ?? '',
                ($array['option'] ?? ''),
                ($array['addClass'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['focusOut'] ?? ''),
                ($array['numerique'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['addon'] ?? ''),
                ($array['bulle'] ?? false),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['labelStyle'] ?? ''),
                ($array['disabledField'] ?? false),
                ($array['clickSelect'] ?? false),
                ($array['onlyNumber'] ?? false),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['tooltipIconeLabel'] ?? ''),
                ($array['length'] ?? ''),
                ($array['numeric'] ?? ''),
                ($array['parameter'] ?? []) + [
                    'inputAttr' => ($array['inputAttr'] ?? [])
                ],
                '',
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'DATE') {
            return $this->inputDate(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['value'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['option'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                [
                    'inputAttr' => $array['inputAttr'] ?? [],
                ],
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'PASSWORD' || strtoupper($type) == 'MDP') {
            return $this->inputPassword(($array['titre'] ?? ''), $array['name'], ($array['value'] ?? ''), ($array['placeholder'] ?? ''), ($array['pathValidator'] ?? ''), $array['paramsValidator'], ($array['myFunction'] ?? ''), ($array['myParams'] ?? ''), ($array['option'] ?? ''), ($array['addStyle'] ?? ''), ($array['obligatoire'] ?? ''), ($array['myFuncValidator'] ?? ''), ($array['paramFuncValidator'] ?? ''), ($array['showPassword'] ?? ''), ($array['infos'] ?? ''));
        } elseif (strtoupper($type) == 'DEVISE') {
            return $this->inputDevise(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['value'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['DEVISE'] ?? $array['devise'] ?? ''),
                ($array['option'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['addCss'] ?? ''),
                [
                    'inputAttr' => $array['inputAttr'] ?? [],
                ],
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'SWITCH') {
            return $this->inputSwitch(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['value'] ?? ''),
                ($array['option'] ?? ''),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['textCheck'] ?? 'Oui'),
                ($array['textUnCheck'] ?? 'Non'),
                ($array['addStyle'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['styleText'] ?? ''),
                ($array['addClass'] ?? ''),
                true,
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['inputAttr'] ?? []),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'SELECT') {
            return $this->inputSelect(
                ($array['titre'] ?? ''),
                $array['name'],
                $array['listeValue'] ?? [],
                ($array['value'] ?? ''),
                ($array['option'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['optionVide'] ?? ''),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['affichageId'] ?? ''),
                ($array['textVide'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['bulle'] ?? false),
                ($array['tooltip'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['addCss'] ?? ''),
                ($array['inputAttr'] ?? []),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'TEXTAREA') {
            return $this->inputTextarea(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['value'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['option'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['paramTextArea'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['inputAttr'] ?? []),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'ZOOM') {
            if (isset($array['entity'])) {
                $entity = $array['entity'];
            } elseif (isset($array['Entity'])) {
                $entity = $array['Entity'];
            }

            return $this->inputZoom(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['pahtZoom'] ?? ''),
                ($array['titleZoom'] ?? ''),
                ($array['valueTextZoom'] ?? ''),
                ($array['value'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['idChamp'] ?? ''),
                ($array['paramZoom'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['option'] ?? ''),
                ($array['idText'] ?? ''),
                ($array['widthPopup'] ?? ''),
                ($entity ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['bulle'] ?? false),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['clickSelect'] ?? false),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['addClass'] ?? ''),
                $array['inputAttr'] ?? [],
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'ZOOMADVANCE') {
            return $this->inputZoomAdvance(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['pahtZoom'] ?? ''),
                ($array['paramZoom'] ?? ''),
                ($array['value'] ?? ''),
                ($array['convertLibelle'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['option'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['pathConvert'] ?? ''),
                ($array['entity'] ?? ''),
                ($array['codeBDD'] ?? ''),
                ($array['libelleBDD'] ?? ''),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['widthPopup'] ?? ''),
                ($array['titleZoom'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['valueTexteZoom'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['clickSelect'] ?? false),
                ($array['paramConvertLibelle'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['addCss'] ?? ''),
                ($array['bulle'] ?? ''),
                ($array['titreHidden'] ?? ''),
                $array['inputAttr'] ?? [],
                $array['faceAttr'] ?? [],
                $array['htmlLabelBlock'] ?? '',
                $array['codeSte'] ?? '',
                $array['tsDon'] ?? '',
                ($array['infos'] ?? ''),
                $array,
            );
        } elseif (strtoupper($type) == 'RADIO') {
            return $this->inputRadio(
                $array['name'],
                ($array['titre'] ?? ''),
                $array['value'],
                ($array['checked'] ?? false),
                ($array['option'] ?? ''),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['addClass'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['styleLabel'] ?? ''),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'TREEVIEW') {
            return $this->inputTreeview(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['pathTreeview'] ?? ''),
                ($array['paramsTreeview'] ?? ''),
                ($array['titleTreeview'] ?? ''),
                ($array['valueTexteTreeview'] ?? ''),
                ($array['value'] ?? ''),
                ($array['convertLibelle'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['pathConvert'] ?? ''),
                ($array['entity'] ?? ''),
                ($array['codeBDD'] ?? ''),
                ($array['libelleBDD'] ?? ''),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['idChamp'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['option'] ?? ''),
                ($array['widthPopup'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['paramConvertLibelle'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['siLink'] ?? ''),
                ($array['codeSte'] ?? ''),
                ($array['sectimpu'] ?? ''),
                ($array['codeAffCG'] ?? ''),
                ($array['codeSteCG'] ?? ''),
                ($array['inputAttr'] ?? []),
                ($array['faceAttr'] ?? []),
                ($array['bulle'] ?? ''),
            );
        } elseif (strtoupper($type) == 'FILE') {
            return $this->inputFile(
                $array['name'],
                ($array['value'] ?? ''),
                ($array['format'] ?? ''),
                ($array['titre'] ?? ''),
                ($array['iconeLabel'] ?? ''),
                ($array['idIconeLabel'] ?? ''),
                ($array['option'] ?? ''),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'MULTISELECT') {
            return $this->multiSelect(
                $array['name'],
                ($array['titre'] ?? ''),
                $array['listeValue'] ?? [],
                $array['post'] ?? [],
                $array['listeObligatoire'] ?? [],
                $array['addClass'] ?? '',
                $array['Entity'] ?? '',
                $array['typeListe'] ?? null,
                ($array['infos'] ?? []),
            );
        } elseif (strtoupper($type) == 'CAPTCHA') {
            return $this->inputCaptcha(
                $array['idCaptcha'],
                $array['name'],
                ($array['titreActif'] ?? true),
                ($array['infos'] ?? ''),
            );
        } elseif (strtoupper($type) == 'HEURE') {
            return $this->inputHeure(
                ($array['titre'] ?? ''),
                $array['name'],
                ($array['value'] ?? ''),
                ($array['placeholder'] ?? ''),
                ($array['pathValidator'] ?? ''),
                ($array['paramsValidator']),
                ($array['myFunction'] ?? ''),
                ($array['myParams'] ?? ''),
                ($array['addStyle'] ?? ''),
                ($array['option'] ?? ''),
                ($array['obligatoire'] ?? ''),
                ($array['myFuncValidator'] ?? ''),
                ($array['paramFuncValidator'] ?? ''),
                ($array['infos'] ?? ''),
            );
        }

        return null;
    }

    /**
     * Summary of inputCaptcha
     * @param mixed $idCaptcha
     * @param mixed $inputCaptcha
     * @param mixed $titre
     * @param string $infos
     * @return string
     */
    public function inputCaptcha($idCaptcha, $inputCaptcha, $titre = true, string $infos = '')
    {
        $url  = $this->router->generateUri('Ajax.outil.captcha', ['idCaptcha' => $idCaptcha, 'inputCaptcha' => $inputCaptcha]);
        $trad = $this->trad;
        if ($infos != '') {
            $iconeInfos = '<span class="white-tooltip icone_input">
                <span class="infos_tooltip top-left">
                    <span class="tooltip-arrow"></span>' .
                $infos .
                '</span>
                <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
            </span>';
        }

        return '
            ' . ($titre
            ? '<label for="input_'
            . $inputCaptcha . '">'
            . $trad->t('Image de sécurité')
            . '<span class="obligatoire">*</span>'
            . ($iconeInfos ?? '')
            : '')
            . '</label>
            <input type="text" class="form-control form-control-sm" id="input_' . $inputCaptcha . '" name="' . $inputCaptcha . '" />
            <div class="captchaBlock clearfix">    
                <img id="image_' . $inputCaptcha . '" src="' . $url . '?' . random_int(0, 999999999) . '"/>
                <button type="button" title="' . $trad->t('Renouveler l\'image') . '" class="captcha_btn"  id="refresh_' . $inputCaptcha . '" onclick="changeCaptcha(\'image_' . $inputCaptcha . '\');"/></button>
            </div>
            <script>
                function changeCaptcha(input)
                {
                    var date = new Date();
                    $(\'#\'+input).attr(\'src\', \'' . $url . '/\'+date.getTime());
                }
            </script>
        ';
    }

    public function inputRadio(
        mixed $name,
        ?string $titre = '',
        ?string $value = '',
        ?bool $checked = false,
        ?string $option = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $addClass = '',
        ?string $addStyle = '',
        ?string $styleLabel = '',
        string $infos = ''
    ): string {
        $html = '';

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }

        if ($infos != '') {
            $iconeInfos = '<span class="white-tooltip icone_input">
                <span class="infos_tooltip top-left">
                    <span class="tooltip-arrow"></span>' .
                $infos .
                '</span>
                <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
            </span>';
        }

        if ($value != '') {
            $html .= '<label style="' . $styleLabel . '" for="radio_' . $value . '">' . $titre . ($iconeInfos ?? '') . '</label>';
        }
        $html .= '
                    <input style = "' . $addStyle . '" class="radio radioObjet ' . $addClass . '" type="radio" id="radio_' . $value . '" name="' . $name . '" ' . $option . ' onchange="' . $myFunction . ';" value="' . $value . '"';

        if ($checked) {
            $html .= ' checked ';
        }


        return $html . '>';
    }

    public function input(
        string $titre,
        string $name,
        ?string $value = '',
        string $option = '',
        string $pathValidator = '',
        ?string $params = '',
        ?bool $zoom = false,
        ?string $pathZoom = '',
        ?string $titleZoom = '',
        ?string $valueTexteZoom = '',
        ?string $type = '',
        ?string $myFunction = '',
        ?string $myParams = ''
    ): string {
        $value = htmlspecialchars($value ?? '');

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }

        $label = '';
        if ($titre) {
            $label = '<label for="input_' . $name . '">' . $titre . '</label>';
        }


        if ($type == "date") {
            $type = 'datepicker';
        }
        if ($type == "devise") {
            $type = 'devise';
        }
        if ($zoom) {
            $type = 'zoom';
        }

        $html = '<div class="input-wrapper input-custom">' . $label . ' 
            <div class="bs-col relative">
            <input type="text" class="form-control form-control-sm  ' . $type . '" data-toggle="tooltip" ' . $option . '
            data-placement="top"
                data-html="true"
                    title="" id="input_' . $name . '" name="' . $name . '" onchange="validatorAjax(\'' . $pathValidator . '\', ' . $params . ',\'' . $name . '\');' . $myFunction . ';" value="' . $value . '">';


        if ($zoom) {
            $html .= '<span class="glyphicon glyphicon-search" onclick="ajaxPopup (\'' . $pathZoom . '\', \'' . $titleZoom . '\', \'input_' . $name . '\', \'text_' . $name . '\')"></span>';
        }

        if ($type == 'devise') {
            $html .= '<span class="input-group-addon span_devise_change">' . $_SESSION['parametrage']['DEVISE_BASE'] . '</span>';
        }


        return $html . '</div></div>';
    }

    public function sessionGet(): void
    {

        $_SESSION['Fournisseur']['mode'] = 'modification';
    }

    /**
     * @param string $titre         obligatoire
     * @param string $name          obligatoire
     * @param ?string $value         valeur pour édition
     * @param mixed $paramsValidator
     * @param array{inputAttr?:string[],wrapperAttr?:array<string>,validator?:array<mixed>} $parameter
     * @param bool   $onlyNumber => une fois le paramètre passer à true le champ n'acceptera rien d'autre que des chiffres
     */
    public function inputText(
        string $titre,
        string $name,
        ?string $value = '',
        ?string $placeholder = '',
        ?string $pathValidator = '',
        $paramsValidator = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $option = '',
        ?string $addClass = '',
        ?string $addStyle = '',
        ?bool $focusOut = false,
        ?bool $numerique = false,
        ?bool $obligatoire = false,
        ?string $addon = '',
        ?bool $bulle = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?string $labelStyle = '',
        ?bool $disabledField = false,
        ?bool $clickSelect = false,
        ?bool $onlyNumber = false,
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $tooltipIconeLabel = '',
        ?string $length = '',
        ?bool $numeric = false,
        ?array $parameter = [],
        ?string $clipboard = '',
        ?string $infos = ''
    ): string {
        $idInput = str_replace('|', '', $name);

        if ($bulle) {
            $_SESSION['bulleFiltre'][$name]['titre'] = $titre;
            $_SESSION['bulleFiltre'][$name]['value'] = htmlspecialchars($value ?? '');
        }


        $html = '<div class="input-wrapper input-text">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }
        $nameJquery = str_replace('#', '\\\#', $idInput);

        if ($infos != '') {
            $iconeInfos = '<span class="white-tooltip icone_input">
                <span class="infos_tooltip top-left" style="font-weight: normal;">
                    <span class="tooltip-arrow"></span>' .
                $infos .
                '</span>
                <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
            </span>';
        }
        if ($iconeLabel != '') {
            $hidden = false;
            if (strtoupper((string) $option) == 'READONLY'
                || strtoupper((string) $option) == 'DISABLED'
            ) {
                $hidden = true;
            }
            if ($tooltipIconeLabel != '') {
                $tooltipIconeLabel =
                    '<span class="infos_tooltip top-left">
                    <span class="tooltip-arrow"></span>' .
                    $tooltipIconeLabel .
                    '</span>';
            }

            $icone = '<span class="white-tooltip icone_input" id="' . htmlspecialchars((string) $idIconeLabel) . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                ' . $tooltipIconeLabel . '
                <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
            </span>';

            if ($iconeLabel == 'pastille') {
                $icone = '<span class="white-tooltip icone_input">
                    <div class="img_cercle ' . htmlspecialchars((string) $idIconeLabel) . '"></div>
                </span>';
            }
        }
        $html .= ' <label style="' . $labelStyle . ' ' . (empty($titre) ? 'display: none' : '') . '" for="input_' . $idInput . '">'
            . $titre . $this->labelSuffixe($obligatoire)
            . ($iconeInfos ?? '')
            . ($icone ?? '')
            . '</label>';


        $spiterMillier = '';
        if ($numerique) {
            $spiterMillier = 'separateurMilier(this);';
        }

        if (empty($paramsValidator)) {
            $paramsValidator = '{}';
        }

        if (!is_string($paramsValidator)) {
            $paramsValidator = json_encode($paramsValidator);
        }

        if ($pathValidator != '') {
            $pathValidator = 'validatorAjax(\'' . $pathValidator . '\', ' . $paramsValidator . ',\'' . $nameJquery . '\', \'\', \'\', \'' . $myFuncValidator . '\', \'' . str_replace('"', "\\'", $paramFuncValidator) . '\');';
        }

        $inputAttr = [
            'id' => 'input_' . $idInput,
            'type' => 'text',
            'name' => $name,
            'value' => $value,

            'style' => $addStyle . ' ' . ($numerique ? 'text-align: right;' : ''),
            'class' => 'bs-col form-control form-control-sm  ' . $addClass . ' ' . ($numeric ? 'numeric' : ''), // TODO : merge with class of  $parameter['inputAttr']

            'data-toggle' => 'tooltip',
            'data-placement' => 'top',
            'data-html' => 'true',

            'placeholder' => $placeholder,
            'title' => '',

            'onchange' =>
                $spiterMillier . $pathValidator . $myFunction . ';'
                . ($parameter['inputAttr']['onchange'] ?? ''),
        ] + ($parameter['inputAttr'] ?? []); //!\ Addition order is important

        if ($disabledField == true) {
            $inputAttr['disabled'] = '';
        }
        if ($onlyNumber == true) {
            $inputAttr['oninput'] = 'this.value = this.value.replace(/[^0-9.]/g, \'\').replace(/(\..*)\./g, \'\');';
        }
        if ($length) {
            $inputAttr['maxlength'] = $length;
        }
        if ($clickSelect) {
            $inputAttr['onclick'] = 'this.select();';
        }
        if ($focusOut) {
            $inputAttr['onfocusout'] = 'validatorAjax('
                . json_encode($pathValidator) . ', '
                . $paramsValidator . ','
                . json_encode($nameJquery) . ', "", "", '
                . json_encode($myFuncValidator) . ','
                . json_encode($paramFuncValidator)
                . ');'
                . $myFunction . ';';
        }


        $html .= '<input ' . $this->attr($inputAttr) . ' ' . $option . '>';

        if ($addon != '') {
            $html .= '<span class="input-group-addon">' . $addon . '</span>';
        }

        if ($clipboard !== '') {
            $html .= '<button
                type="button"
                class="button principal ml-base"
                id="button-to-clipboard"
                onclick="copyToClipBoard(\'' . $inputAttr['id'] . '\')"
                >
                ' . $clipboard . '
            </button>';
        }

        return $html . '</div>';
    }

    public function inputPassword(
        string $titre,
        string $name,
        ?string $value = '',
        ?string $placeholder = '',
        string $pathValidator = '',
        mixed $params = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $option = '',
        ?string $addStyle = '',
        ?bool $obligatoire = false,
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?bool $showPassword = false,
        string $infos = ''
    ): string {
        unset($placeholder);
        $value = htmlspecialchars($value ?? '');

        $html = '<div class="input-wrapper input-text">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }
        $nameJquery = str_replace('#', '\\\#', $name);

        if ($infos != '') {
            $iconeInfos = '<span class="white-tooltip icone_input">
                <span class="infos_tooltip top-left">
                    <span class="tooltip-arrow"></span>' .
                $infos .
                '</span>
                <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
            </span>';
        }

        if ($titre) {
            $html .= '
            <label>' . $titre . $this->labelSuffixe($obligatoire) . ($iconeInfos ?? '') . '</label>';
        }

        if (!is_string($params)) {
            $params = json_encode($params);
        }

        $html .= '<div class="divPassword bs-col"><input type="password" class="form-control form-control-sm  ' . $addStyle . '" data-toggle="tooltip"
            data-placement="top"
                data-html="true"
                    title="" id="input_' . $name . '" name="' . $name . '" ' . $option . ' onchange="validatorAjax(\'' . $pathValidator . '\', ' . ((!$params) ? '\'\'' : $params) . ',\'' . $nameJquery . '\', \'\', \'\', \'' . $myFuncValidator . '\', \'' . str_replace('"', "\\'", $paramFuncValidator) . '\');' . $myFunction . '" value="' . $value . '">';

        if ($showPassword) {
            $html .= '<img class="iconePassword" src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/eye.png" style="opacity: 0.4; width: 18px !important">
                    <script>
                        $( document ).ready(function() {
                            $(\'#input_' . $name . ' + .iconePassword\').click(function(){
                                var input = $(this).parent().find(\'input\');
                                input.attr("type") === "password" ? input.attr(\'type\', \'text\') : input.attr(\'type\', \'password\');
                                input.attr("type") === "password" ? $(this).attr(\'src\', "' . $this->container->get('baseUrl') . 'IconeV2/Misc/eye.png") : $(this).attr(\'src\', "' . $this->container->get('baseUrl') . 'IconeV2/Misc/eye-slash.png");
                            });
                        });
                   	</script>';
        }

        return $html . '</div></div>';
    }

    /**
     * @param string|array<mixed>|null $params
     * @param array<mixed> $parameter
     */
    public function inputDate(
        string $titre,
        string $name,
        ?string $value = '',
        ?string $placeholder = '',
        ?string $pathValidator = '',
        $params = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $addStyle = '',
        mixed $option = '',
        ?bool $obligatoire = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?array $parameter = [],
        ?string $infos = ''
    ): string {

        $idInput = str_replace('|', '', $name);

        $_SESSION['bulleFiltre'][$name]['titre'] = $titre;
        $_SESSION['bulleFiltre'][$name]['value'] = htmlspecialchars($value ?? '');


        $html = '<div class="input-wrapper input-date">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }
        $nameJquery = str_replace('#', '\\\#', $idInput);
        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;
                if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . htmlspecialchars((string) $idIconeLabel) . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="input_' . $idInput . '">'
                . $titre
                . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }

        $datepicker = false;
        if ($option === true || !in_array($option, ['disabled', 'readonly', 'readOnly'])) {
            $datepicker = true;
        }

        if (!is_string($params)) {
            $params = Utils::jsonEncode($params);
        }

        $attr = ($parameter['inputAttr'] ?? []) + [
            'class' => 'form-control form-control-sm  ' . ($datepicker ? 'datepicker' : '') . ' ' . $addStyle,
            'data-datepicker' => '',
            'placeholder' => $placeholder,
            'id' => 'input_' . $idInput,
            'name' => $name,
            'value' => $value,

            'data-toggle' => 'tooltip',
            'data-placement' => 'top',
            'data-html' => 'true',

            'onchange' =>
                'formatDate(this,\'' . $_SESSION['DATE_FORMAT'] . '\');'
                . 'validatorAjax(\'' . $pathValidator . '\', ' . $params . ',\'' . $nameJquery . '\', \'\', \'\', \'' . $myFuncValidator . '\', \'' . str_replace('"', "\\'", $paramFuncValidator) . '\');'
                . $myFunction . ';',
        ];

        if (!empty($option)) {
            $attr[$option] = '';
        }


        $html .= '<div class="bs-col relative">
            <input type="text" ' . $addStyle . ' '
            . implode(' ', array_map(function (string $key, string $value): string {
                return $key . '="' . htmlspecialchars($value) . '"'; // TODO : escape ?
            }, array_keys($attr), $attr))
            . ' title="" />';

        return $html . '</div></div>';
    }

    /**
     * @param ?array<mixed> $parameter
     */
    public function inputDevise(
        string $titre,
        string $name,
        ?string $value = '',
        ?string $placeholder = '',
        ?string $pathValidator = '',
        mixed $paramsValidator = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $addStyle = '',
        ?string $devise = '',
        ?string $option = '',
        ?bool $obligatoire = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $addCss = '',
        ?array $parameter = [],
        ?string $infos = ''
    ): string {

        $idInput = str_replace('|', '', $name);

        $nameJquery = str_replace('#', '\\\#', $idInput);
        $html       = '<div class="input-wrapper input-devise">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }

        if ($devise == '') {
            $devise = $_SESSION['parametrage']['DEVISE_BASE'];
        }
        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;
                if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="input_' . $idInput . '">'
                . $titre . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }
        if (empty($paramsValidator)) {
            $paramsValidator = '{}';
        }
        if (!is_string($paramsValidator)) {
            $paramsValidator = json_encode($paramsValidator);
        }

        if (!is_string($paramFuncValidator)) {
            $paramFuncValidator = json_encode($paramFuncValidator);
        }

        $inputAttr =
            [

                'id' => 'input_' . $idInput,
                'type' => 'text',
                'name' => $name,
                'title' => '',
                'class' => 'form-control form-control-sm  devise numerique ' . $addStyle,
                'style' => $addCss,
                'onclick' => 'this.select();',
                'placeholder' => $placeholder,
                'data-toggle' => 'tooltip',
                'data-placement' => 'top',
                'data-html' => 'true',
                'onchange' => 'separateurMilier(this);validatorAjax('
                    . json_encode($pathValidator) . ', '
                    . $paramsValidator . ','
                    . json_encode($nameJquery) . ', \'\', \'\', '
                    . json_encode($myFuncValidator) . ', \''
                    . str_replace('"', "\\'", (string) $paramFuncValidator)
                    . '\');'
                    . $myFunction
                    . ';',
                'value' => $value,
            ] + ($parameter['inputAttr'] ?? []); //!\ Addition order is important

        $html .= '<div class="bs-col relative  bs-row flex-nowrap">
            <input ' . $this->attr($inputAttr) . '
                ' . $option . ' >';
        if (!empty($devise)) {
            $html .= '<span id="devise_' . $idInput . '" class="input-group-addon span_devise_change">' . $devise . '</span>';
        }

        return $html . '</div></div>';
    }

    /**
     * @param string $titre             obligatoire
     * @param string $name              obligatoire
     * @param string $pathZoom          obligatoire
     * @param string $titleZoom         obligatoire
     * @param ?string $value             valeur pour édition
     * @param mixed $paramsValidator
     * @param array<string,string> $inputAttr
     */
    public function inputZoom(
        string $titre,
        string $name,
        string $pathZoom,
        string $titleZoom,
        ?string $valueTexteZoom = '',
        ?string $value = '',
        ?string $placeholder = '',
        ?string $pathValidator = '',
        $paramsValidator = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $idChamp = '',
        mixed $paramsZoom = '',
        ?string $addStyle = '',
        ?string $option = '',
        ?string $idText = '',
        ?string $width_popup = 'modal_small',
        ?string $entity = '',
        ?bool $obligatoire = false,
        ?bool $bulle = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?bool $clickSelect = false,
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $addClass = '',
        $inputAttr = [],
        ?string $infos = ''
    ): string {

        $idInput = str_replace('|', '', $inputAttr['id'] ?? $name);

        if ($bulle) {
            $_SESSION['bulleFiltre'][$name]['titre'] = $titre;
            $_SESSION['bulleFiltre'][$name]['value'] = htmlspecialchars($value ?? '');
        }

        $autocomplete     = '';
        $dataAutocomplete = '';

        if ($entity != '') {
            $autocomplete     = 'autocomplete';
            $dataAutocomplete = 'data-autocomplete="' . $entity . '"';
        }

        $html        = '<div class="input-wrapper input-zoom">';
        $convertType = false;
        $nameInput   = "input_" . $idInput;
        if ($idChamp) {
            $nameInput   = $idChamp;
            $convertType = true;
        }

        $textInput = 'text_' . $name;
        if ($idText) {
            $textInput = $idText;
        }

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }

        if (empty($paramsZoom)) {
            $paramsZoom = '{}';
        }
        if (!is_string($paramsZoom)) {
            $paramsZoom = json_encode($paramsZoom);
        }
        // By default the value of the input is passed down with the other params (can be overrided)
        $paramsZoom = ", Object.assign({value: $('#input_" . $idInput . "').val()}, " . $paramsZoom . ")";

        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;

                if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="' . $nameInput . '">'
                . $titre
                . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }
        $nameJquery  = str_replace('.', '_', str_replace('#', '\\\#', $nameInput));
        $titreJquery = str_replace('#', '\\\#', (string) str_replace('|', '', $textInput));

        if ($option === 'desactiveSaisie') {
            $optionInput = 'readOnly';
            $style       = "background: white;";
        } else {
            $optionInput = $option;
            $style       = '';
        }

        $onclick = '';
        if ($clickSelect) {
            $onclick = 'onClick="this.select();"';
        }

        if (!is_string($paramsValidator)) {
            $paramsValidator = json_encode($paramsValidator);
        }

        $html .= '<div class="bs-col relative">
        <input ' . $onclick . ' ' . $optionInput . '
            ' . $this->attr([
                'type' => 'text',
                'class' =>
                    'form-control form-control-sm zoom '
                    . $addStyle . ' ' . $autocomplete
                    . ' ' . ($inputAttr['class'] ?? ''),
            ] + $inputAttr + [
                'id' => str_replace('.', '_', $nameInput),
                'name' => $name,
                'value' => $value,
                'style' => $style . ' ' . $addClass,
                'title' => '',
                'data-toggle' => 'tooltip',
                'data-placement' => 'top',
                'data-html' => 'true',
                'data-libelle' => '',
                'placeholder' => $placeholder,
                'data-autocomplete' => $entity ?? '',
                'onchange' => ($pathValidator ?
                    'validatorAjax(\''
                    . $pathValidator . '\', '
                    . $paramsValidator . ',\''
                    . $nameJquery . '\', \''
                    . $convertType . '\', \'\', \''
                    . $myFuncValidator . '\', '
                    . json_encode($paramFuncValidator)
                    . ');'
                    : ''
                )
                    . $myFunction
                    . ';',
            ]) . '>';

        $hiddenSpan = '';
        if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
            $hiddenSpan = 'style="display: none;"';
        }

        $html .= '<span id="zoom_' . $idInput . '" class="glyphicon glyphicon-search" onclick="'
            . htmlspecialchars(
                'ajaxPopup (\''
                . $pathZoom . '\','
                . json_encode($titleZoom) . ', \''
                . $nameJquery . '\', \''
                . $titreJquery . '\' '
                . $paramsZoom . ', \''
                . $width_popup
                . '\')'
            ) . '" ' . $hiddenSpan . '></span></div></div>';

        if ($entity != '') {
            $html .= "<script>
            $( '#" . $nameInput . "' ).autocomplete({
                source: function(requete, response){ // la fonction anonyme permet de maintenir une requête AJAX directement dans le plugin
            //console.log($('#'+this.element.context.id).data().autocomplete);
                        $.ajax({
                            url : '" . $this->router->generateUri('Ajax.AutoComplete.autocomplete') . "', // on appelle le script JSON
                            dataType : 'json', // on spécifie bien que le type de données est en JSON
                            type: 'POST',
                            data: {'search' : requete.term, 'entity' : $('#'+this.element.context.id).data().autocomplete},
                            
                            success : function(data){ 
                                response(data);// on se prépare à renvoyer les données réceptionnées grâce à l'évènement de succès
                            }
                        });
                    },
                    select: function(event, ui){
                        $.ajax({
                            url : '" . $this->router->generateUri('Ajax.AutoComplete.autocomplete') . "', // on appelle le script JSON
                            dataType : 'json', // on spécifie bien que le type de données est en JSON
                            type: 'POST',
                            data: {'value' : ui.item.label, 'entity' : event.target.attributes['data-autocomplete'].value},
                            
                            success : function(data){ 
                                var idValue = event.target.attributes['id'].value;

                                if($('#'+event.target.attributes['id'].value.replace('text_', 'input_')).length != 0 && '#'+event.target.attributes['id'].value.replace('text_', 'input_') != '#'+event.target.attributes['id'].value)
                                {
                                    var idHidden = event.target.attributes['id'].value.replace('text_', 'input_');

                                    $('#'+idHidden).val(data);
                                    $('#'+idValue).val(data);
                                }else
                                {
                                    $('#'+idValue).val(data);
                                }
                                
                                $( '#menu-lateral' ).focus();
                                $( '#'+idValue).focus();
                            }
                        });
                    
                    },
                    // [Dossier n°34705]
                    change: function(event, ui) {
                        if (ui.item) {
                            var idValue = event.target.attributes['id'].value;
                            var custom_tooltip = $('#'+idValue).parent().find('.sec-label-tooltip');
                            if (custom_tooltip.length > 0) {
                                custom_tooltip.text(ui.item.value);
                            }
                        } 
                    }
                });
                        </script>";
        }
        return $html;
    }

    /**
     * @param string $titre         facultatif
     * @param string $name          obligatoire
     * @param array<mixed> $liste_value    obligatoire liste cle/valeur pour les options du select
     * @param ?string $value         valeur pour édition
     * @param array<string,string> $inputAttr
     * {{ inputSelect($titre, $name, {test : "test", test1 : "test1"}) }}
     */
    public function inputSelect(
        ?string $titre = '',
        ?string $name = '',
        ?array $liste_value = [],
        ?string $value = '',
        ?string $option = '',
        ?string $pathValidator = '',
        ?string $params = '',
        ?bool $optionVide = false,
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $addStyle = '',
        ?bool $affichageId = true,
        ?string $textVide = '',
        ?bool $obligatoire = false,
        ?bool $bulle = false,
        ?string $tooltip = '',
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $addCss = '',
        $inputAttr = [],
        ?string $infos = ''
    ): string {

        $idInput = str_replace('|', '', $name);

        if ($bulle) {
            $_SESSION['bulleFiltre'][$name]['titre'] = $titre;
            $_SESSION['bulleFiltre'][$name]['value'] = $liste_value[$value] ?? '';
        }

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ');';
        } else {
            $myFunction = '';
        }

        $classTooltip = '';
        if ($tooltip != '') {
            $classTooltip = 'white-tooltip';
            $tooltip      =
                '<span class="infos_tooltip top-left text-left">
                <span class="tooltip-arrow"></span>' .
                $tooltip .
                '</span>';
        }

        $html = '<div class="input-wrapper input-select ' . $classTooltip . '" data-toggle="tooltip">' . $tooltip;

        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;
                if (strtoupper($option) == 'READONLY' || strtoupper($option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="input_' . $idInput . '">'

                . $titre
                . $this->labelSuffixe($obligatoire)
                . ($icone ?? '')
                . ($iconeInfos ?? '')
                . '</label>';
        }

        $nameJquery = str_replace('#', '\\\#', $idInput);
        $html .= '<select ' . $option . ' class="bs-col form-control ' . $addStyle . '" style="'
            . $addCss . '" id="input_' . $idInput . '"  name="' . $name . '"'
            . ($pathValidator != '' ?
                ' onchange="' . htmlspecialchars(
                    'validatorAjax('
                    . json_encode($pathValidator) . ','
                    . $params . ','
                    . json_encode($nameJquery) . ', \'\', \'\', '
                    . json_encode($myFuncValidator) . ', '
                    . json_encode($paramFuncValidator) . ');'
                    . $myFunction
                ) . '"' : ($myFunction != '' ? 'onchange="' . $myFunction . '"' : '')
            )
            . ' ' . $this->attr($inputAttr)
            . '>';

        if ($optionVide) {
            $html .= '<option value=""';
            if ($value == '') {
                $html .= ' selected ';
            }
            $html .= '>' . $textVide . '</option>';
        }
        foreach ($liste_value as $cle => $valeur) {
            if (is_array($valeur)) {
                $html .= '<option data-type="' . $valeur['data'] . '" value="' . htmlspecialchars($cle) . '"';
                if (trim((string)$value) === trim((string)$cle) || $value === $cle) {
                    $html .= 'selected';
                }
                $html .= '>' . htmlentities($valeur['value'] . ' (' . $cle . ')') . '</option>';
            } else {
                $html .= '<option value="' . htmlspecialchars($cle) . '"';

                if (trim((string)$value) === trim((string)$cle) || $value === $cle) {
                    $html .= ' selected';
                } else {
                    if (strtoupper($option) == 'READONLY') {
                        $html .= 'disabled';
                    }
                }
                if ($cle && $affichageId) { // mettre affichageId a false si on ne veut pas afficher la cle dans le select
                    $html .= '>' . htmlentities($valeur . ' (' . $cle . ')') . '</option>';
                } else {
                    $html .= '>' . htmlentities((string) $valeur) . '</option>';
                }
            }
        }

        return $html . '</select></div>';
    }

    /**
     * @param mixed $paramsValidator
     * @param array<mixed> $inputAttr
     */
    public function inputTextarea(
        string $titre,
        string $name,
        ?string $value = '',
        ?string $pathValidator = '',
        $paramsValidator = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $option = '',
        ?string $addClass = '',
        ?string $paramTextArea = '',
        ?bool $obligatoire = false,
        ?bool $addStyle = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        $inputAttr = [],
        ?string $infos = ''
    ): string {
        $value = htmlspecialchars($value ?? '');

        $idInput = str_replace('|', '', $name);

        $html = '<div class="input-wrapper input-textarea">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }
        $nameJquery = str_replace('#', '\\\#', $idInput);
        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;
                if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . htmlspecialchars((string) $idIconeLabel) . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="input_' . $idInput . '">'
                . $titre . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }

        if (!is_string($paramsValidator)) {
            $paramsValidator = json_encode($paramsValidator);
        }

        $html .= '<textarea ' . $this->attr($inputAttr) . ' class="bs-col form-control ' . $addClass . '" style="height: 80px;' . $addStyle . '"' . $paramTextArea . ' data-toggle="tooltip" data-placement="top"
            data-html="true"
            id="input_' . $idInput . '" name="' . $name . '" ' . $option . ' onchange="' . htmlspecialchars('validatorAjax(\'' . $pathValidator . '\', ' . $paramsValidator . ',\'' . $nameJquery . '\', \'\', \'\', \'' . $myFuncValidator . '\', \'' . str_replace('"', "\\'", $paramFuncValidator) . '\');' . $myFunction . ';') . '">' . $value . '</textarea>';

        return $html . '</div>';
    }

    /**
     *
     * @Param : $myFunction => 'changeButtonSociete'
     * @Param : $myParams => si array  "{ 'id' : 'toto' }" ou  "baba"
     * @param array<mixed> $inputAttr
     */
    public function inputSwitch(
        string $titre,
        string $name,
        mixed $value = null,
        ?string $option = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $textCheck = 'Oui',
        ?string $textUnCheck = 'Non',
        ?string $style = '',
        ?bool $obligatoire = false,
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $styleText = '',
        ?string $addClass = '',
        ?bool $isAdvance = false,
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        $inputAttr = [],
        ?string $infos = ''
    ): string {
        $value = Sql::boolSql($value);

        $idInput = str_replace('|', '', $name);
        $trad    = $this->trad;
        $html    = '<div class="input-wrapper input-switch">';

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }

        if ($myFuncValidator != '') {
            $myFuncValidator = 'myFunc(' . $myFuncValidator . ', ' . str_replace('"', "'", $paramFuncValidator) . ')';
        }

        // pour la gestion ajax dynamique car on passe pas par le helper/Validator isCheck
        // if ($value === 'on') {
        //     $value = 1;
        // }

        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = false;
                if (strtoupper((string) $option) == 'READONLY' || strtoupper((string) $option) == 'DISABLED') {
                    $hidden = true;
                }

                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }

            $html .= '
            <label>'
                . $titre . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }

        if (strtoupper($option ?? '') == 'READONLY') {
            $option = 'disabled';
        }

        $textCheck   = $textCheck == 'Oui' ? $trad->t('Oui') : $textCheck;
        $textUnCheck = $textUnCheck == 'Non' ? $trad->t('Non') : $textUnCheck;

        if ($this->container->get('application.name') == 'oxalink' && !$isAdvance) {
            $id_input = $idInput;
        } else {
            $id_input = 'input_' . $idInput;
        }

        $html .= '<div class="bs-col"><label class="switchV2" style ="' . $style . '">
                        <input ' . $this->attr($inputAttr) . ' 
                                class="input_value_switch ' . $addClass . '" 
                                style="display:none;" 
                                type="checkbox" 
                                name="' . $name . '" id="' . $id_input . '" ' . ($value == 1 ? ' checked' : '') . '  ' .
            $option . ' ' . ($myFunction != '' || $myFuncValidator != '' ? 'onchange="' . $myFunction . $myFuncValidator . '"' : '') . ' 
                                data-oui="' . $textCheck . '" 
                                data-non="' . $textUnCheck . '">
                        <span class="slider round"></span>
                        <span class="value_switch" id="value_switch_' . $idInput . '" style="' . $styleText . '">' . ($value == 1 ? $textCheck : $textUnCheck) . '</span>
                    </label></div>';

        return $html . '</div>';
    }

    /**
     * @param string $titre                 obligatoire
     * @param string $name                  obligatoire
     * @param string $pathTreeview          obligatoire
     * @param ?string $titleTreeview         obligatoire
     * @param ?string $valueTexteTreeview    obligatoire
     * @param ?string $value                 valeur pour édition
     * @param array<mixed> $inputAttrTwig
     * @param array<mixed> $faceAttrTwig
     */
    public function inputTreeview(
        string $titre,
        string $name,
        string $pathTreeview,
        ?string $paramsTreeview = '',
        ?string $titleTreeview = '',
        ?string $valueTexteTreeview = '',
        ?string $value = '',
        ?string $convertLibelle = '',
        ?string $placeholder = '',
        ?string $pathValidator = '',
        ?string $params = '',
        ?string $pathConvert = '',
        ?string $entity = '',
        ?string $codeBDD = '',
        ?string $libelleBDD = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $idChamp = '',
        ?string $addStyle = '',
        ?string $option = '',
        ?string $width_popup = 'modal_small',
        ?bool $obligatoire = false,
        ?string $paramConvertLibelle = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $siLink = '',
        ?string $codeSte = '',
        ?string $sectimpu = '',
        ?string $codeAffCG = '',
        ?string $codeSteCG = '',
        $inputAttrTwig = [],
        $faceAttrTwig = [],
        ?bool $bulle = false
    ): string {
        unset($placeholder);
        unset($idChamp);

        if (!$_SESSION['IS_CG_ACTIVE'] && in_array(strtoupper((string) $entity), ['CODGESTPANIER', 'CODGEST'])) {
            return '';
        }

        $html = '<div class="input-wrapper input-treeview" data-zoom="'.htmlspecialchars($name).'">';

        $idInput = str_replace('|', '', $name);

        if ($convertLibelle == 'convertLibelleGlobal') {
            $convert      = new ConvertLibelleExtension($this->pdo);
            $valueLIBELLE = $convert->convertLibelleGlobal($entity, $libelleBDD, $value);
        } elseif ($convertLibelle == 'cgTrad' || $convertLibelle == 'cgTradCode') {
            $convert      = new ConvertLibelleExtension($this->pdo);
            $valueLIBELLE = $convert->cgTrad($value, '', $sectimpu, $codeSteCG, ($convertLibelle == 'cgTradCode'));

            if (!$valueLIBELLE && $value) {
                $valueLIBELLE = str_contains($codeAffCG, $value) ? $codeAffCG : $codeAffCG . ' (' . $value . ')';
            }
        } elseif ($convertLibelle) {
            $convert      = new ConvertLibelleExtension($this->pdo);
            $valueLIBELLE = $convert->$convertLibelle($value);

            if (!$valueLIBELLE) {
                $valueLIBELLE = $value . ' (' . $value . ')';
            }
        } else {
            $valueLIBELLE = $valueTexteTreeview != '' ? $valueTexteTreeview : $value;
        }

        if ($valueLIBELLE != '' && $bulle) {
            $_SESSION['bulleFiltre'][$name] = [
                'titre' => $titre,
                'value' => $valueLIBELLE
            ];
        }

        if ($titre) {
            $html .= ' <label>' . $titre . $this->labelSuffixe($obligatoire) . '</label>';
        }

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ');';
        } else {
            $myFunction = '';
        }

        $convert = '';
        if ($pathConvert != '') {
            $convert = 'ConvertLibelle(' . implode(',', [
                json_encode($pathConvert),
                'this',
                json_encode($entity),
                json_encode($codeBDD),
                json_encode($libelleBDD),
                json_encode('input_' . $idInput),
                json_encode('text_' . $name),
                '0',
                '0',
                $paramConvertLibelle,
            ])
                . ');';
        }

        $inputFaceAttr = [
            'id' => 'text_' . $idInput,
            'type' => 'text',
            'name' => 'text_' . $name,
            'class' => 'form-control form-control-sm zoom' . ' ' . $addStyle,
            'data-toggle' => 'tooltip',
            'data-placement' => 'top',
            'data-html' => 'true',
            'data-silink' => $siLink,
            'title' => '',
            'value' => $valueLIBELLE,
            'data-zoom-label' => '',
            'data-onchange-echo' => // We use echo to handle the case when user unfocus the input to pick an item inside the autocomplete, his "search" must not trigger a convertLibelle
                // Case : the input has been changed with a value that is already valid
                "if(event?.detail?.source == 'safe') return;"
                . $myFunction // Note : myFunc is often used to convertLibelle for CG
                // Else
                . $convert
                . 'validatorAjax(' . implode(',', [
                        json_encode($pathValidator),
                        $params,
                        json_encode($idInput),
                        json_encode(''),
                        json_encode($idInput),
                        json_encode($myFuncValidator),
                        json_encode(str_replace('"', "\\'", $paramFuncValidator)),
                    ])
                . ');'
        ] + $faceAttrTwig;

        $inputAttr = [
            'type' => 'hidden',
            'name' => $name,
            'id' => 'input_' . $idInput,
            'class' => 'hidden_' . $addStyle,
            'value' => $value,
            'data-zoom-input' => '',
            'onchange' => 'validatorAjax('
                . implode(',', [
                    json_encode($pathValidator),
                    $params,
                    json_encode($idInput),
                    json_encode(''),
                    json_encode($idInput),
                    json_encode($myFuncValidator),
                    json_encode($paramFuncValidator),
                ])
                . ');',
        ] + $inputAttrTwig;

        $html .= '
            <div class="bs-col relative">
            <input ' . $this->attr($inputAttr) . ' />
            <input ' . $this->attr($inputFaceAttr) . ' ' . $option . ' />';

        if (strtoupper((string) $option) == 'DISABLED' || strtoupper((string) $option) == 'READONLY') {
            $hiddenSpan = 'style="display: none;"';
        } else {
            $hiddenSpan = '';
        }
        $html .= '<span id="zoom_' . $name . '" class="glyphicon glyphicon-search" onclick="'
            . htmlspecialchars(
                'ajaxPopup('
                . implode(',', [
                    \json_encode($pathTreeview),
                    \json_encode($titleTreeview),
                    \json_encode('input_' . $idInput),
                    \json_encode('text_' . $name),
                    $paramsTreeview,
                    \json_encode($width_popup),
                ])
                . ')'
            ) . '" ' . $hiddenSpan . '></span></div></div>';

        // TODO : clean up -> should not use ajax, specific should not be here
        if ($siLink) {
            $html .= "  <script>
                            $('#' + CSS.escape('" . $siLink . "')).change(function(){
                                $.ajax({
                                    url: '" . $this->router->generateUri('Ajax.Outil.cgActifForSi') . "',
                                    type: 'POST',
                                    dataType : 'JSON',
                                    data: {'SECTIMP' : $(this).val(), 'CODE_STE' : " . (str_starts_with($codeSte, '$(') ? $codeSte : "'$codeSte'") . "},
                                    success: function (json) {
                                        const zoom = $('#zoom_' + CSS.escape('" . $name . "'));
                                        const input = $('#input_'+ CSS.escape('" . $idInput . "'));
                                        const faceInput = $('#text_' + CSS.escape('" . $idInput . "'));
                                       
                                        if (json.CG == 1) {
                                            faceInput.prop('readonly', false); 
                                            zoom.show();
                                            input.val('');
                                            faceInput.val('');
                                        } else {
                                            faceInput.prop('readonly', true); 
                                            zoom.hide();
                                            input.val('');
                                            faceInput.val('');
                                        }
                                    }
                                });
                            });
                        </script>";
        }

        return $html;
    }
    /**
     * @param array<mixed>|string|null $paramValidator
     * @param array<mixed>|string|null $paramsZoom
     * @param array<string,string> $inputAttr
     * @param array<string,string> $faceAttr TODO
     * @param array<mixed> $parameter as given in inputAdvance
     */
    public function inputZoomAdvance(
        string $titre,
        string $name,
        string $pathZoom,
        $paramsZoom = '',
        ?string $value = '',
        ?string $convertLibelle = '', // TODO: Deprecate this arg
        ?string $pathValidator = '',
        $paramValidator = '',
        ?string $option = '',
        ?string $addStyle = '',
        ?string $pathConvert = '',
        ?string $entity = '',
        ?string $codeBDD = '',
        ?string $libelleBDD = '',
        ?string $myFunction = '',
        ?string $myParams = '',
        ?string $width_popup = 'modal_small',
        ?string $titre_popup = '',
        ?string $placeholder = '',
        ?bool $obligatoire = false,
        ?string $valueTexteZoom = '',
        ?string $iconeLabel = '',
        ?string $idIconeLabel = '',
        ?bool $clickSelect = false,
        ?string $paramConvertLibelle = '',
        ?string $myFuncValidator = '',
        ?string $paramFuncValidator = '',
        ?string $addCss = '',
        ?bool $bulle = false,
        ?string $titreHidden = '',
        $inputAttr = [],
        $faceAttr = [],
        ?string $htmlLabelBlock = '',// TODO : remove
        ?string $codeSte = '',
        ?string $tsDon = '',
        ?string $infos = '',
        $parameter = []
    ): string {
        $idInput = str_replace('|', '', $inputAttr['id'] ?? $name);

        $autocomplete     = '';
        $dataAutocomplete = '';

        if ($entity != '') {
            $autocomplete     = 'autocomplete';
            $dataAutocomplete = 'data-autocomplete="' . $entity . '"';
        }

        // zoomPath override the older pathZoom (aka 'pahtZoom')
        if (!empty($parameter['zoomPath'])) {
            $pathZoom    = $this->router->generateUri($parameter['zoomPath']);
            $titre_popup = ZoomHelper::getZoomTitle($parameter['zoomPath'], $this->trad);
            $class       = ZoomHelper::getEntityFromPath($parameter['zoomPath']);
            if ($class !== null) {
                $entity = (new ReflectionClass($class))->getShortName();
            }

            $autocomplete = ''; // Disable old autocompletion (new one is handled in public\js_src\Global\Form\inputZoom.js)
        }
        
        if (!$paramsZoom) {
            $paramsZoom = "{}";
        }
        if (!is_string($paramsZoom)) {
            $paramsZoom = (string) json_encode($paramsZoom);
        }

        $html = '<div class="input-wrapper input-zoom-adv" ' . $this->attr([
            'data-zoom' => $name,
            'data-zoom-path' => $parameter['zoomPath'] ?? '',
            'data-zoom-filter' => $paramsZoom,
        ]) . '>';

        if ($convertLibelle == 'convertLibelleGlobal') {
            $convert      = new ConvertLibelleExtension($this->pdo);
            $valueLIBELLE = $convert->convertLibelleGlobal($entity, $libelleBDD, $value, true, $codeSte, $tsDon);
        } elseif ($convertLibelle) {
            $convert      = new ConvertLibelleExtension($this->pdo);
            $valueLIBELLE = $convert->$convertLibelle($value);
        } else {
            $valueLIBELLE = ($valueTexteZoom != '' ? $valueTexteZoom : $value);
        }

        if (!empty($titre)) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $hidden = (strtoupper($option) == 'READONLY' || strtoupper($option) == 'DISABLED');

                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '" ' . ($hidden ? 'style="display:none;"' : '') . '>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                </span>';
            }
            $html .= '
            <label for="text_' . $idInput . '" ' . ($titreHidden ? 'style="display: none;"' : '') . '>'
                . $titre
                . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . '</label>';
        }

        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ');';
        } else {
            $myFunction = '';
        }
        if ($paramConvertLibelle) {
            $paramConvertLibelle = ', ' . $paramConvertLibelle;
        }

        $nameJquery = str_replace('#', '\\\#', $idInput);

        $onclick = '';
        if ($clickSelect) {
            $onclick = 'onclick="this.select();"';
        }
        
        $hiddenStyle = '';
        if ($addStyle === 'no-empty') {
            $hiddenStyle = $name . '-' . $addStyle;
        }

        if (!is_string($paramValidator)) {
            $paramValidator = json_encode($paramValidator);
        }

        $html .= '
            <input ' . $this->attr([
                'type' => 'hidden',
                'name' => $name,
                'id' => 'input_' . $idInput,
                'value' => ($valueLIBELLE ? $value : ''),
                'data-zoom-input' => '',
                'onchange' => 'validatorAjax('
                    . implode(',', [
                        json_encode($pathValidator),
                        $paramValidator,
                        json_encode($nameJquery),
                        json_encode(''),
                        json_encode(1),
                        json_encode($myFuncValidator),
                        json_encode($paramFuncValidator),
                    ])
                    . ');'
                    . $myFunction,
            ] + $inputAttr) . ' ' . ($hiddenStyle != '' ? 'class="' . $hiddenStyle . '"' : '') . ' /> 
            <div class="bs-col relative">
            <input ' . $this->attr(
                [
                    'type' => 'text',
                    'class' =>
                        'form-control form-control-sm zoom '
                        . $addStyle . ' ' . $autocomplete . ' '
                        . ($faceAttr['class'] ?? '')
                        . ($option == 'desactiveSaisie' ? 'zoom-desactiveSaisie' : ''),
                    'data-zoom-label' => '',
                    'list' => 'datalist_' . $idInput
                ]
                + $faceAttr
                + ($codeSte ? [
                    'data-codeste' => $codeSte
                ] : [])
                + [
                    'id' => 'text_' . $idInput,
                    'name' => 'text_' . $name,
                    'value' => $valueLIBELLE,
                    'data-toggle' => 'tooltip',
                    'data-placement' => 'top',
                    'data-html' => 'true',
                    'title' => '',
                    'placeholder' => $placeholder,
                    'style' => $addCss,
                    'onchange' =>
                        // Case : the input has been changed with a value that is already valid
                        "if(event?.detail?.source == 'safe') return;"
                        // Else
                        . 'ConvertLibelle(\'' . $pathConvert . '\', this,\'' . $entity . '\', \'' . $codeBDD . '\',\'' . $libelleBDD . '\', \'input_' . $nameJquery . '\', \'text_' . $nameJquery . '\', 0, 0 ' . $paramConvertLibelle . ');'
                        . 'validatorAjax('
                        . implode(',', [
                            json_encode($pathValidator),
                            $paramValidator,
                            json_encode($nameJquery),
                            json_encode('true'),
                            json_encode(''),
                            json_encode($myFuncValidator),
                            json_encode($paramFuncValidator),
                        ])
                        . ');'
                ]
                + (!empty($parameter['zoomPath']) ? [
                    'data-onkeyup-echo' => 'new InputZoom(event.target).handleKeyUp(event)',
                    'onfocus' => 'new InputZoom(event.target).autocompShowAndUpdate()',
                    'onblur' => 'eventEcho(event, () => {
                        new InputZoom(event.target).displayAutocomp(false)
                    })',
                ] : [])
            ) . ' ' . $dataAutocomplete . ' ' . ($option == 'desactiveSaisie'? 'readonly':$option) . ' ' . $onclick . '>'
            . '<ul class="input-text-autocomplete" style="display: none" '. $this->attr([
                //'id' => 'datalist_' . $idInput,

                // We preventDefault() on the mousedown event
                // to keep the dropdown from taking focus from the input.
                'onmousedown' => 'event.preventDefault()',

                'data-autocomp-box' => '',
            ]).'></ul>'
        ;


        if ($valueLIBELLE != '' && $bulle) {
            $_SESSION['bulleFiltre'][$name] = [
                'titre' => $titre,
                'value' => $valueLIBELLE
            ];
        }
        
        if (!$paramsZoom) {
            $paramsZoom = "{}";
        }
        if (!is_string($paramsZoom)) {
            $paramsZoom = json_encode($paramsZoom);
        }

        if (strtoupper($option)=='READONLY' || strtoupper($option)=='DISABLED') {
            $hiddenSpan = 'style="display: none;"';
        } else {
            $hiddenSpan = '';
        }


        // TODO : simplify
        $html .= '<span id="zoom_' . $name . '" 
            class="glyphicon glyphicon-search btn-zoom-open" 
            onclick="!' . htmlspecialchars(
            'ajaxPopup('
                . implode(',', [
                    json_encode($pathZoom),
                    json_encode($titre_popup),
                    json_encode('input_' . $idInput),
                    json_encode('text_' . $idInput),
                    $paramsZoom,
                    json_encode($width_popup),
                ])
                . ')'
        ) . '" '.$hiddenSpan.'></span></div></div>';

        return $html;
    }

    /**
     * @param bool|null $obligatoire
     */
    public function labelSuffixe($obligatoire): string
    {
        return $obligatoire ?
            '<span class="obligatoire" data-labelsuffix>*</span>' :
            '<span data-labelsuffix></span>';
    }

    /**
     * Summary of inputFile
     * @param mixed $name
     * @param mixed $value
     * @param mixed $format
     * @param mixed $titre
     * @param mixed $iconeLabel
     * @param mixed $idIconeLabel
     * @param mixed $option
     * @param string $infos
     * @return string
     */
    public function inputFile($name, $value = '', $format = '', $titre = '', $iconeLabel = '', $idIconeLabel = '', $option = '', string $infos = '')
    {
        $value = htmlspecialchars($value ?? '');
        $trad  = $this->trad;

        if ($format == 'excel') {
            $formatAccept = 'accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, .csv"';
        } elseif ($format == 'image') {
            $formatAccept = 'accept="image/png, image/jpeg, .html, .htm"';

            $image_format = $trad->t('Formats acceptés') . ' : png, jpg, svg';

            if ($name != '' && $name == 'BANDEAU_OXALINK') {
                $accepted_formats_list = '<img class="tooltip-param-oxalnk-icon" src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                <span class="infos_tooltip bottom tooltip-param-oxalnk-txt">
                    <span class="tooltip-arrow"></span>
                    <p style="margin-bottom: 0;">' . $image_format . '</p>
                    <p style="margin-bottom: 0;">' . $trad->t('Résolution recommandée') . ' : 460x80 pixels</p>
                </span>';
            } elseif ($name != '' && $name == 'BG_ACCUEIL_OXALINK') {
                $accepted_formats_list = '<img class="tooltip-param-oxalnk-icon" src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                <span class="infos_tooltip bottom tooltip-param-oxalnk-txt">
                    <span class="tooltip-arrow"></span>
                    <p style="margin-bottom: 0;">' . $image_format . '</p>
                    <p style="margin-bottom: 0;">' . $trad->t('Résolution recommandée') . ' : 1490x900 pixels</p>
                </span>';
            }
        } elseif ($format == 'excelWithOutCSV') {
            $formatAccept = 'accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"';
        } elseif ($format == 'csv') {
            $formatAccept = 'accept=".csv"';
        }
        $html = '';

        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            if ($iconeLabel != '') {
                $icone = '<span class="white-tooltip icone_input" id="' . $idIconeLabel . '">
                            <img src="' . $this->container->get('baseUrl') . 'IconeV2/Misc/' . $iconeLabel . '" />
                            </span>';
            }
            $html = '
            <label style="position: relative;" for="input_' . $name . '">'
                . $titre
                . ($iconeInfos ?? '')
                . ($icone ?? '')
                . ($accepted_formats_list ?? '')
                . '</label>';
        }

        return $html . ('   
                    <div id="file-wrap' . $name . '" class="file-wrap ' . '' . '">
                        <img class="dragIcon" src="' . $this->container->get('baseUrl') . '/IconeV2/Misc/drag-icon.png" />
                        <p id="text_' . $name . '">' . ($value != '' ? $value : $trad->t('Déplacez votre fichier ici, ou bien cliquez pour ajouter.')) . '</p>
                        <input class="input-import" type="file" id="import' . $name . '" name="import' . $name . '" draggable="true" ' . ($formatAccept ?? '') . ' ' . $option . '/>
                        <input type="hidden" id="file_name' . $name . '" name="file_name' . $name . '" value="' . $value . '"/>
                    </div>

                    <script>
                        inputFile(' . json_encode($name) . ');
                    </script>
        ');
    }

    /**
     * multiSelect
     *
     * @param  mixed $name
     * @param  mixed $titre
     * @param  mixed $listeValue
     * @param  array<mixed> $post
     * @param  array<mixed> $obli
     * @param  mixed $class
     * @param  mixed $entity
     * @param  ?array<mixed> $typeListe
     * @param  array<mixed> $arrayPost
     * @return string
     */
    public function multiSelect($name, $titre, $listeValue, $post = [], $obli = [], $class = '', $entity = null, ?array $typeListe = [], array $arrayPost = [])
    {

        $listeLEFT      = [];
        $listeRIGHT     = [];
        $paginationHTML = '';
        $trad           = $this->trad;

        // filtre le POST uniquement avec le multiSelect
        $arrayMultiSelect = array_filter($post, function ($k) use ($name): bool {
            return (bool) stristr($k, 'multiSelect' . $name); // TODO BBA : voir si c'est judicieux
        }, ARRAY_FILTER_USE_KEY);

        if ($entity == null) {
            foreach ($arrayMultiSelect as $key => $value) {
                $listeRIGHT[$value] = $listeValue[$value];
            }

            foreach ($listeValue as $key => $value) {
                if (array_search($key, $arrayMultiSelect)) {
                    //$listeRIGHT[$key]=$value;
                } else {
                    $listeLEFT[$key] = $value;
                }
            }
        } else {
            if (count($typeListe??[])) {
                $parameter   = new Parametre($this->pdo);
                $filtreListe = $parameter->keyPathliste($typeListe, 'filtreListe');
                $post        = array_merge($post, $filtreListe);
            }

            $societes = (new Societe($this->pdo))->listRestrictedSocieteForUser();

            // TODO BBA voir pour faire quelque chose de générique
            if ($entity == 'Societe' && $societes !== null) {
                foreach ($societes as $value) {
                    $label = $value['RAIS_SOC'] . ' (' . $value['CODE_STE'] . ')';
                    if (array_search($value['CODE_STE'], $arrayMultiSelect)) {
                        $listeRIGHT[$value['CODE_STE']] = $label;
                    } else {
                        $listeLEFT[$value['CODE_STE']] = $label;
                    }
                }
            } else {
                $entityTmp   = '';
                $clauseWhere = '';
                if ($entity == 'CENTRE_L') {
                    $entityTmp                          = 'Centre';
                    $arrayPost['filter_egal_LIVRAISON'] = 'T';
                } elseif ($entity == 'CENTRE_E') {
                    $entityTmp                         = 'Centre';
                    $arrayPost['filter_egal_EMISSION'] = 'T';
                } elseif ($entity == 'ACHETEUR') {
                    $entityTmp             = 'Hastutil';
                    $arrayPost['ACHETEUR'] = 1;
                } elseif ($entity == 'SectimpuSpecifique') {
                    $entityTmp = 'Sectimpu';
                } else {
                    $entityTmp = $entity;
                }

                if (!$arrayPost) {
                    $arrayPost = [];
                }

                $generatorEntity = "\\Entity\\Model\\" . $entityTmp;
                /** @var Entity $entityPdo */
                $entityPdo = new $generatorEntity($this->pdo);

                $paginator = new PaginatorGestion();
                $paginator->generate(false, $entityPdo->getLibelle(), 'ASC');

                if ($entity == 'SectimpuSpecifique') {
                    $entitys = [];

                    $specifique          = new Specifique();
                    $namespaceSpecifique = $specifique->specifiqueFunction('\\Modules\\Liste\\Service\\SpecifiqueSI');
                    if (class_exists($namespaceSpecifique)) {
                        $namespaceSpecifique = new $namespaceSpecifique();
                        if (method_exists($namespaceSpecifique, 'multiSelectSI')) {
                            $entitys = Specifique::specifique('\\Modules\\Liste\\Service\\SpecifiqueSI', 'multiSelectSI', $this->pdo, $arrayPost);
                        } else {
                            $entitys = (new Multiselect($this->pdo))->getResultEntityDynamique($entityPdo, '', '', [], $arrayPost, $clauseWhere);
                        }
                    }
                } elseif (strtoupper((string) $entityTmp) == 'HASTUTIL') {
                    $listeRepo = new Listes($this->pdo);
                    $entitys   = $listeRepo->utilisateurListe($arrayPost);
                } elseif (strtoupper((string) $entityTmp) == 'TYPEDOC') {
                    $listeRepo            = new Listes($this->pdo);
                    $arrayPost['oxaproc'] = '1';
                    $arrayPost['valide']  = 'on';
                    $entitys              = $listeRepo->listeTypeDoc($arrayPost);
                } elseif (strtoupper((string) $entityTmp) == "TYEVTSTP") {
                    $listeRepo            = new Listes($this->pdo);
                    $arrayPost['oxaproc'] = '1';
                    $arrayPost['valide']  = 'on';
                    $entitys = $listeRepo->listeTyevtstp($arrayPost);
                    foreach ($entitys as &$ent) {
                        if (Sql::toBool($ent['HAPLUS'])) {
                            $ent['LIB_EVT'] = $ent['LIB_EVT'] . ' - ' .  $trad->t('Automatique');
                        }
                        if (Sql::toBool($ent['PRO_POSTE'])) {
                            $ent['LIB_EVT'] = $ent['LIB_EVT'] . ' - ' .  $trad->t('Avec postes');
                        }
                    }
                } else {
                    $entitys = (new Multiselect($this->pdo))->getResultEntityDynamique($entityPdo, '', '', [], $arrayPost, $clauseWhere);
                }

                $entitysRIGHT = (new Multiselect($this->pdo))->getRightValue($entityPdo, $arrayMultiSelect, $arrayPost);
                if (strtoupper((string) $entityTmp) == "TYEVTSTP") {
                    foreach ($entitysRIGHT as &$entRight) {
                        foreach ($entitys as $ent2) {
                            if (($entRight['CODE_EVT'] == $ent2['CODE_EVT']) && Sql::toBool($ent2['HAPLUS'])) {
                                $entRight['LIB_EVT'] = $ent2['LIB_EVT'];
                            }
                            if (($entRight['CODE_EVT'] == $ent2['CODE_EVT']) && Sql::toBool($ent2['PRO_POSTE'])) {
                                $entRight['LIB_EVT'] = $ent2['LIB_EVT'];
                            }
                        }
                    }
                }

                $infoPagination = PaginatorGestion::getInfoPagination();

                /**
                 * faux positif
                 */
                /** @phpstan-ignore-next-line */
                $infoPagination['post'] = 'entity : \'' . $entity . '\'';

                $pagination = new PaginationExtension($this->container);


                $paginationHTML = $pagination->paginations(
                    $this->router->generateUri('Outil.MultiSelect.entity'),
                    $infoPagination['nombreDePage'],
                    $infoPagination['page'],
                    'entity : \'' . $entity . '\', name : \'' . $name . '\'',
                    $name . '_left'
                );

                $alreadyUse = [];
                foreach ($entitysRIGHT as $value) {
                    if ($value[$entityPdo->getLibelle()] != $value[$entityPdo->getPrimaryKey()]) {
                        $libelle = $value[$entityPdo->getLibelle()] . ' (' . $value[$entityPdo->getPrimaryKey()] . ')';
                    } else {
                        $libelle = $value[$entityPdo->getLibelle()];
                    }
                    $listeRIGHT[$value[$entityPdo->getPrimaryKey()]] = $libelle;
                    $alreadyUse[$value[$entityPdo->getPrimaryKey()]] = $value[$entityPdo->getPrimaryKey()];
                }
                foreach ($entitys as $value) {
                    if ($value[$entityPdo->getLibelle()] != $value[$entityPdo->getPrimaryKey()]) {
                        $libelle = $value[$entityPdo->getLibelle()] . ' (' . $value[$entityPdo->getPrimaryKey()] . ')';
                    } else {
                        $libelle = $value[$entityPdo->getLibelle()];
                    }
                    if (!array_search($value[$entityPdo->getPrimaryKey()], $alreadyUse)) {
                        $listeLEFT[$value[$entityPdo->getPrimaryKey()]] = $libelle;
                    }
                }
            }
        }

        $html = '<div class="padding_form div_SyncLists ' . $class . '" style ="width:100%;">
            		<div>
                        <div class="SyncLists" id="' . $name . '"><div style="display: flex; justify-content: space-between; align-items: center; gap: 1em;">';
        if ($paginationHTML == '') {
            $html .= '<input id="' . $name . '_findInSyncLists" onkeypress="refuserToucheEntree(event);" class="form-control form-control-sm" type="text">';
        } else {
            $html .= '<input id="' . $name . '_findEntityList" onkeypress="refuserToucheEntree(event);" onkeyup="searchEntityFindAll(this.value, \'' . $entity . '\')" class="form-control form-control-sm" type="text">';
        }
        if (strtoupper(strval($entityTmp??'')) == "TYEVTSTP" && Roles::droitsUtilisateur($this->pdo, 'HA_TYEV_CM')) {
            $html .= "
                    <a class=\"ajouter_v2 white-tooltip\" style=\"float: right;\" onClick=\"ajaxDynamiqueTab('".$this->router->generateUri('Tables.evementTP.Create', ["mode" =>'ajax', 'idModule' => 0])."', '".$this->trad->t('Création d’un type d’événement')."');\">
                        <span class=\"infos_tooltip left\">
                            ".$this->trad->t('Ajouter un type d’événement')."
                        </span>
                    </a>
                ";
        }
        $html .= "</div>";
        $html .= '<ul id="' . $name . '_left" class="SyncLists left" get_value="5">';

        foreach ($listeLEFT as $key => $value) {
            $html .= '<li class="SyncLists" style="white-space: nowrap;" data-codeValue="' . $key . '">' . $value . '</li>';
        }

        $html .= '          </ul>
                        </div>
                        <div class="button_SyncLists" style="margin-top:139px;">';
        if ($paginationHTML == '') {
            $html .= '<button id="' . $name . '_RightAll" class="principal button" type="button">>></button>';
        }
        $html .= '<button id="' . $name . '_LeftAll" class="principal button" type="button"><<</button>
                        </div>
                        <div class="SyncLists SyncLists_right">
                            <p><b>' . $trad->t('Nombre d\'éléments sélectionnés') . ' : <span id="' . $name . 'nbItem">' . count(array_filter($listeRIGHT)) . '</span></b></p>
                            <ul id="' . $name . '_right" class="SyncLists right" get_value="5">';

        if (count(array_filter($listeRIGHT)) != 0) {
            foreach ($listeRIGHT as $key => $value) {
                if ($obli && in_array($key, $obli)) {
                    $html .= '<li class="SyncLists unsortable" style="white-space: nowrap;" data-codeValue="' . $key . '">' . $value . '</li>';
                } else {
                    $html .= '<li class="SyncLists" style="white-space: nowrap;" data-codeValue="' . $key . '">' . $value . '</li>';
                }
            }
        }

        $html .= '          </ul>
                        </div>
                    </div>
                    
                    <div id="' . $name . '_listePost_SyncLists">';
        $i    = 1;

        foreach ($listeRIGHT as $key => $value) {
            $html .= '<input type="hidden" name="multiSelect' . $name . $i . '" value="' . $key . '"/>';
            $i++;
        }
        $html .= '  </div>
        <div id="' . $name . '_left_pagination" style="height: 49px;">' . $paginationHTML . '</div>
        </div>';

        $html .= '<input type="hidden" name="arrayPost" id="arrayPost" value=\'' . json_encode($arrayPost) . '\'>';

        return $html . ('  <script>
                        function refuserToucheEntree(event)
                        {
                            // Compatibilité IE / Firefox
                            if(!event && window.event) {
                                event = window.event;
                            }
                            // IE
                            if(event.keyCode == 13) {
                                event.returnValue = false;
                                event.cancelBubble = true;
                            }
                            // DOM
                            if(event.which == 13) {
                                event.preventDefault();
                                event.stopPropagation();
                            }
                        }
                        $("#' . $name . '_findInSyncLists").on("keyup", function() {
                	        var value = $(this).val().toLowerCase();
                    	    $("#' . $name . '_left li").filter(function() {
                        		$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
                        	});
                        });

                		$("#' . $name . '_left, #' . $name . '_right").sortable(
                		{
                		    connectWith: "#' . $name . '_right",
                            items: "li:not(.unsortable)",
                		    receive: function (event, ui)
                		    {
                		        SetValue(ui, "true");
                		    }
                		}).disableSelection();
                
                		$("#' . $name . '_right").sortable(
                		{
                		    connectWith: "#' . $name . '_left",
                            items: "li:not(.unsortable)",
                		    receive: function (event, ui) {
                		        SetValue(ui, "false");
                		    },
                            update : function() {
                                getValueMultiSelect();
                            }
                		}).disableSelection();                  
                
                		function SetValue(ui, value)
                		{
                		    var $item = $(ui.item);
                		    var $parent = $item.parent();
                		    getValueMultiSelect();
                		}
                
                		$("#' . $name . '_RightAll").click(function() 
                		{
                		    $("#' . $name . '_left li").each(function()
                		    {
                                if(!$(this).hasClass("unsortable") && $(this).is(":visible")){
                    		        var $this = $(this);
                    		        $this.appendTo("#' . $name . '_right");
                    		        $("#' . $name . '_right").sortable("option", "receive")(null, { item: $this });
                                }
                		    });
                		});
                		$("#' . $name . '_LeftAll").click(function() 
                		{
                		    $("#' . $name . '_right li").each(function()
                		    {
                                if(!$(this).hasClass("unsortable") && $(this).is(":visible")){
                    		        var $this = $(this);
                    		        $this.appendTo("#' . $name . '_left");
                    		        $("#' . $name . '_left").sortable("option", "receive")(null, { item: $this });
                                }
                		    });
                		});

                		function getValueMultiSelect()
                		{
                			var htmlValue = "";
                			var i = 1;
                		    $("#' . $name . '_right li").each(function()
                			{
                				value = $(this).data("codevalue");
                				htmlValue +=  "<input type=\"hidden\" name=\"multiSelect' . $name . '"+i+"\" value=\""+value+"\"/>";
                		    	i++;
                			});

                			$("#' . $name . '_listePost_SyncLists").html(htmlValue);

                            var nbItem = $("#' . $name . '_right li").length;

                            $("#' . $name . 'nbItem").html(nbItem);
                		}
                	
                        function searchEntityFindAll(value, entity)
                        {
                            var notIn = "";

                            $("#' . $name . '_right li").each(function(i)
                            {
                                notIn = notIn+"|"+$(this).attr("data-codevalue");
                            });
                            
                            activeLoader();
                            $.ajax({
                                url: "' . $this->router->generateUri('Outil.MultiSelect.searchEntity') . '",
                                type: "POST",
                                dataType: "html",
                                data: {entity:entity,filter:value,id:"' . $name . '_left",notin:notIn, arrayPost:$(\'#arrayPost\').val()},
                                success: function (htmlData) {
                                    desactiveLoader();

                                    var result = $("<div />").append(htmlData).find("#' . $name . '_left").html();
                                    $("#' . $name . '_left").html(result);

                                    var resultPagination = $("<div />").append(htmlData).find("#entityContentPagination").html();
                                    $("#' . $name . '_left_pagination").html(resultPagination);
                                }
                            });
                        }

                	</script>
                    <style>
                        #pagination {
                            margin-left: -10px;
                        }
                    </style>');
    }

    /**
     * Summary of inputHeure
     * @param string $titre
     * @param string $name
     * @param mixed $value
     * @param string $placeholder
     * @param string $pathValidator
     * @param mixed $params
     * @param mixed $myFunction
     * @param mixed $myParams
     * @param mixed $addStyle
     * @param mixed $option
     * @param mixed $obligatoire
     * @param mixed $myFuncValidator
     * @param mixed $paramFuncValidator
     * @param string $infos
     * @return string
     */
    public function inputHeure(string $titre, string $name, $value = '', string $placeholder = '', string $pathValidator = '', $params = '', $myFunction = '', $myParams = '', $addStyle = '', $option = '', $obligatoire = false, $myFuncValidator = '', $paramFuncValidator = '', string $infos = '')
    {

        $_SESSION['bulleFiltre'][$name]['titre'] = $titre;
        $_SESSION['bulleFiltre'][$name]['value'] = $value;

        $html = '<div class="input-wrapper input-text">';
        if ($myFunction != '') {
            $myFunction = 'myFunc(' . $myFunction . ', ' . str_replace('"', "'", $myParams) . ')';
        } else {
            $myFunction = '';
        }
        $nameJquery = str_replace('#', '\\\#', $name);
        if ($titre) {
            if ($infos != '') {
                $iconeInfos = '<span class="white-tooltip icone_input">
                    <span class="infos_tooltip top-left">
                        <span class="tooltip-arrow"></span>' .
                    $infos .
                    '</span>
                    <img src="' . $this->container->get('baseUrl') . 'IconeV2/Gestion/question.svg" />
                </span>';
            }

            $html .= '
            <label for="input_' . $name . '">'
                . $titre . $this->labelSuffixe($obligatoire)
                . ($iconeInfos ?? '')
                . '</label>';
        }

        $html .= '<div class="bs-col relative"> <input type="time" ' . $option . ' class="form-control form-control-sm ' . $addStyle . '" data-toggle="tooltip"
            data-placement="top"
                data-html="true" placeholder="' . $placeholder . '"
                    title="" id="input_' . $name . '" name="' . $name . '" validatorAjax(\'' . $pathValidator . '\', ' . $params . ',\'' . $nameJquery . '\', \'\', \'\', \'' . $myFuncValidator . '\', \'' . $paramFuncValidator . '\');' . $myFunction . ';" value="' . $value . '"></div>';

        return $html . '</div>';
    }

    /**
     * attr
     * Turn a map into a lsit of html attribute (string)
     *
     * @todo factorize with OutilExtension::attr
     * @see OutilExtension::attr()
     * @param  array<mixed> $attr
     */
    public function attr($attr): string
    {
        if (empty($attr)) {
            return '';
        }
        return implode(' ', array_map(
            fn(string $k, $v): string => $k . '="' . htmlspecialchars($v ?? '') . '"',
            array_keys($attr),
            $attr
        ));
    }

    /**
     * @param stdClass|array<mixed>|null $input
     * @param array<mixed>|null $data
     * @param array<mixed> $option
     */
    public function formInput(
        $input,
        ?array $data,
        ?string $title = null,
        array $option = []
    ): string {

        if ($input == null) {
            return '';
        }
        // This is to support the BS in src\Modules\GlobalApplication\Views\Input\inputTable.twig
        // DO NOT USE IT in any other context
        if (is_array($input)) {
            $input = (object) $input;
        }

        //______________________
        // Process fullName

        if (isset($input->parent)) {
            $input->fullName = AbsFormService::getFullName($input);
        }

        //______________________

        // Retrieve value
        if (isset($input->fullName)) {
            $value = ArrayHelper::pathAccess(
                $data ?? [],
                ArrayHelper::getAccessPath($input->fullName),
                ['??' => null]
            );
        } else {
            $value = $data[$input->name] ?? null;
        }

        if (in_array($input->type, ['FLOAT', 'DEVISE', 'MONTANT'])) {
            [, $deci] = explode('.', $input->format ?? Constante::formatMontant);
            $value    = FloatHelper::format($value, intval($deci));
        }

        //______________________
        // Calculate parent

        // Parent exist only for rendering the full name of an input

        if (in_array($input->type, ['GROUP'])) {
            $input->listChild = array_map(function ($child) use ($input) {
                $child->parent = $input;
                return $child;
            }, $input->listChild);
        }
        if ($input->type == 'BRANCH') {
            foreach ($input->mapSubform as $form) {
                foreach ($form as $child) {
                    $child->parent = $input;
                }
            }
        }

        //______________________
        // Input using template

        // Get default template
        $viewParam = [];
        if (empty($input->template)) {
            switch ($input->type) {
                case 'TEXT':
                    $input->template = '@GlobalApplication/Input/inputText';
                    break;
                case 'TABLE':
                    $input->template = '@GlobalApplication/Input/inputTable';
                    break;
                case 'GROUP':
                    $input->template = '@GlobalApplication/Input/inputGroup';
                    break;
                case 'BRANCH':
                    $input->template = '@GlobalApplication/Input/inputBranch';
                    $input->branch_dependency_fullname = AbsFormService::getFullName((object) [
                        'name' => $input->branch_dependency,
                        'parent' => $input->parent ?? null,
                    ]);
                    $input->selected = ArrayHelper::pathAccess(
                        $data ?? [],
                        ArrayHelper::getAccessPath($input->branch_dependency_fullname),
                        ['??' => null]
                    );
                    break;
                case 'MULTIPICK':
                    $input->template = '@GlobalApplication/Input/inputMultipick';
            }
        }

        // View parameters
        $viewParam = [];
        switch ($input->type) {
            case 'MULTIPICK':
                $viewParam = [
                    'zoomConfig' => ZoomHelper::getDisplayConfig(
                        $this->trad,
                        $this->pdo,
                        $input->zoom_path
                    ),
                ];
        }

        if (!empty($input->template)) {
            $input = (object) array_merge(['label' => $title], (array) $input, $option);
            return $this->container
                ->get(RendererInterface::class)
                ->render($input->template, $viewParam + [
                    'label' => $title ?? $input->label ?? $input->title ?? '',
                    'input' => $input,
                    'subject' => $data,
                    'value' => $value,
                ]);
        }

        //______________________


        return $this->inputAdvance(
            [
                'ZOOM_MULTI' => 'ZOOM',
                'ZOOM' => 'ZOOMADVANCE',
                'FLOAT' => 'TEXT',
                'MONTANT' => 'TEXT',
            ][$input->type] ?? $input->type,
            $option
            + [
                'titre' => $title ?? $input->label ?? $input->title ?? '',
                'name' => $input->fullName ?? $input->name,
                'value' => $input->type == 'DATE' && ! ($input->subjectIsPost ?? false)  ?
                    Date::dateConverte($value) : $value,
                'option' => ($input->disabled ?? false) ? 'disabled' : ($input->option ?? ''),
                'obligatoire' => $input->validator['mandatory'] ?? false,
                'bulle' => $input->bulle ?? false,
            ]
            // Validator
            + $this->getInputValidator($input)

            // DEVISE
            + (in_array($input->type, ['DEVISE']) ? [
                'pathValidator' => $this->router->generateUri('Ajax.validator.float')
            ] : [])

            // SELECT
            + ($input->type == 'SELECT' ? [
                'listeValue' => is_callable($input->choices) ?
                    ($input->choices)($this->trad) : $input->choices,
            ] : [])
            // FLOAT
            + (in_array($input->type, ['FLOAT', 'MONTANT']) ? [
                'numerique' => true,
            ] : [])
            // ZOOM
            + ($input->type == 'ZOOM' ? $this->getInputZoomParam($input) : [])
            // ZOOM_MULTI
            + ($input->type == 'ZOOM_MULTI' ? [
                // TODO : entity should be specified in the route
                'titleZoom' => ZoomHelper::getZoomTitle('GlobalApplication.MultiSelect.afficher', $this->trad),
                'pahtZoom' => $this->router->generateUri('GlobalApplication.MultiSelect.afficher'),
                'paramZoom' => "{
                        titre: " . json_encode(ZoomHelper::getZoomTitle('GlobalApplication.MultiSelect.afficher', $this->trad)) . ",
                        value: $('#input_" . $input->name . "').val(),
                        entity: " . json_encode((new ReflectionClass($input->entity))->getShortName()) . "
                    }",
                'option' => 'desactiveSaisie',
                'widthPopup' => $this->getZoomWidth($input->entity),
            ] : [])
        );
    }

    /**
     * @param stdClass $input
     * @return array<mixed>
     */
    private function getInputValidator($input): array
    {
        $postalValid = $input->validator['code_postal'] ?? null;
        if (!empty($postalValid)) {
            return [
                'pathValidator' => $this->router->generateUri('Ajax.validator.codePostal'),
                'paramsValidator' => 'Object.assign('
                    . Utils::jsonEncode([
                        'nomChamp' => $input->label ?? 'Code postal', // TODO : trad
                        'sizeMin' => $input->validator['min'] ?? 0,
                        'sizeMax' => $input->validator['max'],
                    ]) . ','
                    . (is_string($postalValid)
                        ? '{PAYS:$("#input_' . $postalValid . '").val()}'
                        : '{}')
                    . ')'
            ];
        }

        $format = $input->validator['format'] ?? null;
        if ($format == 'code') {
            return [
                'pathValidator' => $this->router->generateUri('Ajax.validator.isStringSansEspace'),
                'paramsValidator' => (isset($input->validator['max']) ? [
                    'sizeMax' => $input->validator['max'],
                ] : null),
            ];
        }
        if ($format == 'integer') {
            return [
                'pathValidator' => $this->router->generateUri('Ajax.validator.integer'),
                'paramsValidator' => (isset($input->validator['max']) ? [
                    'sizeMax' => $input->validator['max'],
                ] : null),
            ];
        }

        if (in_array($input->type, ['FLOAT', 'DEVISE', 'MONTANT'])) {
            return [
                'pathValidator' => $this->router->generateUri('Ajax.validator.float'),
                'paramsValidator' => Utils::jsonEncode([
                    'format' => ($input->format ?? Constante::formatMontant)
                ]),
            ];
        }
        if (in_array($input->type, ['TEXTAREA', 'TEXT', 'PASSWORD'])) {
            return [
                'pathValidator' => $this->router->generateUri('Ajax.validator.isStringAvecEspace'),
                'paramsValidator' => (isset($input->validator['max']) ? [
                    'sizeMax' => $input->validator['max'],
                ] : null),
            ];
        }

        return [];
    }

    /**
     * @param stdClass $input
     * @return array<mixed>
     */
    private function getInputZoomParam($input, ?string $title = null): array
    {
        // $input->entity is deprecated, use $input->zoom_path instead
        $entity      = $input->entity ?? ZoomHelper::getEntityFromPath($input->zoom_path);
        $entityShort = !empty($entity) ? (new ReflectionClass($entity))->getShortName() : '';
        $zoomFilter  =
            'Object.assign('
            . Utils::jsonEncode($input->zoom_filter ?? (object) []) . ','
            . '{'
            . implode(',', array_map(
                function ($fieldTarget, $fieldOwned) use ($input): string {
                    if (is_int($fieldOwned)) { // Case : numeric key mean use the target field
                        $fieldOwned = $fieldTarget;
                    }
                    $fieldTarget = AbsFormService::getFullName((object) [
                        'name' => $fieldTarget,
                        'parent' => $input->parent ?? null,
                    ]);

                    return Utils::jsonEncode($fieldOwned) . ':$("[name="+CSS.escape(' . json_encode($fieldTarget) . ')+"]").val()';
                },
                $input->zoom_dependency ?? [],
                array_keys($input->zoom_dependency ?? [])
            ))
            . '})';
        $zoomPath   = $input->zoom_path ?? ZoomHelper::getZoomPath($entity);

        return [
            'titleZoom' => ZoomHelper::getZoomTitle($zoomPath, $this->trad),
            'zoomPath' => $zoomPath,
            //'pahtZoom' => $this->router->generateUri($zoomPath),
            'paramZoom' => $zoomFilter,
            'inputAttr' => (!empty($input->zoom_dependency) ? [
                'data-zoom-dependency' => implode(',', $input->zoom_dependency)
            ] : []),
            'pathConvert' => $this->router->generateUri('Ajax.outil.zoomConvertLibelle'),
            'convertLibelle' => !empty($entityShort) ? 'convertLibelleGlobal' : '',
            'paramConvertLibelle' =>
                '{zoomPath: ' . Utils::jsonEncode($zoomPath)
                . ',zoomFilter:' . $zoomFilter . '}',
            'entity' => $entityShort,

            'pathValidator' => $this->router->generateUri('Ajax.validator.zoomListe'),
            'paramsValidator' =>
                'Object.assign('
                . Utils::jsonEncode([
                    'nomChamp' => $title,
                    'entity' => $entityShort,
                    'null' => !($input->validator['mandatory'] ?? false),
                    'zoom_path' => $zoomPath,
                ]) . ','
                . '{post: ' . $zoomFilter . '}'
                . ')',

            'widthPopup' => $this->getZoomWidth($entity ?? ''),
        ];
    }




    private function getZoomWidth(string $entity): string
    {
        if (in_array($entity, [
                Sectimpu::class,
                Codecomp::class,
                Sscptana::class
            ])
        ) {
            return 'modal_large';
        }
        return '';
    }


    /**
     * This function is used to generate a Group input dynamically at render (ex: for the input Table rows)
     * /!\ Do not use it in any other
     * @param array<stdClass|array<mixed>> $subform
     * @param array<mixed> $option
     * @return stdClass
     */
    public function createInputGroup(string $name, array $subform, array $option = []): object
    {
        return (new FormBuilder())->createGroup(
            $name,
            array_column(
                array_map(function ($item): \stdClass {
                    if (is_array($item)) {
                        $item = (object) $item;
                    }
                    return clone $item;
                }, $subform),
                null,
                'name'
            ),
            $option
        );
    }

    public function getFileSizeMax(): int
    {
        return (new Paravrac($this->pdo))->getFileSizeMax();
    }

    /**
     * Summary of updateValue
     * @param string $path -- Path généré
     * @param string $pathJS -- path venant d'une variable JS
     * @param string $successFonction -- fonction a déclanché dans le sucess myFunction(param1, param2,...);
     * @return string
     */
    public function updateValue($path, $pathJS, $successFonction = null):string
    {
        $JS = "<script>
                const postAjaxFormOnSuccess = (element, data) => {
                    $(element).removeClass('error white-tooltip');
                    $(element).removeAttr('data-toggle');
                    $(element).removeAttr('data-original-title');
                    $(element).removeAttr('data-html');
                }

                const postAjaxFormOnError = (element, data) => {
                    $(element).addClass('error white-tooltip');
                    $(element).attr('data-toggle', 'tooltip');
                    $(element).attr('data-original-title', data);
                    $(element).attr('data-html', 'true');
                }

                document.addEventListener('change',(event) => {
                    var target = event.target;
                    if (!(target instanceof HTMLElement) ) {
                        return;
                    }

                    if (!target.hasAttribute('data-updatevalue')){
                        return;
                    } 

                    var fieldName = $(target).attr('name');

                    if ($(target).attr('type') == 'checkbox') {
                        var value = $(target).is(':checked');
                    } else {
                        var value = $(target).val();
                    }

                    activeLoader();
                    $.ajax({
                        dataType: 'json',
                        url: ".($path? "'$path'":$pathJS).",
                        data: {'field' : fieldName, 'value' : value},
                        type: 'POST',
                        success: function(content){
                            if (content.statut == 'O') {
                                desactiveLoader();
                                postAjaxFormOnSuccess(target);

                                if ($(target).data('autocomplete') && $(target).attr('data-no-convert') != 'true') {
                                    var textInput = $(target).attr('id');
                                    var idInput = textInput.replace('text_', 'input_');

                                    ConvertLibelle(
                                        '".($this->router->generateUri('Ajax.outil.convertLibelle'))."', 
                                        target,
                                        $(target).data('autocomplete'), 
                                        '', 
                                        '',
                                        idInput,
                                        textInput,
                                    );
                                }

                                $successFonction
                            } else {
                                desactiveLoader();
                                postAjaxFormOnError(target, content.message);
                            }
                        }
                    });
                });
        </script>";

        return $JS;
    }
}
