'use strict';
define(function() {
  var gcscalevalue = function(
    $timeout,
    ApplicationFactory,
    $location,
    $rootScope, gaJsUtils
  ) {
    return {
      restrict: 'EA',
      templateUrl: 'js/XG/widgets/mapapp/scalevalue/views/gcscalevalue.html',

      link: function(scope, element, attrs) {
        var map = scope.map;
        var dDate;

        var forcedScaleValueList;
        var firstTime = true;
        if (angular.isDefined(attrs.scaleValueList)) {
          forcedScaleValueList = attrs.scaleValueList;
        }
        //Used to kill multiple digest on scroll
        if (angular.isDefined(attrs.setInput)) {
          scope.setInput = attrs.setInput;
        }
        scope.noDigestPlease = false;

        var getScaleForResolution = function(resolution, units) {

          const scale = gaJsUtils.resolutionToScale(resolution, units);

          if ($rootScope.xgos.listOfWmsParams != undefined) {
            for (const wmsParams of $rootScope.xgos.listOfWmsParams) {
              wmsParams.scale4Representation = scale;
            }
          }
          $rootScope.xgos.scale4Representation = scale;
          $rootScope.$broadcast('newScaleForResolution');
          return scale;
        };

        /**
         *     Suite au choix d'une échelle par l'utilisateur,
         * on rafraichit la carte pour qu'elle corresponde à l'échelle demandée.
         */
        var setScaleForResolution = function(scale) {
          if (scale == undefined) return;
          var dpi = 90;
          var mpu = ol.proj.METERS_PER_UNIT['m'];
          var inchesPerMeter = 39.37;
          var res = scale / (mpu * inchesPerMeter * dpi);
          map.getView().setResolution(res);
          scope.scalevalue.value =
            '1:' + getScaleForResolution(map.getView().getResolution(), 'm');
        };

        // passe a vrai quand on selectionne une valeur depuis la liste,
        // sans quoi pas mal de bugs si on change de valeur rapidement
        var setFromSelect = false;
        /**
         *    Ne retenir que la dernère demande d'apply quand
         *  une série d'apply est demandée les unes à la suite des autres.
         */
        var waitForApply = function() {
          var dDate = new Date();
          if (scope.prevApplyRequestDate == 0) return;
          if (scope.newApplies.length == 0 || setFromSelect) {
            //-- On a purgé toutes les demandes d'apply, donc on exécute l'apply.
            scope.prevApplyRequestDate = 0;
            if (setFromSelect) {
              setFromSelect = false;
            }
            else if (scope.setInput == 'true') {
              scope.scalevalue.selected = scope.scalevalue.value.slice(2);
              scope.noDigestPlease = true;
            }
            else {
              scope.scalevalue.selected = undefined;
            }

            if (firstTime) {
              $timeout(function() {
                scope.$apply();
              }, 0);
              firstTime = false;
            }
            else {
              $timeout(function () {
                scope.$apply();
              }, 0);
            }
          }
          else {
            //-- Des apply ont été mis dans la liste,
            //-- on supprime ceux qui sont anciens de plus de 450ms
            //-- et on attend une demi seconde
            //-- pour voir si d'autres sont demandés et/ou
            //-- pour enlever celles qui seront alors suffisament anciennes.
            scope.prevApplyRequestDate = dDate.getTime();
            var ind = scope.newApplies.length - 1;
            while (ind >= 0) {
              if (scope.prevApplyRequestDate - scope.newApplies[ind] > 450)
                scope.newApplies.splice(ind, 1);
              else ind--;
            }
            $timeout(waitForApply, 500);
          }
        };

        /**
         *     Actions initiales pour mettre en fonctionnement
         *  l'outil de gestion des échelles.
         */
        var initScaleTool = function() {
          var appname;
          //-- Conteneur pour gestion des variable de l'outil
          //-- de visualisation et de choix d'une échelle de dessin de la carte.
          scope.scalevalue = {};
          scope.scalevalue.scalevaluelist = [];
          //-- Récupération du nom de l'application
          if ($location.search().app) {
            appname = $location.search().app;
          }
          else {
            appname = angular.module('gcMain').app;
          }
          //-- Récupération de la configuration de l'application.'
          ApplicationFactory.getbyname(appname).then(function(res) {
            var ind,
              scale,
              app = res.data;
            //-- Indicateur d'affichage de l'échelle.
            scope.showScaleTool = app.displayScaleTool == 'yes';

            // Décale sur la droite l'échelle graphique si l'échelle numérique (gcScaleValue) n'est pas affichée
            // Uniquement disponible pour l'application MAP
            adjustScaleLinePosition();

            //-- Liste des valeurs d'échelle de la liste déroulante.
            // sauf si force depuis une liste de valeurs passées à la directive (ANC)
            if (!angular.isDefined(forcedScaleValueList)) {
              for (
                ind = 0;
                app.mapScales4Selection && ind < app.mapScales4Selection.length;
                ind++
              ) {
                scale = {
                  value: app.mapScales4Selection[ind],
                  label: '' + app.mapScales4Selection[ind],
                };
                scope.scalevalue.scalevaluelist.push(scale);
              }
            }
            else {
              console.log(typeof forcedScaleValueList);

              scope.scalevalue.scalevaluelist = JSON.parse(
                forcedScaleValueList
              );
            }
          });

          //-- Liste des demandes d'apply pour afficher la nouvelle valeur d'échelle
          //-- suite à la succession d'événements générés par le zoom carte
          //-- (zoom molette par exemple).
          scope.newApplies = [];

          // Event used if we want to change the map scale
          scope.$on('change_scale', function(event, scale) {
            scope.scalevalue.selected = scale;
          });

          //-- Rafraichir la carte quand une échelle est choisie dans la liste déroulante.
          scope.$watch('scalevalue.selected', function() {
            if (!scope.noDigestPlease) {
              setFromSelect = true;
              setScaleForResolution(scope.scalevalue.selected);
            }
            else {
              scope.noDigestPlease = false;
            }
          });

          //-- Rafraichir la valeur d'échelle affichée
          //-- quand un zoom écran est fait sur la carte.
          scope.$on('mapViewChanged', function() {
            mapView.un('propertychange', propertychange);
            map = scope.map;
            map.getView().on('propertychange', propertychange);
          });
          //-- Rafraichir la valeur d'échelle affichée
          //-- quand un zoom écran est fait sur la carte.

          var mapView = map.getView();
          map.getView().on('propertychange', propertychange);
          function propertychange(e) {
            switch (e.key) {
            case 'resolution':
              scope.scalevalue.value =
                  '1:' +
                  getScaleForResolution(map.getView().getResolution(), 'm');
              dDate = new Date();
              scope.prevApplyRequestDate = dDate.getTime();
              scope.newApplies.push(dDate.getTime());
              waitForApply();
              break;
            }
          }
        };

        initScaleTool();

        /**
         * Décale sur la droite l'échelle graphique si l'échelle numérique n'est pas affichée.<br>
         * Uniquement disponible pour l'application MAP
         */
        const adjustScaleLinePosition = () => {
          if (!scope.showScaleTool && $rootScope.xgos.sector === 'map') {
            const scaleLine = document.getElementById('ol-scale-line-container');
            if (scaleLine) {
              // scaleToolHidden est le nom de la classe qui modifie la propriété CSS right de la classe "ol-scale-line"
              // place l'échelle graphique en bord-droit de la carte à la place de l'échelle numérique
              scaleLine.classList.add('scaleToolHidden');
            }
          }
        };
      },
    };
  };

  gcscalevalue.$inject = [
    '$timeout',
    'ApplicationFactory',
    '$location',
    '$rootScope', 'gaJsUtils'
  ];
  return gcscalevalue;
});
