'use strict';
define(function() {
  let geolocationDirective = function($window, gcStyleFactory) {
    return {
      templateUrl: 'js/XG/widgets/mapapp/geolocation/views/geolocation.html',

      restrict: 'A',

      link: function(scope, element) {
        let btnElt = $(element.children()[0]);
        //ALERT
        if (!('geolocation' in $window.navigator)) {
          btnElt.addClass('btn-danger');
          return;
        }
        // This boolean defines if the user has moved the map itself after the
        // first change of position.
        let userTakesControl = false;
        // Defines if the geolocation control is zooming
        let geolocationZooming = false;
        let map = scope.map;

        let view = map.getView();
        scope.$on('mapViewChanged', function() {
          view = map.getView();
        });
        let accuracyFeature = new ol.Feature();
        let positionFeature = new ol.Feature();
        /*   var featuresOverlay = new ol.FeatureOverlay({
                        features: [accuracyFeature, positionFeature],
                        style: gcStyleFactory.getStyle('geolocation')
                      });*/
        let styleGeolocation = gcStyleFactory.getStyle('geolocation');
        let featuresOverlay = new ol.layer.Vector({
          map: map,
          source: new ol.source.Vector({
            features: [accuracyFeature, positionFeature],
            useSpatialIndex: false, // optional, might improve performance
          }),
          style: styleGeolocation,
          updateWhileAnimating: true, // optional, for instant visual feedback
          updateWhileInteracting: true, // optional, for instant visual feedback
        });
        let geolocation = new ol.Geolocation({
          trackingOptions: {
            maximumAge: 10000,
            enableHighAccuracy: true,
            timeout: 600000,
          },
        });

        // Animation
        // used to having a zoom animation when we click on the button,
        // but not when we are tracking the position.
        let first = true;
        let currentAccuracy = 0;
        let locate = function() {
          geolocationZooming = true;
          let dest = geolocation.getPosition();
          if (dest) {
            let source = view.getCenter();
            let dist = Math.sqrt(
              Math.pow(source[0] - dest[0], 2),
              Math.pow(source[1] - dest[1], 2)
            );
            let duration = Math.min(
              Math.sqrt(300 + (dist / view.getResolution()) * 1000),
              3000
            );
            let start = +new Date();
            /*var pan = ol.animation.pan({
              duration: duration,
              source: source,
              start: start
            });*/
            let pan = {
              duration: duration,
              source: source,
              start: start,
            };
            let bounce;
            let resolution;
            if (first) {
              first = false;
              let extent = [
                dest[0] - currentAccuracy,
                dest[1] - currentAccuracy,
                dest[0] + currentAccuracy,
                dest[1] + currentAccuracy,
              ];
              let size = map.getSize();
              resolution = Math.max(
                (extent[2] - extent[0]) / size[0],
                (extent[3] - extent[1]) / size[1]
              );
              resolution = view.constrainResolution(resolution, 0, 0);
              bounce = {
                duration: duration,
                resolution: Math.max(
                  view.getResolution(),
                  dist / 1000,
                  // needed to don't have up an down and up again in zoom
                  resolution * 1.2
                ),
                start: start,
              };
              let zoom = {
                resolution: view.getResolution(),
                duration: duration,
                start: start,
              };
              //map.beforeRender(pan, zoom, bounce);
              view.animate(pan, zoom, bounce);
              view.setCenter(dest);
              view.setResolution(resolution);
            } else if (!userTakesControl) {
              bounce = {
                duration: duration,
                resolution: Math.max(view.getResolution(), dist / 1000),
                start: start,
              };
              //map.beforeRender(pan, bounce);
              view.animate(pan, bounce);
              view.setCenter(dest);
            }
          }
          geolocationZooming = false;
        };

        let updatePositionFeature = function() {
          if (geolocation.getPosition()) {
            positionFeature.setGeometry(new ol.geom.Point(geolocation.getPosition()))
          }
        };

        let updateAccuracyFeature = function() {
          if (geolocation.getPosition() && geolocation.getAccuracy()) {
            accuracyFeature.setGeometry(
              new ol.geom.Circle(
                geolocation.getPosition(),
                geolocation.getAccuracy()
              )
            );
          }
        };

        // Geolocation control events
        geolocation.on('change:position', function() {
          btnElt.removeClass('btn-danger');
          btnElt.addClass('ga-geolocation-tracking');
          locate();
          updatePositionFeature();
          updateAccuracyFeature();
        });

        geolocation.on('change:accuracy', function() {
          currentAccuracy = geolocation.getAccuracy();
          updateAccuracyFeature();
        });

        geolocation.on('change:tracking', function() {
          let tracking = geolocation.getTracking();
          if (tracking) {
            first = true;
            userTakesControl = false;
            featuresOverlay.setMap(map);
          } else {
            // stop tracking
            btnElt.removeClass('ga-geolocation-tracking');
            featuresOverlay.setMap(null);
          }
        });

        geolocation.on('error', function() {
          btnElt.removeClass('ga-geolocation-tracking');
          btnElt.addClass('btn-danger');
        });

        // Geolocation control bindings
        geolocation.setProjection(view.getProjection());

        // View events
        let updateUserTakesControl = function() {
          if (!geolocationZooming) {
            userTakesControl = true;
          }
        };
        view.on('change:center', updateUserTakesControl);
        view.on('change:resolution', updateUserTakesControl);

        // Button event
        btnElt.bind('click', function(e) {
          e.preventDefault();
          let tracking = !geolocation.getTracking();
          geolocation.setTracking(tracking);
          if (tracking) {
            btnElt.addClass('ga-geolocation-tracking');
            btnElt.removeClass('btn-default');
            btnElt.addClass('btn-info');
          } else {
            btnElt.removeClass('ga-geolocation-tracking');
            btnElt.removeClass('btn-info');
            btnElt.addClass('btn-default');
          }
          try {
            scope.$apply(function() {
              /* gaPermalink.updateParams({
                geolocation: tracking ? 'true' : 'false'
              });*/
            });
          } catch(err) {}
        });

        scope.$on('closeToolsBar_geolocationdirective', function() {
          btnElt.removeClass('btn-info');
          btnElt.addClass('btn-default');
          btnElt.removeClass('ga-geolocation-tracking');
          geolocation.setTracking(false);
        });
      },
    };
  };

  geolocationDirective.$inject = ['$window', 'gcStyleFactory'];
  return geolocationDirective;
});
