'use strict';
define(function() {
  var fixedHeaderTable = function($timeout) {
    return {
      restrict: 'EA',
      scope: {
        mode: '@',
        tableGuid: '=?',
        dontUseIt: '=?',
        noOffset: '=?'
      },
      link: function(scope, elt) {
        var table = elt[0],
          innerWraper = elt.find('.fixInner')[0],
          fixThs = table.getElementsByClassName('fixTh'),
          searchToggle = elt.find('.toggleSearch'),
          realths = table.getElementsByTagName('th');

        const setWidth = () => {
          // do not resize when table is empty
          if (table.getElementsByClassName('fixedTbodyLine').length == 0)
            return;

          // ignore first th
          for (var i = 0; i < realths.length / 2; i++) {
            // headers
            if (fixThs[i]) {
              var hWidth =
                realths[i].offsetWidth == 0 ? 100 : realths[i].offsetWidth;
              // first row has a 30px left padding
              if (i == 0) hWidth -= 30;
              fixThs[i].style.width = hWidth + 'px';
              // also set the th width so it wont reset when the table is empty
              realths[i].style.width = hWidth + 'px';
            }

            // search tr
            if (fixThs[i + realths.length / 2]) {
              fixThs[i + realths.length / 2].style.width =
                realths[i].offsetWidth + 'px';
            }
          }

          // fixes table width

          $timeout(function() {
            elt
              .find('.table')
              .css('min-width', elt.find('.table')[0].offsetWidth + 'px');
          });

          //console.log(hWidth);
        };

        var cancelFirstNullResult = true;

        /**
         * Cette fonction est utilisée pour aligner les entêtes d'une table
         * avec ses colonnes de données.
         *
         * Voici un résumé de ce que fait la fonction :
         *
         * 1. Elle vérifie d'abord si la table n'a pas de résultats.
         *    Si c'est le cas et que cancelFirstNullResult est true, elle sort de la fonction.
         * 2. Elle obtient la rectangle client de la table.
         * 3. Elle vérifie si la table a des lignes de données.
         *    Si c'est le cas, elle obtient la première ligne de colonnes de données.
         * 4. Ensuite, elle itère sur chaque entête (`fixThs`), et
         *    colonne de données correspondante. Si la colonne de données n'existe pas,
         *    elle suppose qu'il s'agit d'un filtre
         *    et obtient la colonne de données correspondante de l'itération précédente.
         * 5. Elle calcule la position relative de l'entête fixe en soustrayant la position gauche
         *    de la table de la position gauche de la colonne de données.
         * 6. Elle définit la position gauche de l'entête fixe sur la position relative calculée.
         *
         * En résumé, cette fonction aligne les entêtes d'une table avec ses colonnes de données,
         * en prenant en compte le nombre de résultats et la taille de la table.
         *
         */
        var setThPosition = function() {
          //console.log('setThPosition');

          // Quand le nombre de resultats passe a 0,
          // il y a un glitch qui decale toutes les colonnes vers la gauche dans le cas
          // des tableaux tres larges qui sont resizes violemment
          // par le navigateur (chrome en tout cas)
          // on annule donc ici ce comportement
          const fixedTbodyLine = table.getElementsByClassName('fixedTbodyLine');
          if (cancelFirstNullResult && !fixedTbodyLine.length) {
            cancelFirstNullResult = false;
            return;
          }

          const origineRect = table.getClientRects()[0];
          // et on le reactive des qu'on a au moins un resultat
          let cols;
          if (fixedTbodyLine.length) {
            cancelFirstNullResult = true;
            if (fixedTbodyLine && fixedTbodyLine.length) {
              cols = fixedTbodyLine[0].getElementsByTagName('td');
            }
          }

          // -- Alignement des colonnes d'entêtes (titre de colonne et filtres)
          // -- avec les colonnes de données.
          let delta=0; // -- Pour gestion du regoupement de colonnes (colspan).
          for (let i = 0; i < fixThs.length; i++) {
            let colInd = i + delta;
            let col = cols[colInd];
            if (!col) {
              // -- Quand col n'existe pas pour l'indice i,
              // -- c'est parceque l'on traite la liste des filtres
              // -- (liste qui suit celle des entêtes de colonnes dans la liste fixThs).
              colInd = i-fixThs.length/2;
              if (colInd===0) {
                // -- On attaque la liste des filtres
                delta = 0;
              }
              colInd += delta;
            }
            col = cols[colInd];
            if (col) {
              // -- Calcul de la position relative de la div de l'intitulé ou du filtre.
              // -- La position relative est le delta entre la position absolue de la table
              // -- et la position absolue de la colonne de données correspondante.
              const colRect = col.getClientRects()[0];
              fixThs[i].style.left = colRect.left - origineRect.left + 'px';
            }
            // -- Gestion du colSpan qui est utilisé dans les liste de l'administartion
            // -- où chaque bouton d'action est dans une colonne dans la partie des données,
            // -- mais qui correspond à un regroupement des N colonnes de commandes
            // -- dans la partie entête.
            // -- Quand des colonnes sont regroupées dans l'entête,
            // -- il faut les passer dans la partie données pour être en phase
            // -- entre la partie entête et la partie données et la partie des données.
            const colSpan = fixThs[i].parentElement.colSpan;
            if (colSpan && colSpan!=1) {
              delta = fixThs[i].parentElement.colSpan - 1;
            }
          }
        };

        const setThPositionWithoutOffset = () => {
          if (
            cancelFirstNullResult &&
              !table.getElementsByClassName('fixedTbodyLine').length
          ) {
            cancelFirstNullResult = false;
            return;
          }
          // et on le reactive des qu'on a au moins un resultat
          if (table.getElementsByClassName('fixedTbodyLine').length)
            cancelFirstNullResult = true;

          var decalLeft = 0;
          for (var i = 0; i < fixThs.length; i++) {
            if (i == realths.length / 2) decalLeft = 0;
            fixThs[i].style.left = decalLeft + 8 + 'px';
            decalLeft += realths[i].offsetWidth;
          }
        };

        if (!scope.dontUseIt) {
          searchToggle.bind('click', () => {
            $timeout(() => {
              if (scope.noOffset){
                setWidthWithoutOffset();
                setThPositionWithoutOffset();
              }else{
                setWidth();
                setThPosition();
              }
            }, 0);
          });

          // RB 11/2017
          // set width a first time when the table data is set
          // + remove width auto on the table which kept changing td width
          var alreadySet = false;
          scope.$on('dataTable_DataLoaded', function(a, e) {
            if (e.table_guid == scope.tableGuid) {
              if (!alreadySet) {
                $timeout(function() {
                  // -- Appel commenté le 22/02/2024 car l'affectation d'une largeur faite
                  // -- dans cette fonction désorganise la datatable dans le cas
                  // -- de la vue tabulaire des DICTs (premiere table ok,
                  // -- les suivantes maldimensionnées).
                  // -- Un test d'affichage d'autres datables ne reléve pas de désorganisation
                  // -- suite à cette mise en commentaire.
                  // setWidth();
                  alreadySet = true;
                  // enleve le width auto sur la table
                  table.style.width = 'inherit';
                });
              }
            }
          });
        }

        // scroll the headers when scrolling the innerWrapper
        // @FIX RB 09/2016
        // To make it work with firefox, we need to compute the left property,
        // and not the negative marginleft
        if (angular.isDefined(innerWraper)) {
          innerWraper.onscroll = () => {
            setThPosition();
          };
        }

        const setWidthWithoutOffset = () => {
          // do not resize when table is empty
          if (table.getElementsByClassName('fixedTbodyLine').length == 0)
            return;

          let tempWidth = [];

          // ignore first th
          for (let i = 0; i < realths.length / 2; i++) {
            // headers
            if (fixThs[i]) {
              let hWidth =
                  realths[i].offsetWidth === 0 ? 100 : realths[i].offsetWidth;

              // first row has a 30px left padding
              if (i === 0) hWidth -= 30;
              fixThs[i].style.width = hWidth + 'px';
              // also set the th width so it wont reset when the table is empty
              tempWidth[i] = hWidth + 'px';
            }

            // search tr
            if (fixThs[i + realths.length / 2]) {
              fixThs[i + realths.length / 2].style.width = tempWidth[i];
            }

            // fixes table width

            $timeout(() => {
              elt
                .find('.table')
                .css('min-width', elt.find('.table')[0].offsetWidth + 'px');
            });
          }
        };
      },
    };
  };

  fixedHeaderTable.$inject = ['$timeout'];
  return fixedHeaderTable;
});
