'use strict';
define(function() {
  /*
   * Params :
   * map /
   */
  var atlas = function(
    gcStyleFactory,
    $filter,
    gaDomUtils,
    ogcFactory,
    GeometryFactory,
    $interval
  ) {
    return {
      templateUrl:
        'js/XG/modules/rights/views/directives/restrictionSelection.html',
      restrict: 'E',
      scope: {
        map: '=',
        result: '=',
        type: '=',
      },
      link: function (scope) {
        let mapSrid = 'EPSG:3857';
        scope.selection = {
          Polygon: {
            active: false,
          },
          MultiPolygon: {
            active: false,
          },
          type: undefined,
          editMode: undefined,
          layer: undefined,
          result: {},
          geometry: undefined,
          showSelectedLayers: false,
        };

        var sourceFeature = new ol.source.Vector({
          //create empty vector
        });

        scope.selection.layer = new ol.layer.Vector({
          source: sourceFeature,
          style: gcStyleFactory.getStyle('edit'),
        });

        var validFeature = new ol.source.Vector({
          //create empty vector
        });

        scope.selection.validatedlayer = new ol.layer.Vector({
          source: validFeature,
          style: gcStyleFactory.getStyle('highlight'),
        });

        if (scope.result) {
          var feat = {
            geometry: scope.result,
            properties: {},
            type: 'Feature',
          };
          scope.selection.result = {
            type: 'FeatureCollection',
            features: [feat],
          };
          var GEOJSON_FORMAT = new ol.format.GeoJSON();
          var feature = GEOJSON_FORMAT.readFeature(feat);
          scope.selection.validatedlayer.getSource().addFeature(feature);
          scope.selection.validatedlayer.setVisible(true);
        }

        scope.pointer = new ol.interaction.Draw({
          type: 'MultiPolygon',
          style: gcStyleFactory.getStyle('edit'),
        });

        scope.pointer.set('gctype', 'kis');
        scope.pointer.set('interaction', 'Draw');
        scope.pointer.set('widget', 'Restriction');

        scope.pointer.on('drawstart', function() {
          scope.selection.startedEdit = true;
        });

        scope.pointer.on('drawend', function(evt) {
          try {
            if (scope.selection.type === 'Polygon') {
              clearLayer(scope.selection.layer);
              scope.selection.layer.getSource().addFeature(evt.feature.clone());
            } else {
              scope.selection.layer.getSource().addFeature(evt.feature.clone());
            }
            scope.selection.layer.getSource().addFeature(evt.feature.clone());

            if (!scope.selection.layer.getVisible())
              scope.selection.layer.setVisible(true);

            scope.selection.tovalidate = true;
            require('toastr').info(
              $filter('translate')('rights.restriction.map.validatedessin')
            );
          } catch (e) {
            require('toastr').info(
              $filter('translate')('rights.restriction.map.erreur')
            );
            scope.result = scope.selection.geometry = undefined;
          }
        });

        var dragBoxStyle = gcStyleFactory.getStyle('selectrectangle');
        scope.dragBox = new ol.interaction.DragBox({
          type: 'Polygon',
          style: dragBoxStyle,
        });

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

        scope.dragBox.on('boxend', function() {
          try {
            var wktObj = new ol.format.WKT();
            var wktStr = wktObj.writeGeometry(scope.dragBox.getGeometry());
            var spatialClause = 'INTERSECTS(geom, ' + wktStr + ')';
            var filter = getFtiudsForSelection();
            if (filter !== '') {
              const promise = ogcFactory.getfeatures('GetFeature','WFS',
                '1.0.0', filter, 'json', mapSrid, spatialClause);
              promise.then(
                (res) => {
                  const geoms = [];
                  if (
                    res.data &&
                    res.data.features &&
                    res.data.features.length > 0
                  ) {
                    if (res.data.features.length > 1) {
                      res.data.features.map(function(x) {
                        if (x.geometry) geoms.push(x.geometry);
                      });
                      gaDomUtils.showGlobalLoader();
                      GeometryFactory.unionifpossible(geoms).then(
                        function(res) {
                          try {
                            if (res.data)
                              createFeatureCollectionFromGeometries(res.data);
                          } catch (e) {
                            console.error(e);
                          }
                          gaDomUtils.hideGlobalLoader();
                        },
                        function() {
                          gaDomUtils.hideGlobalLoader();
                          require('toastr').info(
                            $filter('translate')(
                              'rights.restriction.map.nofeatures'
                            )
                          );
                        }
                      );
                    } else {
                      try {
                        if (res.data.features[0].geometry)
                          createFeatureCollectionFromGeometries(
                            res.data.features[0].geometry
                          );
                      } catch (e) {
                        console.error(e);
                      }
                    }
                  }
                },
                function() {
                  require('toastr').info(
                    $filter('translate')('rights.restriction.map.nofeatures')
                  );
                }
              );
            } else {
              require('toastr').info(
                $filter('translate')(
                  'rights.restriction.map.nolayersingeocatalogue'
                )
              );
              if (
                !angular.element('#collapse-target-restriction').hasClass('in')
              ) {
                angular.element('#collapse-restriction').click();
                if (
                  angular
                    .element('#collapse-restriction')
                    .scope()
                    .Layers.getLength() === 0
                )
                  angular.element('#configuration-restriction').click();
              } else {
                if (
                  angular
                    .element('#collapse-restriction')
                    .scope()
                    .Layers.getLength() === 0
                )
                  angular.element('#configuration-restriction').click();
              }
            }
          } catch (e) {
            require('toastr').info(
              $filter('translate')(
                'rights.restriction.map.nolayersingeocatalogue'
              )
            );
            if (
              !angular.element('#collapse-target-restriction').hasClass('in')
            ) {
              angular.element('#collapse-restriction').click();
              if (
                angular
                  .element('#collapse-restriction')
                  .scope()
                  .Layers.getLength() === 0
              )
                angular.element('#configuration-restriction').click();
            } else {
              if (
                angular
                  .element('#collapse-restriction')
                  .scope()
                  .Layers.getLength() === 0
              )
                angular.element('#configuration-restriction').click();
            }
            scope.result = scope.selection.extent = undefined;
          }
        });


        const addInteractionAndLayers = () => {
          var layers = scope.map.getLayers();
          layers.insertAt(11, scope.selection.layer);
          layers.insertAt(9, scope.selection.validatedlayer);
          scope.pointer.setActive(false);
          scope.dragBox.setActive(false);
          scope.map.addInteraction(scope.dragBox);
          scope.map.addInteraction(scope.pointer);
          if (scope.result)
            scope.map.getView().fit(
              scope.selection.validatedlayer
                .getSource()
                .getFeatures()[0]
                .getGeometry()
                .getExtent(),
              scope.map.getSize()
            );
        };


        /**
         * Une fois la carte dessinée, ajouter les interactions OpenLayers
         * pour permettre la sélection et autres manipulations.
         *
         * @param {*} evt : evenement OpenLayers aprés dessin
         * @param {*} param : description de la carte OpenLayers
         */
        const defineInteractionsOnMap = (evt,param) => {
          if (param !== undefined) {
            scope.map = param.map;
            mapSrid = param.mapSrid;
          }
          let stop = $interval(() => {
            if (scope.map) {
              scope.map.once('postrender', addInteractionAndLayers);
              $interval.cancel(stop);
            }
          }, 600);
        };
        defineInteractionsOnMap();


        scope.$on('retrictionMapChanged', defineInteractionsOnMap);


        function clearLayer(l) {
          if (l.getSource().getFeatures().length > 0) {
            var features = l.getSource().getFeatures();
            features.map(function(feat) {
              try {
                l.getSource().removeFeature(feat);
              } catch (e) {
                console.info(
                  'unable to remove feature Experimental in v 3.6.0'
                );
              }
            });
          }
        }

        scope.createWidget = function(type) {
          if (!scope.pointer.getActive()) {
            scope.selection.type = type;
            scope.selection.editMode = 'create';
            clearLayer(scope.selection.layer);
            scope.pointer.setActive(true);
          } else {
            scope.pointer.setActive(false);
          }
        };

        function buildPolygonsforLayerEdit() {
          var GEOJSON_FORMAT = new ol.format.GeoJSON();
          var olf = GEOJSON_FORMAT.writeFeatures(
            scope.selection.validatedlayer.getSource().getFeatures()
          );
          var featurecollection = JSON.parse(olf);
          var realFeaturesPolygon = [];
          featurecollection.features.map(function(f) {
            if (f.geometry.type === 'MultiPolygon') {
              var coordiantes = f.geometry.coordinates;
              coordiantes.map(function(c) {
                var feat = {
                  geometry: {
                    coordinates: c,
                    type: 'Polygon',
                  },
                  properties: {},
                  type: 'Feature',
                };
                realFeaturesPolygon.push(GEOJSON_FORMAT.readFeature(feat));
              });
            } else {
              realFeaturesPolygon.push(GEOJSON_FORMAT.readFeature(f));
            }
          });
          scope.selection.layer.getSource().addFeatures(realFeaturesPolygon);
        }

        scope.editFeature = function() {
          scope.selection.tovalidate = true;
          scope.selection.editMode = 'update';
          scope.historicfeatures = scope.selection.validatedlayer
            .getSource()
            .getFeatures()
            .map(function(x) {
              return x.clone();
            });
          clearLayer(scope.selection.layer);
          buildPolygonsforLayerEdit();
          //scope.selection.layer.getSource().addFeatures(scope.selection.validatedlayer.getSource().getFeatures());
          scope.selection.validatedlayer.setVisible(false);
          scope.selection.layer.setVisible(true);

          if (scope.modifyInteraction)
            scope.map.removeInteraction(scope.modifyInteraction);

          scope.modifyInteraction = new ol.interaction.Modify({
            features: new ol.Collection(
              scope.selection.layer.getSource().getFeatures()
            ),
            deleteCondition: function(event) {
              return (
                ol.events.condition.shiftKeyOnly(event) &&
                ol.events.condition.singleClick(event)
              );
            },
          });

          scope.modifyInteraction.set('gctype', 'kis');
          scope.modifyInteraction.set('interaction', 'Modify');
          scope.modifyInteraction.set('widget', 'Restriction');

          scope.map.addInteraction(scope.modifyInteraction);
        };

        scope.validerSelection = function() {
          scope.selection.startedEdit = false;

          if (scope.modifyInteraction) {
            scope.modifyInteraction.setActive(false);
            scope.map.removeInteraction(scope.modifyInteraction);
          }

          scope.pointer.setActive(false);
          scope.dragBox.setActive(false);

          if (scope.selection.editMode === 'create') {
            if (scope.selection.type === 'Polygon')
              clearLayer(scope.selection.validatedlayer);
            var features = scope.selection.layer
              .getSource()
              .getFeatures()
              .map(function(x) {
                return x.clone();
              });
            scope.selection.validatedlayer.getSource().addFeatures(features);
          } else {
            clearLayer(scope.selection.validatedlayer);
            var features = scope.selection.layer
              .getSource()
              .getFeatures()
              .map(function(x) {
                return x.clone();
              });
            scope.selection.validatedlayer.getSource().addFeatures(features);
          }

          var GEOJSON_FORMAT = new ol.format.GeoJSON();
          var olf = GEOJSON_FORMAT.writeFeatures(
            scope.selection.validatedlayer.getSource().getFeatures()
          );
          scope.selection.result = JSON.parse(olf);

          scope.selection.layer.setVisible(false);
          scope.selection.validatedlayer.setVisible(true);

          scope.selection.tovalidate = false;
          if (scope.selection.result) {
            setResultFromFeatureCollection(scope.selection.result);
          } else {
            require('toastr').error(
              $filter('translate')('itv.correspondance.nofeatureselected')
            );
            scope.result = scope.selection.result = undefined;
          }
        };

        scope.removeSelection = function() {
          scope.selection.startedEdit = false;
          if (scope.modifyInteraction) {
            scope.modifyInteraction.setActive(false);
            scope.map.removeInteraction(scope.modifyInteraction);
          }

          scope.pointer.setActive(false);

          try {
            clearLayer(scope.selection.layer);
            if (scope.selection.editMode !== 'create') {
              clearLayer(scope.selection.validatedlayer);
              scope.selection.validatedlayer
                .getSource()
                .addFeatures(scope.historicfeatures);
              scope.selection.validatedlayer.setVisible(true);
            }
          } catch (e) {
            console.error(e);
          }
          scope.selection.validatedlayer.setVisible(true);
          scope.dragBox.setActive(false);
          scope.selection.layer.setVisible(false);

          scope.selection.tovalidate = false;
        };

        scope.deleteFeaturesSaved = function() {
          var ans = confirm(
            $filter('translate')(
              'model.featuretypes.actions.confirmSuppression'
            )
          );
          if (ans) {
            scope.result = scope.selection.result = undefined;
            clearLayer(scope.selection.validatedlayer);
          }
        };

        function getFtiudsForSelection() {
          var uids = [];
          scope.map.getLayers().forEach(function(l) {
            if (l.selectionable && l.fti && l.fti.uid) uids.push(l.fti.uid);
          });
          return uids.join(',');
        }

        scope.selectObjectsFromMap = function() {
          //scope.selection.tovalidate = true;
          scope.dragBox.setActive(!scope.dragBox.getActive());
        };

        function createFeatureCollectionFromGeometries(geom) {
          var featurecollection = {
            type: 'FeatureCollection',
            features: [
              {
                geometry: geom,
                properties: {},
                type: 'Feature',
              },
            ],
          };

          var GEOJSON_FORMAT = new ol.format.GeoJSON();
          var olf = GEOJSON_FORMAT.readFeatures(featurecollection);
          clearLayer(scope.selection.layer);
          scope.selection.layer.getSource().addFeatures(olf);
          scope.selection.layer.setVisible(true);
          scope.selection.tovalidate = true;
          scope.selection.result = featurecollection;
        }

        function setResultFromFeatureCollection(e) {
          var geometries = [];
          if (!e.features) {
            scope.result = undefined;
            return false;
          }

          e.features.map(function(f) {
            if (f.geometry) {
              if (f.geometry.type == 'Polygon') {
                f.geometry.type = 'MultiPolygon';
                f.geometry.coordinates = [f.geometry.coordinates];
              }
              geometries.push(f.geometry);
            }
          });
          if (geometries.length === 0) {
            scope.result = undefined;
            return false;
          }

          if (geometries.length === 1) {
            scope.result = geometries[0];
          } else {
            gaDomUtils.showGlobalLoader();
            GeometryFactory.unionifpossible(geometries).then(
              function(res) {
                try {
                  if (res.data) {
                    if (res.data.type == 'Polygon') {
                      res.data.type = 'MultiPolygon';
                      res.data.coordinates = [res.data.coordinates];
                    }
                    scope.result = res.data;
                  } else {
                    scope.result = undefined;
                  }
                } catch (e) {
                  console.error(e);
                  scope.result = undefined;
                }
                gaDomUtils.hideGlobalLoader();
              },
              function(res) {
                gaDomUtils.hideGlobalLoader();
                scope.result = undefined;
                require('toastr').error(res.data.message);
              }
            );
          }
        }
      },
    };
  };

  atlas.$inject = [
    'gcStyleFactory',
    '$filter',
    'gaDomUtils',
    'ogcFactory',
    'GeometryFactory',
    '$interval',
  ];
  return atlas;
});
