'use strict';
define(function() {
  const bizeditreverseline = ($filter, SelectManager, ogcFactory, gclayers, gcStyleFactory,
      EditTypesFactory, gcInteractions) => {
    return {
      templateUrl: 'js/XG/widgets/mapapp/bizedition/views/bizeditreverseline.html',
      restrict: 'E',
      scope: {
        map: '=',
        editdescription: '=',
        createeditdescription: '&',
        isActive: '=isactive',
        toolbarwidget: '=?',
        reset: '&',
        selectfti: '=',
        save: '&',
        resetMenuContext: '&'
      },
      link: (scope) => {

        /**
         * Méthode appelée au clic sur le bouton correspondant à cette directive.
         * @returns {undefined}
         */
        scope.startAction = () => {
          scope.reset();
          //Activation si désactivé et desactivation si activé
          //(la mise à jour de isActive n'a pas encore eu lieu à ce niveau,
          //on a ici encore la valeur de 'isactive' tel qu'elle était avant l'appel de reset() )
          scope.isActive = !scope.isActive;
          dragBox.setActive(scope.isActive);
          if (!scope.isActive) {
            return;
          }

          scope.selectedFeatures = []; //.splice(0);

          scope.editdescription = scope.createeditdescription();
          scope.editdescription.editType = EditTypesFactory.editTypes.reverse.name;
          scope.editdescription.fti = scope.selectfti;

          scope.selectfeaturesToUpdate();
        };

        /**
         * Utilitaire: indique si le feature passé en paramètre appartient déjà à la sélection.
         * @param {ol.Feature} featureToCheck objet openlayers dont on évalue la présence dans le tableau selectedFeatures
         * @return {Boolean} true si feature en paramètre appartient déjà à la sélection sinon false
         */
        const isFeatureToAdd = (featureToCheck) => {
          return !scope.selectedFeatures.some(feature => feature.getId() === featureToCheck.getId());
        };

        const onSelectionResult = (result, evt) => {
          //Instanciation de l'objet editdescription à chaque nouvelle sélection si on veut prendre en compte
          //dynamiquement les changement de type de sélection
          //                    scope.createeditdescription();
          //                    scope.editdescription.editType = EditTypesFactory.editTypes.update.name;
          //                    scope.editdescription.fti = scope.selectfti;
          //                    //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
          //                    scope.editdescription.interactions.push(dragBox);
          //
          require('toastr').clear();
          if (result.data.features === undefined || result.data.features.length === 0) {
            require('toastr').warning($filter('translate')('bizedition.attributesPopupNoResult'));
            return;
          }

          gclayers.getDrawLayer().getSource().clear();

          //Decodage de la featureCollection, (le decodage retourne un tableau de ol.feature)
          if (scope.selectionType.value === 'new') {
            scope.selectedFeatures = GEOJSON_FORMAT.readFeatures(result.data);
          }
          //Si la sélection actuelle d'objets doit s'ajouter à la précedente sélection
          else if (scope.selectionType.value === 'add') {
            //Récupération de la nouvelle sélection
            let partialSelection = GEOJSON_FORMAT.readFeatures(result.data);
            //Filtrage pour ne récupérer que des nouveaux features non précedement sélectionnés
            partialSelection = partialSelection.filter(isFeatureToAdd);
            //Ajout des nouveaux features à la sélection
            scope.selectedFeatures = scope.selectedFeatures.concat(partialSelection);
          }
          //Par defaut, nouvelle sélection
          else {
            scope.selectedFeatures = GEOJSON_FORMAT.readFeatures(result.data);
          }

          //Mise en evidence des features sélectionnés
          gclayers.getselectSource().clear();
          gclayers.getselectSource().addFeatures(scope.selectedFeatures);
          if (scope.selectfti.typeInfo !== 'POINT' && scope.selectfti.typeInfo !== 'MULTIPOINT') {
            const vertStyle = gcStyleFactory.getStyle('verticeShow');
            for (let ind = 0; ind < scope.selectedFeatures.length; ind++) {
              scope.selectedFeatures[ind].setStyle(vertStyle);
            }
          }
          //Suppression des eventuels precedents features presents
          //dans editDescription
          if (!scope.editdescription.relatedfeatures0) {
            scope.editdescription.relatedfeatures0 = [];
          }
          scope.editdescription.editedfeature = undefined;
          scope.editdescription.relatedfeatures.splice(0);
          scope.editdescription.relatedfeatures0.splice(0);
          scope.editdescription.shareObjects.splice(0);
          scope.editdescription.geometryStatus = '';

          if (scope.selectedFeatures.length === 0) {
            scope.resetMenuContext();
          }
          //EditDescription: On ne prend en compte qu'un seul objet,
          //le premier sélectionné.

          if (scope.selectedFeatures.length > 0) {
            scope.fCollection = new ol.Collection();

            scope.editdescription.editedfeature = scope.selectedFeatures[0];
            scope.editdescription.editedfeature0 = scope.selectedFeatures[0].getProperties();
            //-- Si on resélectionne le même objet, saved sera à "true" et
            //-- ce n'est pas bon. Il faut donc forcer la valeur à "false"
            //-- afin de prendre en compte les prochaines modifications.
            scope.editdescription.editedfeature.saved = false;
            // ajout des differentes actions au niveau du bouton droit (les actions dependent du type de geometry)

            scope.fCollection.push(scope.editdescription.editedfeature);
            //Visualisation

            for (let i = 1; i < scope.selectedFeatures.length; i++) {
              const relatFeature = scope.selectedFeatures[i];
              scope.fCollection.push(relatFeature);
              const newObject = {
                shareObject: '',
                editType: EditTypesFactory.editTypes.reverse.name,
                feature: relatFeature,
                fti: scope.editdescription.fti,
              };
              scope.editdescription.relatedfeatures.push(newObject);
              scope.editdescription.relatedfeatures0.push(newObject.feature.getProperties());
            }
            scope.editdescription.geometryStatus = 'toReverse';
            gcInteractions.setCurrentToolBar(scope.toolbarwidget);
          }
        };

        /**
         * Active une méthode de sélection de features
         * @returns {undefined}
         */
        scope.selectfeaturesToUpdate = function() {

          // laisse uniquement zoom+/- dans le menu contextuel
          scope.resetMenuContext();

          //Si option de sélection de features par dessin d'un polygone
          if (scope.selectionMode.value === 'polygon') {
            scope.map.removeInteraction(dragBox);
            gcInteractions.setCurrentToolBar(scope.toolbarwidget);
            draw.setActive(true);
            scope.map.addInteraction(draw);
            //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
            scope.editdescription.interactions.push(draw);
          } else if (scope.selectionMode.value === 'query') {
            scope.map.removeInteraction(dragBox);
            scope.map.removeInteraction(draw);
            const res = {data: SelectManager.getFeaturesByftiType(scope.selectfti.name)};
            onSelectionResult(res, {});
          } else {
            scope.map.removeInteraction(draw);
            gcInteractions.setCurrentToolBar(scope.toolbarwidget);
            dragBox.setActive(true);
            scope.map.addInteraction(dragBox);
            //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
            scope.editdescription.interactions.push(dragBox);
          }
          scope.interactionOn.value = true;
        }; //end select

        /******************
         *                *
         * INITIALISATION *
         *                *
         ******************/

        const GEOJSON_FORMAT = new ol.format.GeoJSON();
        scope.interactionOn = { value: true };
        scope.selectionMode = { value: 'normal' };
        scope.selectionType = { value: 'add' };

        //Interaction de dessin d'un cadre pour sélectionner des features sur la carte.
        const draw = new ol.interaction.Draw({
          type: 'Polygon',
        });
        draw.setActive(scope.isActive);

        /**
         * Handler de fin de dessin de polygone de sélection d'objet sur la carte.
         * Permetr de requeter les objets features de la couche sélectionnée, situés à l'intérieur du dessin.
         */
        draw.on('drawend', function(evt) {
          //Fermeture de l'eventuelle popup déjà ouverte.
          if (scope.p != undefined && scope.p.element != null) {
            scope.p.destroy();
          }

          //if (scope.modifyInteraction) map.removeInteraction(scope.modifyInteraction);
          //Récupération de la géométrie dessinée
          const polygon = evt.feature.getGeometry();
          const srid = scope.map.getView().getProjection().getCode();
          // résultat de la sélection
          ogcFactory.findIntersectedFeaturesByPolygon(polygon, srid, scope.editdescription.fti.uid).then(
              res => {
                onSelectionResult(res, evt);
              },
              error => {
                console.error('ogcFactory.getfeatures, error:' + error);
                require('toastr').error(error);
              }
          );
        });

        const 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.isActive
            ); /* ||
                      (gaBrowserSniffer.mac && evt.originalEvent.metaKey);*/
          },
          style: gcStyleFactory.getStyle('selectrectangle'),
        });
        dragBox.set('gctype', 'kis');
        dragBox.set('interaction', 'Select');
        dragBox.set('widget', 'Edition');
        dragBox.setActive(scope.isActive);

        //Interaction de dessin d'un polygone pour sélectionner des features sur la carte.
        dragBox.on('boxend', (evt) => {
          if (scope.p !== undefined && scope.p.element != null) {
            scope.p.destroy();
          }

          //Recherche des objets intersectés par le polygone de sélection
          const extent = dragBox.getGeometry().getExtent();
          const srid = scope.map.getView().getProjection().getCode();
          //Résultat de la sélection
          ogcFactory.findIntersectedFeaturesByRectangle(extent, srid,
              scope.editdescription.fti.uid, 'edition').then(
              res => {
                onSelectionResult(res, evt);
              },
              error => {
                console.error('select feature() ogcFactory.getfeatures, error:' + error);
                require('toastr').error(error);
              }
          );
        });
      }
    };
  };
  bizeditreverseline.$inject = ['$filter', 'SelectManager', 'ogcFactory', 'gclayers',
    'gcStyleFactory', 'EditTypesFactory', 'gcInteractions'];
  return bizeditreverseline;
});
