'use strict';
define(function() {
  var importdiverstwidget = function(
    ImportExportFactory,
    gclayers,
    $filter,
    extendedNgDialog,
    $timeout,
    EditFactory,
    $rootScope,
    gaDomUtils,
    gcStyleFactory,
    SelectManager,
    gcPopup,
    gcRestrictionProvider,
    gcInteractions,
    FeatureTypeFactory,
    SridFactory,
    importdiversservice,
    gaJsUtils,
    RegionalFactory
  ) {
    return {
      templateUrl:
        'js/XG/widgets/mapapp/importdivers/views/importdiverswidget.html',
      restrict: 'A',

      link: function(scope) {
        scope.srids = SridFactory.sridsList;

        scope.geoData = {
          inputsrid: scope.map.getView().getProjection().getCode(),
          isGeographic: false
        };
        scope.geomcolonneType = 'WKT';
        scope.geomcolonneName = '';
        scope.geomcolonneNameX = 'X';
        scope.geomcolonneNameY = 'Y';

        scope.$watch('geoData.isGeographic', () => {
          if (scope.geoData.isGeographic) {
            scope.geoData.inputsrid = scope.map.getView().getProjection().getCode();
          }
        });

        // taille de l'extent quand la layer ne contient qu'un seul point.
        // Evite plantage openlayers
        // modifier cette valeur pour modifier la taille de l'extent
        const DISTANCE = 50;

        scope.dzMemShare = {};
        scope.layers = [];
        scope.waitImport = false;
        scope.applyRules = {value: false};

        /**
         * Création de l'objet contenant les onglets et leur propriétés<br><ul><li>
         * title: nom de l'onglet affiché</li><li>
         * disabled: état courant de l'onglet</li></ul>
         */
        const setTabs = () => {
          scope.tabs = [
            {
              title: $filter('translate')('importexportwidget.import'),
            },
            {
              title: $filter('translate')('importexportwidget.dataset'),
            },
          ];
        };

        // fonction détachée pour pouvoir être exécutée après navigation
        // @see resetViewAfterNavigation
        setTabs();


        scope.dxftabs = {
          activeTab: 0,
        };

        RegionalFactory.getCsvColumnSeparators().then(
            res => {
              scope.separators = res;
              scope.separator = {
                char : scope.separators[0].id
              };
            }
        );

        scope.dateFormats = RegionalFactory.dateFormats;
        scope.dateFormat = {
          format: scope.dateFormats[0]
        };


        /**
         * Lance la conversion du csv en geojson
         * Bascule l'onglet actif sur l'onglet "Filtrer"
         */
        const parser = new ol.format.GeoJSON();

        // récupère l'encodage de texte du portail. Le séparateur CSV est défini ici dans le widget
        const textEncoding = RegionalFactory.getPortalTextEncoding($rootScope.xgos.portal);

        scope.importFile = () => {
          if (scope.geoData.isGeographic && !scope.srids.includes(scope.geoData.inputsrid)) {
            require('toastr').warning(
              $filter('translate')('importdxfwidget.noSridSelected')
            );
            return;
          }
          if (scope.dzMemShare.dropzoneComponent.files.length > 0) {
            scope.waitImport = true;
            ImportExportFactory.getGeoJson(
              scope.dzMemShare.processId,
              scope.map.getView().getProjection().getCode(),
              'csv',
              scope.separator.char,
              scope.geoData.isGeographic,
              scope.geomcolonneType,
              scope.geomcolonneName,
              scope.geomcolonneNameX,
              scope.geomcolonneNameY,
              scope.geoData.inputsrid,
              textEncoding
            ).then((geoJsonResults) =>{
              if (!Array.isArray(geoJsonResults.data)) {
                // toastr pour vérifier la saisie des inputs
                require('toastr').error($filter('translate')('importdxfwidget.importError'));
                require('toastr').warning($filter('translate')('importdiverswidget.checkInputs'));
                scope.waitImport = false;
              } else {

                // Quand on fait deux imports csv de suite,
                // si on n'a pas tout supprimé du premier import
                // alors dans la carte le chargement du second csv s'ajoute aux précédents
                gclayers
                  .getImportLayer()
                  .getSource()
                  .clear();
                if (scope.layers && Array.isArray(scope.layers)) {
                  scope.layers.splice(0,scope.layers.length);
                }

                geoJsonResults.data.map(function (x) {
                  const layersNames = Object.keys(x);
                  angular.forEach(layersNames, function (key) {
                    scope.layers.push({
                      name: key,
                      geojson: x[key],
                    });
                  });
                });

                scope.dxftabs.activeTab = 1;

                for (let i = 0; i < scope.layers.length; i++) {
                  const obj = scope.layers[i];
                  if (scope.geoData.isGeographic) {
                    // converti les features du geojson en ol.feature
                    const features = parser.readFeatures(obj.geojson);
                    scope.layers[i].features = features;
                    // insère les ol.feature dans la couche d'importation
                    gclayers
                      .getImportLayer()
                      .getSource()
                      .addFeatures(features);
                  } else {
                    scope.layers[i].features = obj.geojson;
                  }
                  scope.layers[i].visible = true;
                }

                // vide la dropzone
                scope.dzMemShare.dropzoneComponent.removeAllFiles();

                // passe en mode actif le bouton "fa-eye" des layers
                scope.allv = true;

                if (scope.geoData.isGeographic) {
                  // place la couche d'import sur le dessus
                  const zIndex = gaJsUtils.getZIndexMax(scope.map) + 1;
                  gclayers
                    .getImportLayer().setZIndex(zIndex);
                  // zoom sur les données temporaires
                  scope.zoomAll();
                }
                // copie dans les layers dans le service
                // pour restauration après navigation dans l'application
                importdiversservice.layers = scope.layers;
                importdiversservice.processId = scope.dzMemShare.processId;
                importdiversservice.inputValues = {
                  geoData: scope.geoData,
                  geomcolonneName: scope.geomcolonneName,
                  geomcolonneType: scope.geomcolonneType,
                  geomcolonneNameX: scope.geomcolonneNameX,
                  geomcolonneNameY: scope.geomcolonneNameY,
                  separator: scope.separator.char
                };
              }
              // masque le spinner
              scope.waitImport = false;
            },
            () => {
              // masque le spinner
              scope.waitImport = false;
              require('toastr').error($filter('translate')('importdxfwidget.importError'));
            });
          }
        };

        /**
         * Après conversion du csv en geojson (import)
         * ou bien au clic sur le bouton loupe de l'onglet "Filtrer" du widget:
         * zoom sur tous les éléments de la couche d'import
         * @see scope.importFile
         */

        scope.zoomAll = () => {
          const extent = gclayers
            .getImportLayer()
            .getSource()
            .getExtent();
          if (isExtentAPoint(extent)){
            fitMapToPoint(extent);
          }else {
            scope.map.getView().fit(extent, scope.map.getSize());
          }
        };

        scope.selectionisactive = false;

        scope.dragBox = new ol.interaction.DragBox({
          condition: function(evt) {
            //MacEnvironments don't get here because the event is not
            //recognized as mouseEvent on Mac by the google closure.
            //We have to use the apple key on those devices
            return (
              evt.originalEvent.ctrlKey || scope.selectionisactive
            ); /* ||
                  (gaBrowserSniffer.mac && evt.originalEvent.metaKey);*/
          },
          style: gcStyleFactory.getStyle('selectrectangle'),
        });

        scope.dragBox.set('gctype', 'kis');
        scope.dragBox.set('interaction', 'Select');
        scope.dragBox.set('widget', 'ImportDXF');

        /**
         * Gère l'état commun de la visibilité de chaque couche
         * Si false, vide la couche d'importation KIS
         * Si true, ajoute les layers GPX à la couche d'importation KIS
         */
        scope.toggleAllvisible = () => {
          scope.allv = !scope.allv;
          for (const layer of scope.layers) {
            layer.visible = scope.allv;
          }
          gclayers
            .getImportLayer()
            .getSource()
            .clear();
          if (scope.allv) {
            for (const layer of scope.layers) {
              gclayers
                .getImportLayer()
                .getSource()
                .addFeatures(layer.features);
            }
          }
        };

        scope.dragBox.setActive(false);
        scope.dragBox.on('boxend', function(event) {
          const hasClickOnCtrl = event && event.hasOwnProperty('mapBrowserEvent')
              && event.mapBrowserEvent.hasOwnProperty('originalEvent')
              && event.mapBrowserEvent.originalEvent.ctrlKey;
          if (!hasClickOnCtrl){
            scope.selectedfeatures = [];
          }
          var i = 0;
          gclayers
            .getImportLayer()
            .getSource()
            .forEachFeatureIntersectingExtent(
              scope.dragBox.getGeometry().getExtent(),
              function(feature) {
                feature.set('index', ++i);
                scope.selectedfeatures.push(feature);
              }
            );
          SelectManager.clear();
          try {
            SelectManager.addFeaturesFromGeojson(
              JSON.parse(parser.writeFeatures(scope.selectedfeatures))
            );
          } catch (e) {
            console.info('features n\'ont pas d\'IDs normal');
          }
          boutonDroit();
        });

        scope.selectElementOnMap = function() {
          scope.selectionisactive = !scope.selectionisactive;
          if (!scope.selectionisactive) {
            SelectManager.clear();
            scope.dragBox.setActive(false);
            scope.map.removeInteraction(scope.dragBox);
            scope.selectedfeatures = [];
          } else {
            scope.dragBox.setActive(true);
            gcInteractions.setCurrentToolBar(scope.toolBarWidget);
            scope.map.addInteraction(scope.dragBox);
          }
        };

        function boutonDroit() {
          var Supprimer = [
            $filter('translate')('importdiverswidget.remove'),
            function() {
              scope.removeFeatures();
            },
          ];
          var clear = [
            $filter('translate')('importdiverswidget.abandon'),
            function() {
              clearFeatures();
            },
          ];
          const menu = scope.menuContext;
          if (scope.menuContext && scope.menuContext.length >= 3) {
            scope.menuContext.splice(0, scope.menuContext.length - 2);
            menu.unshift(clear);
            menu.unshift(Supprimer);
          }
        }

        scope.removeFeatures = function() {
          if (scope.selectedfeatures.length > 0) {
            var ans = window.confirm(
              $filter('translate')('common.confirm_action')
            );
            if (ans) {
              var olcol = new ol.Collection(
                gclayers
                  .getImportLayer()
                  .getSource()
                  .getFeatures()
              );
              angular.forEach(scope.selectedfeatures, function(ft) {
                olcol.remove(ft);
              });
              gclayers
                .getImportLayer()
                .getSource()
                .clear();
              gclayers
                .getImportLayer()
                .getSource()
                .addFeatures(olcol.getArray());
              var idxx = [];
              for (var i = 0; i < scope.layers.length; i++) {
                var layer = scope.layers[i];
                var col = new ol.Collection(layer.features);
                angular.forEach(scope.selectedfeatures, function(ft) {
                  col.remove(ft);
                });
                layer.features = col.getArray();
                layer.geojson = JSON.parse(
                  parser.writeFeatures(layer.features)
                );
                layer.geojson.totalFeatures = layer.geojson.features.length;
                if (layer.geojson.totalFeatures === 0) idxx.push(i);
              }
              if (idxx.length > 0) {
                idxx = idxx.reverse();
                idxx.map(function(x) {
                  scope.layers.splice(x, 1);
                });
              }
              // supprime les données sélectionnées sans désactiver le bouton de sélection
              clearFeatures();
              scope.selectElementOnMap();

              // màj des layers dans le service
              importdiversservice.layers = scope.layers;
            }
          } else {
            require('toastr').info(
              $filter('translate')('importdiverswidget.selectObjectfirst')
            );
          }
        };

        const clearFeatures = () => {
          const idx = [];
          if (scope.menuContext) {
            for (var i = 0; i < scope.menuContext.length; i++) {
              if (
                scope.menuContext[i][0] ===
                  $filter('translate')('importdiverswidget.remove') ||
                  scope.menuContext[i][0] ===
                  $filter('translate')('importdiverswidget.abandon')
              ) {
                idx.push(i);
              }
            }
            idx.reverse().map((x) => {
              scope.menuContext.splice(x, 1);
            });
          }
          scope.selectedfeatures = [];
          SelectManager.clear();
          scope.selectionisactive = false;
          scope.dragBox.setActive(false);
          scope.map.removeInteraction(scope.dragBox);
        };

        let pop;
        scope.listFeatures = () => {
          if (SelectManager.getpop()) {
            try {
              if (SelectManager.getpop().element) {
                SelectManager.getpop().destroy();
              }
              if (SelectManager.getpop().scope) {
                SelectManager.getpop().scope.$broadcast('$destroy');
              }
            } catch (e) {
              SelectManager.setpop(null);
            }
          }

          pop = gcPopup.open({
            scope: scope,
            title:
              $filter('translate')('importdiverswidget.features') +
              '<label class="label label-default csvSelectedFeaturesLength">' + scope.selectedfeatures.length + '</label>',
            template:
              'js/XG/widgets/mapapp/importdxf/views/importdxffeatures.html',
            showClose: true,
            minimizeMaximize: true,
            resizable: true,
          });

          SelectManager.setpop(pop);
        };

        scope.highLightFeature = (f) => {
          gclayers.addhighLightFeature(f);
        };
        scope.removehighLightFeature = (f) => {
          $('.csvSelectedFeaturesLength').text('' + scope.selectedfeatures.length);
          gclayers.removehighLightFeatures(f);
        };

        /**
         * Zoom sur une feature d'une couche du CSV
         * Attention! Il faut modifier l'extent en cas de point
         * car fit() sur un extent de point plante (error 32)
         * @param feature objet du CSV spatial dont on récupère l'extent
         */
        scope.zoomOnFeature = (feature) => {
          const extent = feature.getGeometry().getExtent();
          if (isExtentAPoint(extent)){
            fitMapToPoint(extent);
          }else{
            scope.map
              .getView()
              .fit(feature.getGeometry().getExtent(), scope.map.getSize());
          }
        };

        scope.removeFeature = (idx) => {
          scope.selectedfeatures.splice(idx, 1);
          SelectManager.clear();
          try {
            SelectManager.addFeaturesFromGeojson(
              JSON.parse(parser.writeFeatures(scope.selectedfeatures))
            );
          } catch (e) {
            console.info('features n\'ont pas d\'IDs normal');
          }
        };


        /**
         * Au clic sur le bouton "Tout supprimer",
         * <ul><li>
         * vide les items et les fichiers de la dropzone</li><li>
         * reinitialise les inputs du widget</li><li>
         * supprime les layers le processId du service</li><ul>
         *
         */
        scope.clearDropzone = () => {
          const { dropzoneComponent } = scope.dzMemShare;
          if (dropzoneComponent.files.length > 0) {
            dropzoneComponent.removeAllFiles();
          }

          gclayers
            .getImportLayer()
            .getSource()
            .clear();

          scope.layers.splice(0,scope.layers.length);
          // réinitialise les inputs du widget
          // et les variables stockées dans le service
          resetService();
        };

        /**
         * Ajoute les layers visibles dans la couche temporaire
         */
        scope.visible = () => {
          gclayers
            .getImportLayer()
            .getSource()
            .clear();
          let allvisiblelayers = 0;
          for (let i = 0; i < scope.layers.length; i++) {
            if (scope.layers[i].visible) {
              gclayers
                .getImportLayer()
                .getSource()
                .addFeatures(scope.layers[i].features);

              scope.layers[i].visible = true;
              allvisiblelayers++;
            }
          }
          scope.allv = allvisiblelayers === scope.layers.length;
        };

        let dialog;
        scope.copyIn = (layer) => {
          if (dialog) dialog.close();

          scope.selectedLayer = layer;
          //if ( !scope.selectedLayer.importcfg )
          scope.selectedLayer.importcfg = {
            liaisons: {},
            values: {},
            maj: {},
            layer: layer,
            dateattributes: [],
          };

          scope.layerAttributes = Object.keys(
            layer.geojson.features[0].properties
          );

          // personnalise le composant gcimportfeatures
          scope.isCsv=true;

          dialog = extendedNgDialog.open({
            template:
              'js/XG/widgets/mapapp/importdxf/views/importdxftemplate.html',
            className:
              'ngdialog-theme-plain overflowY width600 max-height500 nopadding miniclose',
            closeByDocument: false,
            scope: scope,
            title:
              $filter('translate')('importdiverswidget.copytitle') + layer.name,
            draggable: true,
          });
        };

        scope.save = () => {
          $timeout(() => {
            addFeaturesToFtid(scope.selectedLayer);
            dialog.close();
            resetService();
          });
        };

        //-- Format de la date à envoyer au serveur.
        var FORMAT_DATE = 'yyyy-MM-ddTHH:mm:ss.sssZ';
        var checkDateFormat = function(val) {
          //-- Format de la date dans le fichier CSV.
          var regex = new RegExp(
            '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]',
            'i'
          );
          var searchText = val;
          if (searchText.length > 0 && !regex.test(searchText)) {
            return false;
          } else {
            return true;
          }
        };
        const checkformatAndGetValue = (feature, sourceField) => {
          const value = sourceField ? feature.properties[sourceField] : feature;
          if (typeof value === 'string' && checkDateFormat(value)) {
            try {
              const dateValue = sourceField ? parseDateString(feature, sourceField) : value;
              var date = Date.parse(dateValue);
              var v = $filter('date')(date, FORMAT_DATE);
              return v;
            } catch (e) {
              console.info(value + ' is not a date');
              return value;
            }
          } else {
            return value;
          }
        };

        /**
         * Ajoute / met à jour les lignes du CSV dans le composant
         *
         * @param layer couche temporaire issue du CSV
         */
        function addFeaturesToFtid(layer) {
          gaDomUtils.showGlobalLoader();
          try {
            var geojson = layer.geojson;
            var defaultLayer = angular.copy(geojson);
            const fti = FeatureTypeFactory.getFeatureByUid(
              layer.importcfg.ftid
            );

            // transforme les attributs du csv "oui/non", "vrai/faux", "true/false" mappés vers un champ cible de type "boolean" en true/false
            transformBoolean(geojson.features, layer.importcfg.liaisons, fti);

            // transforme les attributs du csv mappés vers un champ cible de type "Date" ou "Timestamp"
            transformToDateOrTimestamp(geojson.features, layer.importcfg.liaisons, fti);

            angular.forEach(geojson.features, function(feature) {
              // pour chaque ligne/objet du CSV,
              // création des attributs  à partir des associations d'attributs et des valeurs par défaut
              var propnew = {};
              var values = Object.keys(layer.importcfg.values);
              var liaisons = Object.keys(layer.importcfg.liaisons);
              var maj = layer.importcfg.maj;

              if (maj.maj_component && Object.keys(maj.attribut).length > 0){
                if (maj.attribut !== 'fid') {
                  propnew[maj.value.name] = checkformatAndGetValue(feature, maj.attribut);
                } else {
                  feature.id = feature.properties[maj.attribut];
                }
              }

              if (liaisons.length === 0 && values.length === 0) {
                // si aucun champ lié et aucun champ avec valeur par défaut
                propnew = {};
              } else if (liaisons.length > 0 && values.length === 0) {
                // si au moins 1 champ lié et aucun champ avec valeur par défaut
                angular.forEach(layer.importcfg.liaisons, function(value, key) {
                  if (
                    maj.maj_component &&
                    Object.keys(maj.attribut).length > 0 &&
                    key !== maj.attribut
                  ) {
                    propnew[value] = checkformatAndGetValue(feature, key);
                  } else if (!maj.maj_component) {
                    propnew[value] = checkformatAndGetValue(feature, key);
                  }
                });
              } else if (liaisons.length === 0 && values.length > 0) {
                // si aucun champ lié et au moins 1 champ avec valeur par défaut
                angular.forEach(layer.importcfg.values, function(value, key) {
                  if (
                    maj.maj_component &&
                    Object.keys(maj.attribut).length > 0 &&
                    key !== maj.attribut
                  ) {
                    propnew[key] = checkformatAndGetValue(value);
                  } else if (!maj.maj_component) {
                    propnew[key] = checkformatAndGetValue(value);
                  }
                });
              } else {
                // si au moins 1 champ lié et au moins 1 champ avec valeur par défaut
                angular.forEach(layer.importcfg.values, function(value, key) {
                  // créé les propriétés avec valeur par défaut
                  if (
                    maj.maj_component &&
                    Object.keys(maj.value).length > 0 &&
                    key !== maj.value.name
                  ) {
                    propnew[key] = checkformatAndGetValue(value);
                  } else if (!maj.maj_component) {
                    propnew[key] = checkformatAndGetValue(value);
                  }
                });
                angular.forEach(layer.importcfg.liaisons, function(value, key) {
                  let newVal = checkformatAndGetValue(feature, key);
                  // est true
                  // si key existe déjà parmi les propriétés du feature de sortie et
                  // si key fait partie des valeurs par défaut fournies à gcimportfeatures (@see gcimportfeatures defaultValues)
                  const overrideDefault = Object.keys(propnew).indexOf(key) > -1 && Object.keys(layer.importcfg.values).indexOf(key) > -1;

                  if (
                    maj.maj_component &&
                    Object.keys(maj.attribut).length > 0 &&
                    key !== maj.attribut
                  ) {
                    propnew[value] = newVal;
                  } else if (
                    (Object.keys(propnew).indexOf(key) === -1
                     || (propnew[value] === null && newVal !== null)
                     || (overrideDefault && newVal!== null))
                     &&
                    !maj.maj_component
                  ) {
                    propnew[value] = newVal;
                  }
                });
              }
              feature.properties = propnew;
            });

            if (layer.importcfg.maj.maj_component) {
              // mise à jour des objets du composant layer.importcfg.ftid basé sur geojson.features[x].id
              const sendata = {
                attribut: layer.importcfg.maj.value.name,
                geojson: geojson,
              };
              EditFactory.specialUpdate(
                layer.importcfg.ftid,
                sendata,
                fti.srid,
                'false',
                scope.applyRules.value
              ).then(
                (res) => {
                  if (
                    res.data.errors.length === 0 ||
                    res.data.create.length === layer.geojson.features.length
                  ) {
                    // vide la/les couche(s) temporaire(s) du csv
                    for (let i = 0; i < scope.layers.length; i++) {
                      if (scope.layers[i].name === layer.name) {
                        scope.layers.splice(i, 1);
                        break;
                      }
                    }
                    // ajoute les features visibles à la couche d'importation
                    scope.visible();

                    // retourne sur l'onglet "Importer"
                    scope.dxftabs.activeTab = 0;
                    // met à jour les styles,cql_filter,opacity... esri et geoserver
                    $rootScope.$broadcast(
                      'gcOperationalLayerChange',
                      '',
                      'applyall'
                    );
                    gaDomUtils.hideGlobalLoader();
                    require('toastr').success(
                      $filter('translate')('importdiverswidget.updatesuccess') +
                        layer.name
                    );
                  } else {
                    layer.geojson = angular.copy(defaultLayer);
                    gaDomUtils.hideGlobalLoader();
                    require('toastr').error(
                      $filter('translate')('importdiverswidget.copyerror') +
                        layer.name
                    );
                  }
                },
                (result) => {
                  gaDomUtils.hideGlobalLoader();
                  if (
                    result.data &&
                    result.data.code === 403 &&
                    result.data.CLASSTYPE === 'Error' &&
                    result.data.message &&
                    result.data.details
                  ) {
                    gcRestrictionProvider.showDetailsErrorMessage(result);
                  } else {
                    require('toastr').error(
                      $filter('translate')('importdiverswidget.copyerror') +
                        layer.name
                    );
                  }
                }
              );
            } else {
              // ajoute les lignes du CSV dans le composant layer.importcfg.ftid
              EditFactory.add(
                layer.importcfg.ftid,
                geojson,
                scope.map
                  .getView()
                  .getProjection()
                  .getCode(),
                'false',
                scope.applyRules.value
              ).then(
                function(res) {
                  if (
                    res.data.errors.length === 0 ||
                    res.data.create.length === layer.geojson.features.length
                  ) {
                    // vide la/les couche(s) temporaire(s) du csv
                    for (var i = 0; i < scope.layers.length; i++) {
                      if (scope.layers[i].name === layer.name) {
                        scope.layers.splice(i, 1);
                        break;
                      }
                    }
                    // ajoute les features visibles à la couche d'importation
                    scope.visible();

                    // retourne sur l'onglet "Importer"
                    scope.dxftabs.activeTab = 0;

                    // met à jour les styles,cql_filter,opacity... esri et geoserver
                    $rootScope.$broadcast(
                      'gcOperationalLayerChange',
                      '',
                      'applyall'
                    );
                    gaDomUtils.hideGlobalLoader();
                    require('toastr').success(
                      $filter('translate')('importdiverswidget.copysuccess') +
                        layer.name
                    );
                  } else {
                    layer.geojson = angular.copy(defaultLayer);
                    gaDomUtils.hideGlobalLoader();
                    require('toastr').error(
                      $filter('translate')('importdiverswidget.copyerror') +
                        layer.name
                    );
                  }
                },
                function(result) {
                  gaDomUtils.hideGlobalLoader();
                  if (
                    result.data &&
                    result.data.code === 403 &&
                    result.data.CLASSTYPE === 'Error' &&
                    result.data.message &&
                    result.data.details
                  ) {
                    gcRestrictionProvider.showDetailsErrorMessage(result);
                  } else {
                    require('toastr').error(
                      $filter('translate')('importdiverswidget.copyerror') +
                        layer.name
                    );
                  }
                }
              );
            }
          } catch (e) {
            console.error(e.message);
            layer.geojson = angular.copy(defaultLayer);
            gaDomUtils.hideGlobalLoader();
            require('toastr').error(
              $filter('translate')('importdiverswidget.copyerror') + layer.name
            );
          }
        }

        /*scope.$on('openTools_importdiverswidget', function(event, arg) {
          if (
            arg.directive === 'importdiverswidget' &&
            scope.layers &&
            scope.layers.length > 0
          ) {
            scope.dragBox.setActive(true);
            gcInteractions.setCurrentToolBar(scope.toolBarWidget);
            scope.map.addInteraction(scope.dragBox);
          }
        });*/

        scope.$on('closeTools_importdiverswidget', function(event, arg) {
          if (arg.directive === 'importdiverswidget') {
            clearFeatures();
            scope.dragBox.setActive(false);
            scope.map.removeInteraction(scope.dragBox);
          }
        });

        scope.$on('openCloseTools_importdiverswidget', function(event, arg) {
          if (arg.directive === 'importdiverswidget') {
            if (!arg.active) {
              clearFeatures();
              scope.dragBox.setActive(false);
              scope.map.removeInteraction(scope.dragBox);
            } else {
              scope.dragBox.setActive(true);
              gcInteractions.setCurrentToolBar(scope.toolBarWidget);
              scope.map.addInteraction(scope.dragBox);
            }
          }
        });

        /**
         * Vérifie si extent est un point
         * @param extent étendue courante de la carte (Xmin, Ymin, Xmax, Ymax)
         * @returns {boolean} true si l'extent est un point
         */
        const isExtentAPoint = (extent) => {
          if (Array.isArray(extent) && extent.length === 4) {
            return extent[0] === extent[2] && extent[1] === extent[3];
          }
        };

        /**
         * Centre la carte sur un point
         * Utile dans le cas où l'extent est un point (layer ne contenant qu'un seul point)
         * @param extent étendue courante de la carte (Xmin,Ymin,Xmax,Ymax)
         * @see zoomAll
         * @see zoomOnObject
         */
        const fitMapToPoint = (extent) => {
          if (Array.isArray(extent) && extent.length === 4) {
            const pointExtent = [extent[0] - (DISTANCE / 2),
              extent[1] - (DISTANCE / 2), extent[2] + (DISTANCE / 2),
              extent[3] + (DISTANCE / 2)];
            scope.map.getView().fit(pointExtent, scope.map.getSize());
          }
        };

        /**
         * Dans le cas d'un champ boolean, transforme un attribut CSV "oui/non" "vrai/faux" "true/false" en true/false
         * @param features objets du geojson issu du csv
         * @param liaisons objet contenant les mappages entre propriété source du csv et champ cible de la table du composant
         * @param fti featureTypeInfo du composant cible
         */
        const transformBoolean = (features, liaisons, fti) => {

          if (features && liaisons && fti && Object.entries(liaisons).length > 0) {
            for (const feature of features) {
              for (const [champ_source, champ_cible] of Object.entries(liaisons)) {

                // regarde si le champ destination est un boolean et si la propriété source contient les valeurs "oui/non", "true/false", "vrai/faux"
                const ftiAttribute = fti.attributes.find(attr => attr.name === champ_cible);
                const booleanValues = ['oui', 'non', 'true', 'false', 'vrai', 'faux'];
                const trueValues = ['oui', 'true', 'vrai'];
                if (ftiAttribute && ftiAttribute.type === 'java.lang.Boolean'
                    && feature.properties[champ_source] !== null) {
                  if (booleanValues.includes(feature.properties[champ_source].toLowerCase())) {
                    feature.properties[champ_source] = trueValues.includes(feature.properties[champ_source].toLowerCase());
                  }else {
                    // null à toutes valeurs qui ne correspond pas à true/false, vrai/faux, oui/non
                    feature.properties[champ_source] = null;
                  }
                }
              }
            }
          }
        };

        /**
         * Transforme les attributs du csv mappés vers un champ cible de type "Date" ou "Timestamp"
         * @param features objets du geojson issu du csv
         * @param liaisons objet contenant les mappages entre propriété source du csv et champ cible de la table du composant
         * @param fti featureTypeInfo du composant cible
         */
        const transformToDateOrTimestamp = (features, liaisons, fti) => {
          if (features && liaisons && fti && Object.entries(liaisons).length > 0) {
            for (const feature of features) {
              for (const [champ_source, champ_cible] of Object.entries(liaisons)) {

                const ftiAttribute = fti.attributes.find(attr => attr.name === champ_cible);

                if (ftiAttribute.type === 'java.sql.Timestamp') {
                  const date = parseDateString(feature, champ_source);
                  const datetime = Date.parse(date);
                  if (!isNaN(datetime)) {
                    feature.properties[champ_source] = datetime;
                  }
                } else if (ftiAttribute.type === 'java.util.Date') {
                  const preventDateFormat = parseDateString(feature, champ_source);
                  const date = new Date(preventDateFormat);
                  feature.properties[champ_source] = $filter('date')(date, FORMAT_DATE);
                }
              }
            }
          }
        };

        /**
         * Transforme une date d'un format français en format anglais
         * @param feature objet correspondant à une ligne du fichier CSV
         * @param champ_source nom de propriété de l'objet <code>feature.properties</code>
         * @return {number|string} date en string au format anglais
         */
        const parseDateString = (feature, champ_source) => {
          const { dateFormat, dateFormats } = scope;
          if (typeof feature.properties[champ_source] === 'string' && feature.properties[champ_source].length > 0
              && dateFormat && dateFormats.includes(dateFormat.format)) {
            const separator = dateFormat.format.includes('/') ? '/' : '-';
            const dateParts = feature.properties[champ_source].split(separator);
        
            if (dateParts.length === 3) {
              let [part1, part2, part3] = dateParts;
              let formattedDate;
        
              if (dateFormat.format.startsWith('dd')) {
                // dd/MM/yyyy ou dd-MM-yyyy
                formattedDate = `${part2}${separator}${part1}${separator}${part3}`;
              } else if (dateFormat.format.startsWith('MM')) {
                // MM/dd/yyyy ou MM-dd-yyyy
                formattedDate = `${part1}${separator}${part2}${separator}${part3}`;
              } else if (dateFormat.format.startsWith('yyyy')) {
                // Formats commençant par yyyy
                if (dateFormat.format === 'yyyy/MM/dd' || dateFormat.format === 'yyyy-MM-dd') {
                  formattedDate = feature.properties[champ_source]; // Déjà bien formaté
                } else if (dateFormat.format === 'yyyy/dd/MM' || dateFormat.format === 'yyyy-dd-MM') {
                  formattedDate = `${part1}${separator}${part3}${separator}${part2}`;
                }
              }
        
              return formattedDate;
            } else {
              // cas rare de date csv déjà formattée geojson "2018-07-02 00:00:00.0"
              const dateFormatRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d$/;
              if (dateFormatRegex.test(feature.properties[champ_source])) {
                return feature.properties[champ_source];
              }
              // KIS-3137: peux tu indiquer le noms des champs ayant des dates dans le mauvais format STP "Attention, les champs suivants titi,toto,tutu présente une date...."
              require('toastr').warning($filter('translate')('importdiverswidget.dateWarnPrefix')
                  + champ_source + $filter('translate')('importdiverswidget.dateWarn')
                  + '(' + scope.dateFormat.format + ') : ' + feature.properties[champ_source]);
              console.error('IMPORT CSV - ' + $filter('translate')('importdiverswidget.dateError')
                  + '(' + champ_source + ') : ' + feature.properties[champ_source]);
            }
          }
          return feature.properties[champ_source];
        };

        /**
         * Gère l'état commun de la visibilité de chaque couche
         * Si false, vide la couche d'importation KIS
         * Si true, ajoute les layers GPX à la couche d'importation KIS
         */
        scope.toggleAllvisible = () => {
          scope.allv = !scope.allv;
          for (const layer of scope.layers) {
            layer.visible = scope.allv;
          }
          gclayers
            .getImportLayer()
            .getSource()
            .clear();
          if (scope.allv) {
            for (const layer of scope.layers) {
              gclayers
                .getImportLayer()
                .getSource()
                .addFeatures(layer.features);
            }
          }
        };

        /**
         * Restaure la couche du CSV
         * lors d'une ré-ouverture du widget
         * après navigation dans les autres catégories de widgets
         */
        const resetViewAfterNavigation = () => {
          if (importdiversservice.layers){
            if (importdiversservice.processId) {
              scope.dzMemShare.processId = importdiversservice.processId;
            }

            let isGeographic = false;
            if (importdiversservice.inputValues && importdiversservice.inputValues.geoData
                && importdiversservice.inputValues.geoData.isGeographic) {
              isGeographic = importdiversservice.inputValues.geoData.isGeographic;
            }
            if (isGeographic) {
              const extent = gclayers
                .getImportLayer()
                .getSource()
                .getExtent();
              if (isExtentAPoint(extent)) {
                fitMapToPoint(extent);
              } else {
                scope.map.getView().fit(extent, scope.map.getSize());
              }
            }
            scope.layers = importdiversservice.layers;
            scope.dxftabs = {
              activeTab: 1,
            };
            scope.tabs[1].disabled = false;
            // initialise l'intéraction
            scope.selectionisactive = true;
            scope.selectElementOnMap();
          }
          if (importdiversservice.inputValues){
            scope.geoData.inputsrid = importdiversservice.inputValues.geoData.inputsrid;
            scope.geoData.isGeographic = importdiversservice.inputValues.geoData.isGeographic;
            scope.geomcolonneType = importdiversservice.inputValues.geomcolonneType;
            scope.geomcolonneName = importdiversservice.inputValues.geomcolonneName;
            scope.geomcolonneNameX = importdiversservice.inputValues.geomcolonneNameX;
            scope.geomcolonneNameY = importdiversservice.inputValues.geomcolonneNameY;
            if (importdiversservice.inputValues.separator) {
              if (!scope.separator){
                scope.separator = {};
              }
              scope.separator.char = importdiversservice.inputValues.separator;
            }
          }
        };

        // restaure la liste des couches après navigation
        if (importdiversservice.layers && importdiversservice.layers.length > 0) {
          resetViewAfterNavigation();
        }

        /**
         * Après sauvegarde de la couche temporaire
         * ou après clic sur le bouton "Tout Supprimer",
         * supprime les variable stockées dans le services:<ul><li>
         * couche temporaire</li><li>
         * identifiant de l'upload des fichiers déposés</li><li>
         * saisie des inputs du widget</li><ul>
         */
        const resetService = () => {
          importdiversservice.layers = undefined;
          importdiversservice.processId = undefined;
          importdiversservice.inputValues = undefined;
        };
      },
    };
  };

  importdiverstwidget.$inject = [
    'ImportExportFactory',
    'gclayers',
    '$filter',
    'extendedNgDialog',
    '$timeout',
    'EditFactory',
    '$rootScope',
    'gaDomUtils',
    'gcStyleFactory',
    'SelectManager',
    'gcPopup',
    'gcRestrictionProvider',
    'gcInteractions',
    'FeatureTypeFactory',
    'SridFactory',
    'importdiversservice',
    'gaJsUtils',
    'RegionalFactory'
  ];
  return importdiverstwidget;
});
