/**
 *
 */
'use strict';
define(function () {
  var printV2Ctrl = function ($scope, $http, $window, $translate, $timeout,
    gaDomUtils, gclayers, gaBrowserSniffer, GraticulesFactory, BaseMapFactory,
    PrintModelFactory, gcRestrictionProvider, $q, $rootScope, $filter,
    SridFactory, PrintLegendFactory, ParametersFactory, pv2LayerServices,
    pv2Config, pv2Annotations, $location, PortalsFactory, layersService, MeasureFactory) {
    var KEY = 'key';
    var VALUE = 'value';

    // gaWaitCursor.remove();
    var pdfLegendsToDownload = [];
    var printRectangle;
    var deregister;
    var DEVICE_PIXEL_RATIO = window.devicePixelRatio;
    var POINTS_PER_INCH = 72; //PostScript points 1/72"
    var MM_PER_INCHES = 25.4;
    var UNITS_RATIO = 39.37; // inches per meter
    var printConfigLoaded = false;
    var baseMapConfig = {};
    var osmUrl = '';
    var variablesToExport;

    const layersToSplice = [];

    $scope.options = {};
    $scope.options.active = false;
    //-- When not as visible on map, what's draw is what is visible
    //-- depending on layer configuration for choosen scale.
    $scope.options.asVisibleOnMap = 'asVisibleOnMap';

    $scope.cfgParamsReady = true;

    // destroy the component, we call this from mapLeftMenu.js,
    // without the timeout it throws an error.
    $scope.$on('destroy_gaprintv2', function () {
      $timeout(() => $scope.$destroy(), 0);
    });

    // Open/Close event panel
    $scope.$on('closeTools_gaprintv2', function (event, arg) {
      if (arg.directive === 'gaprintv2') {
        if (arg.active) {
          $scope.options.active = true;
        } else {
          $scope.options.active = false;
          deactivate();
        }
      }
    });

    $scope.$on('openTools_gaprintv2', function (event, arg) {
      if (arg.directive === 'gaprintv2') {
        if ($scope.hasCalledConfig && !$scope.configLoaded) {
          $scope.isWidgetOpen = true;
        } else {
          $scope.options.active = true;
        }
      }
    });

    $scope.$on('openTools_gaprintdirv2', function (event, arg) {
      if (angular.isDefined($scope.launchmode)) {
        if (arg.directive === 'gaprintdirv2') {
          if ($scope.hasCalledConfig && !$scope.configLoaded) {
            $scope.isWidgetOpen = true;
          } else {
            $scope.options.active = true;
          }
        }
      }
    });

    $scope.$on('openCloseTools_gaprintv2', function (event, arg) {
      if (arg.directive === 'gaprintv2') {
        if (arg.active) {
          $scope.options.active = true;
        } else {
          $scope.options.active = false;
          deactivate();
        }
      }
    });

    // Get print config
    var getBaseMapConfig = function () {
      var basemaps = BaseMapFactory.resources.basemaps;
      for (var i = 0; i < basemaps.length; i++) {
        if (basemaps[i].active) {
          baseMapConfig = basemaps[i];
          osmUrl = baseMapConfig.url;
          break;
        }
      }
    };

    // Get print config
    var updatePrintConfig = function () {
      $scope.hasCalledConfig = true;
      var http = $http.get(
        '/printv2/pdf/info.json?f=json&app=' +
        PortalsFactory.getPortalId() +
        '.json'
      );
      http.then(function (res) {
        const data = res.data;

        $scope.printConfig = {};
        SridFactory.getbycode(
          $scope.map
            .getView()
            .getProjection()
            .getCode()
        ).then(function (res) {
          $scope.secondProjection = res.data;
          $scope.olProjection =
            '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs';
        });

        $scope.capabilities = data;
        $scope.outputformat = data.outputFormats[0];

        // default values:
        if (data.layouts != undefined) {
          $scope.layout = data.layouts[0];
          $scope.dpi = data.dpis[0];
          $scope.scales = data.scales;
          if ($scope.inscale)
            angular.forEach($scope.scales, function (scale) {
              if ($scope.inscale == scale.value) $scope.scale = scale;
            });
          else $scope.scale = data.scales[0];
          $scope.options.legend = true;
          $scope.options.active = false;
          $scope.options.graticuleList = [];

          $translate('print.Aucun').then(function (res) {
            $scope.options.graticuleList.push({ name: res });
            $scope.options.selectedGraticule = $scope.options.graticuleList[0];
            loadGraticuleList();
          });
        }
      }).finally(() => {
        if ($scope.isWidgetOpen && !$scope.options.active) {
          $scope.options.active = true;
        }
        $scope.configLoaded = true;
      });
    };


    var preparePageVariables = function (arrayObj) {
      var objArrayResult = [];

      for (var i = 0; i < arrayObj.length; i++) {
        var key = arrayObj[i][KEY];
        var value = arrayObj[i][VALUE];

        var currentObj = {};
        currentObj[key] = value;

        objArrayResult.push(currentObj);
      }

      return objArrayResult;
    };

    var getVariables = function () {
      $scope.managevars = {};
      $scope.managevars.variables = [];
      PrintModelFactory.getAllVariables(PortalsFactory.getPortalId()).then(
        function (data) {
          if (data && data.data) {
            $scope.allVariables = data.data;
            updateVariableList();
          } else {
            console.log('No variables');
          }
        },
        function (data) {
          require('toastr').info(data);
        }
      );
    };
    var updateVariableList = function () {
      var ind;

      if ($scope.allVariables != undefined)
        for (ind = 0; ind < $scope.allVariables.length; ind++)
          if (
            $scope.allVariables[ind] != undefined &&
            $scope.layout != undefined &&
            $scope.allVariables[ind].name == $scope.layout.name
          ) {
            $scope.managevars.variables = $scope.allVariables[ind].variables;
            break;
          }
    };

    var loadGraticuleList = function () {
      GraticulesFactory.list().then(function (res) {
        var ind,
          graticulesTemp = [];
        for (ind = 0; ind < res.data.length; ind++)
          graticulesTemp.push(res.data[ind]);
        graticulesTemp.sort(function (a, b) {
          if (a.name > b.name) return 1;
          if (a.name < b.name) return -1;
          return 0;
        });
        for (ind = 0; ind < res.data.length; ind++)
          $scope.options.graticuleList.push(graticulesTemp[ind]);
      });
    };

    var activate = function () {
      deregister = [
        $scope.map.on('precompose', handlePreCompose),
        $scope.map.on('postcompose', handlePostCompose),
        $scope.map.getView().on('change:resolution', function () {
          updatePrintRectanglePixels($scope.scale);
        }),
      ];
      if ($scope.inscale) {
        angular.forEach($scope.scales, function (scale) {
          if ($scope.inscale == scale.value) $scope.scale = scale;
        });
      }
      if ($scope.scale == undefined) $scope.scale = getOptimalScale();

      refreshComp();
    };

    var deactivate = function () {
      if (deregister) {
        for (var i = 0; i < deregister.length; i++) {
          try {
            ol.Observable.unByKey(deregister[i]);
            //deregister[i].src.unByKey(deregister[i]);
            // deregister[i].target.unByKey(deregister[i]);
          } catch (e) {
            console.info(e);
          }
        }
      }
      refreshComp();
    };

    var refreshComp = function () {
      updatePrintRectanglePixels($scope.scale);
      $scope.map.render();
    };

    // Compose events
    var handlePreCompose = function (evt) {
      var ctx = evt.context;
      ctx.save();
    };

    var handlePostCompose = function (evt) {
      var ctx = evt.context;
      var size = $scope.map.getSize();
      var height = size[1] * DEVICE_PIXEL_RATIO;
      var width = size[0] * DEVICE_PIXEL_RATIO;

      var minx, miny, maxx, maxy;
      ///-- Modèle sans carte !!!
      if (printRectangle == undefined) return;
      (minx = printRectangle[0]),
      (miny = printRectangle[1]),
      (maxx = printRectangle[2]),
      (maxy = printRectangle[3]);

      ctx.save();

      ctx.beginPath();
      // Outside polygon, must be clockwise
      ctx.moveTo(0, 0);
      ctx.lineTo(width, 0);
      ctx.lineTo(width, height);
      ctx.lineTo(0, height);
      ctx.lineTo(0, 0);
      ctx.closePath();

      // Inner polygon,must be counter-clockwise
      ctx.moveTo(minx, miny);
      ctx.lineTo(minx, maxy);
      ctx.lineTo(maxx, maxy);
      ctx.lineTo(maxx, miny);
      ctx.lineTo(minx, miny);
      ctx.closePath();

      ctx.fillStyle = 'rgba(0, 5, 25, 0.25)';
      ctx.fill();

      ctx.restore();
    };

    updatePrintConfig();
    getVariables();

    // Listeners
    $scope.$on('gaTopicChange', function () {
      if (!printConfigLoaded) {
        updatePrintConfig();
        printConfigLoaded = true;
      }
    });
    $scope.$on('gaLayersChange', function () {
      updatePrintRectanglePixels($scope.scale);
    });
    $scope.map.on('change:size', function () {
      updatePrintRectanglePixels($scope.scale);
    });
    $scope.$watch('scale', function () {
      updatePrintRectanglePixels($scope.scale);
    });
    $scope.$watch('layout', function () {
      updatePrintRectanglePixels($scope.scale);
      updateVariableList();
      $scope.getPrintConfig(false);
    });
    $scope.$watch('options.asVisibleOnMap', function () {
      $scope.getPrintConfig(false);
    });


    $scope.downloadUrl = (url) =>{
      if ($scope.ongeturl) {
        if ($scope.options.active) deactivate();

        $scope.ext = printRectangle;
        $scope.res = $location.protocol() + '://' + $location.host() + ':' + $location.port() + url;
        $scope.ongeturl();
      } else {
        if (gaBrowserSniffer.msie == 9) {
          $window.open(url);
        } else {
          $window.location = url;
        }
      }
    };

    $scope.oncleanview = function () {
      console.log('clean me');
    };


    const layerScaleOk = (layer, scaleVal) => {
      const fti = layer.getProperties().fti;
      let ok = true;

      if (fti && fti.ogcProperties) {
        //-- Les ogcProperties ssont défines sur les couches ArcGIS.
        //-- En particulier les échelles minimum et maximum de dessin
        //-- sont définies dans le descriptif de la couche publiée.
        const props = fti.ogcProperties;
        if (props.maxScale != undefined) {
          //-- Si maxScale est défini ou nul (Echelle; max ArcGIS = min KIS)
          ok = scaleVal >= props.maxScale;
        }
        if (ok && props.minScale != undefined) {
          //-- Si minScale est défini ou nul (Ecxhelle: min ArcGIS = max KIS)
          ok = scaleVal < props.minScale || props.minScale == 0;
        }
      }

      return ok &&
        (layer.minScale == undefined || scaleVal >= layer.minScale) &&
        (layer.maxScale == undefined || scaleVal < layer.maxScale);
    };


    const addAllToEncLayer = (encLayersOut, encLayersIn) => {
      for (let ind = 0; ind < encLayersIn.length; ind++) {
        encLayersOut.push(encLayersIn[ind]);
      }
    };


    const getArcGisLayer = (arcgisLayers, encLayers) => {
      if (arcgisLayers.length !== 0) {
        const el
          = pv2LayerServices.getEncodedLayer($scope, 'ArcGIS', arcgisLayers);
        encLayers.push(el);
      }
    };


    /**
     * On a fini de parcourir les couches d'un groupe de couches arcgis
     * quand on passe à une couche non arcgis ou que le datastore
     * de la couche n'est pas le même que celui de la précédente.
     *
     * @param {*} prevLayer
     * @param {*} layer
     * @returns
     */
    const arcgisLayerGroupEnded = (prevLayer, layer) => {
      return prevLayer && prevLayer.gctype === 'esri'
        && (layer.gctype !== 'esri'
          || layer.getProperties().fti.storeName
          != prevLayer.getProperties().fti.storeName);
    };


    /**
     * On a fini de parcourir les couches d'un groupe de couches geoserver
     * quand on passe à une couche non arcgis ou que le datastore
     * de la couche n'est pas le même que celui de la précédente.
     *
     * @param {*} prevLayer
     * @param {*} layer
     * @returns
     */
    const gsLayerGroupEnded = (prevLayer, layer) => {
      return prevLayer && prevLayer.gctype === 'g2c'
        && (layer.gctype !== 'g2c'
          || layer.getProperties().fti.storeName
          != prevLayer.getProperties().fti.storeName);
    };


    /**
     * Recherche des couches visible selon la configuration la carte
     * (une couche visible à l'écran pourra ne pas l'être à l'impression
     * étant donnée que le niveau d'échelle ne sera pas forcément le même, ou
     * que l'on a pu agir sur la visibilité de la couche dans le géovatalogue)
     * afin de les ajouter dans la liste des couches à imprimer transmise
     * à MapFishPrint.
     *
     * @param {*} layers: Liste des tous les layers de l'application
     * @param {*} proj: Système de projection de la carte de l'applicaition
     * @param {*} encLayers: Résultat contenant le descriptif
     *                       des layers à imprimer
     * @param {*} outParams: Résultat contenant des paramétres d'impression
     * @param {*} extentp: Etendu à imprimer
     */
    const setLayersToPrintAsConfigured = (layers, proj, encLayers,
      outParams, extentp) => {
      const featuresList = getfeaturesListInExtentForConfig(layers, extentp);
      const addedLayer = [], layers0 = [];
      const scaleVal = Number($scope.scale.value);
      const arcgisLayers = [];
      let prevLayer;

      const layerArray = layersService.sortLayersOnPriority(layers.getArray(), null, true);
      //-- "gsPrioIndex" est le numéro de priorité de dessin de la couche
      //-- à utiliser dans l'ordre pour insérer les couches GeoServer
      //-- entre, avant ou aprés les groupes de couche ArcGIS.
      let gsPrioIndex = 0;
      for (let ind = 0; ind < layerArray.length; ind++) {
        const layer = layerArray[ind];
        if (arcgisLayerGroupEnded(prevLayer, layer)
          && arcgisLayers.length !== 0) {
          //-- On change de groupe de couches.
          getArcGisLayer(arcgisLayers, encLayers);
          arcgisLayers.splice(0, arcgisLayers.length);
          gsPrioIndex++;
        }
        if (layer.getProperties().gctype === 'esri'
          && layerScaleOk(layer, scaleVal)) {
          //-- Prise en compte de la couche
          arcgisLayers.push(layer);
          prevLayer = layer;
          layers0.push(layer);
        }
        else if (layer.name == 'Edition' ||
          (layerScaleOk(layer, scaleVal) &&
            (!layer.get('fti') || featuresList.length === 0 ||
              (layer.get('fti') &&
                featuresList.indexOf(layer.get('fti').name) !== -1 &&
                addedLayer.indexOf(layer.get('fti').name) === -1)))
        ) {
          addedLayer.push(layer.name);
          const attribution = layer.attribution;
          if (attribution !== undefined &&
            attribution.indexOf(attribution) == -1) {
            attribution.push(attribution);
          }
          if (layer instanceof ol.layer.Group) {
            const encs
              = pv2LayerServices.getEncodedLayer($scope, 'Group', layer, proj);
            addAllToEncLayer(encLayers, encs);
          }
          else {
            const enc
              = pv2LayerServices.encodeLayer(layer, proj, $scope, osmUrl, extentp);
            if (enc && enc.layer) {
              layer.prioIndex = gsPrioIndex++;
              layers0.push(layer);
            }
          }
          //-- Prise en compte de la couche
          prevLayer = layer;
        }
      }
      if (prevLayer && prevLayer.gctype === 'esri') {
        //-- On passe d'une liste de couche ArcGIS à des couches GeoServer.
        getArcGisLayer(arcgisLayers, encLayers);
      }
      return setMinLegend(layers0, outParams, encLayers, proj, extentp);
    };


    /**
     * Récupére la liste des couches rendues visibles par leur configuration
     * pour le niveau d'échelle actuel de la carte dessiné dans la page web.
     *
     * @param {*} layers : liste des couches de l applciation
     * @returns Liste des uids des couches visible pour le niveau
     *          d'echelle actuel de la carte de l'aplication
     */
    const getFeaturesInResolution = (layers) => {
      const resolution = $scope.map.getView().getResolution();
      const featuresNames = [];

      const layerArray = layers.getArray();
      for (const layer of layerArray) {
        if (layer.visible &&
          (layer.getMinResolution() == undefined ||
            resolution >= layer.getMinResolution()) &&
          (layer.getMaxResolution() == Infinity ||
            resolution < layer.getMaxResolution()) &&
          layer.get('fti')
        ) {
          featuresNames.push(layer.get('fti').uid);
        }
      }
      return featuresNames;
    };


    function getfeaturesListInExtentForConfig(layers, extent) {
      var leftX = extent[0];
      var bottomY = extent[1];
      var rightX = extent[2];
      var topY = extent[3];
      var filters = [];
      angular.forEach(layers, function (layer) {
        if (
          (layer.minScale == undefined ||
            Number($scope.scale.value) >= layer.minScale) &&
          (layer.maxScale == undefined ||
            Number($scope.scale.value) < layer.maxScale) &&
          layer.get('fti')
        ) {
          filters.push(layer.get('fti').uid);
        }
      });
      var featuresNames = [];
      if (filters.length > 0) {
        var filter = filters.join(',');
        var cql_filter =
          'INTERSECTS(geom, POLYGON((' +
          leftX +
          ' ' +
          bottomY +
          ',' +
          rightX +
          ' ' +
          bottomY +
          ',' +
          rightX +
          ' ' +
          topY +
          ',' +
          leftX +
          ' ' +
          topY +
          ',' +
          leftX +
          ' ' +
          bottomY +
          ')))';
        var catchments_url =
          '/services/' +
          angular.module('gcMain').portalid +
          '/ogc/getfeat?service=WFS&version=1.0.0&request=GetFeature&typeName=' +
          filter +
          '&outputformat=json&srsName=' +
          $scope.map
            .getView()
            .getProjection()
            .getCode() +
          '&cql_filter=' +
          cql_filter +
          '&token=' +
          localStorage.getItem('auth_token') +
          '&kis_app=' +
          $rootScope.xgos.sector;
        var xhr = new XMLHttpRequest();
        xhr.open('GET', catchments_url, false);
        xhr.onload = function (e) {
          if (xhr.readyState === 4) {
            if (xhr.status === 200) {
              featuresNames = $.unique(
                JSON.parse(e.srcElement.response).features.map(function (x) {
                  return x.id.split('.')[0];
                })
              );
            } else {
              console.error(xhr.statusText);
            }
          }
        };
        xhr.onerror = function () {
          console.error(xhr.statusText);
        };
        xhr.send(null);
      }
      return featuresNames;
    }

    /**
     *     Vérifie si les systèmes de projections
     *  d'impression et de OpenLayers sont les mêmes.
     *
     *  Return: VRAI si ce sont les mêmes
     *          FAUX si ce ne sont pas les mêmes.
     */
    $scope.projImpEqualsProjDisplay = function (pProj1) {
      var prop, proj1;

      //-- Si une projection est passée en paramétre
      //-- dans pProj1, on l'utilise pour la comparer
      //-- à la projection d'impression.
      if (pProj1 == undefined) proj1 = $scope.olProjection;
      else proj1 = pProj1;

      for (prop in proj1)
        if (proj1[prop] != $scope.secondProjection[prop]) return false;

      return true;
    };


    /**
     * Fabriquer la liste des items de légende qui correspondent
     * aux couches réellement présentes sur la carte à imprimer.
     * Donc, fabriquer une légende minimum.
     *
     * Le bouchon est même poussé un peu plus loin, puisque
     * si la repésentation est faite par valeur, on cherche
     * s'il y a des objets de la couches visibles par rapport à chaque valeur
     * pour ne mettre que les représentations par valeur pertinente.
     * Le même style de traitement est fait pour les couches ArcGIS,
     * même si la prise en compte du résulatt est davantage faite côté
     * MapFishPrint.
     *
     * @param {*} layers0: liste des couches à imprimer
     * @param {*} outParams: paramétres supplémentaire pour le service
     *                       d'impression
     * @param {*} encLayers: description des couches pour le service
     *                       d'impression
     * @param {*} proj: système de projection pour l'impression
     * @param {*} extentp: étendu à imprimer en coordonnées terrain
     * @returns
     */
    const setMinLegend = (layers0, outParams, encLayers, proj,
      extentp) => {
      var iLyr, fti, style;
      var defer = $q.defer();
      var bbox = $scope.curPrintBbox;
      var ftisAndStyles = {};
      ftisAndStyles.ftiAndStyle = [];
      for (iLyr = 0; iLyr < layers0.length; iLyr++) {
        fti = layers0[iLyr].get('fti');
        if (fti != undefined) {
          style = layers0[iLyr].getSource().getParams().STYLES;
          if (!style) style = fti.defaultStyle;
          ftisAndStyles.ftiAndStyle.push({
            ftiUid: fti.uid,
            style: style,
          });
        }
      }
      layers0.sort((a, b) => {
        return a.prioIndex === undefined || b.prioIndex === undefined
          ? 1 : a.prioIndex - b.prioIndex;
      });
      PrintLegendFactory.getLegendForLayers(bbox.xmin, bbox.xmax, bbox.ymin,
        bbox.ymax, $scope.map.getView().getProjection().getCode(),
        parseInt('' + $scope.scale.value), ftisAndStyles).then((res) => {
        var iLyr, iRes, layer, wLyr;
        let enc;
        //-- A-t-on un système de projecition différent
        //-- pour l'impression de celui de l'affichage dans OpenLayers.
        var projImpIsProjDisplay = $scope.projImpEqualsProjDisplay();
        if ($scope.printLegendLayersWithoutObjects == undefined)
          $scope.printLegendLayersWithoutObjects = [];
        else $scope.printLegendLayersWithoutObjects.splice(0);
        for (iLyr = 0; iLyr < layers0.length; iLyr++) {
          layer = layers0[iLyr];
          if (layer.get('fti') == undefined) {
            enc = pv2LayerServices.encodeLayer(layers0[iLyr], proj, $scope,
              osmUrl, extentp);
            if (enc && enc.layer) {
              if (!projImpIsProjDisplay && enc.layer.type == 'Vector') {
                //-- Le système de projection est différent
                //-- entre l'impression et l'affichage OpenLayers,
                //-- donc il faut transformer
                //-- les coordonnées des annotations.
                wLyr = angular.copy(enc.layer);
                enc.layer = wLyr;
              }
              enc.layer.overview = false;
              if (layer.prioIndex!==undefined) {
                encLayers.splice(layer.prioIndex, 0, enc.layer);
              }
              else {
                encLayers.push(enc.layer);
              }
            }
          }
          else {
            for (iRes = 0; iRes < res.data.length; iRes++) {
              if (layer.get('fti').uid == res.data[iRes].fti) {
                enc = pv2LayerServices.encodeLayer(layer, proj, $scope,
                  osmUrl, extentp);
                // @EDG 13/01/2022 peut-etre à remettre
                //if (enc && enc.layer) {
                if (layer.get('fti').type === 'esri') {
                  let ind;
                  for (ind = 0; ind < res.data[iRes].classes.length; ind++) {
                    res.data[iRes].classes[ind].typeInfo = 'arcgis';
                    res.data[iRes].classes[ind].arcgisLegend
                        = $location.protocol() + '://' + $location.host()
                        + ':' + $location.port()
                        + layer.getProperties().legend.replace('..', '');
                  }
                }
                else {
                  if (layer.prioIndex!==undefined) {
                    encLayers.splice(layer.prioIndex, 0, enc.layer);
                  }
                  else {
                    encLayers.push(enc.layer);
                  }
                }
                if (enc && enc.layer) {
                  outParams.encLegends = outParams.encLegends || [];
                  if (layer.theme !== 'WebBackGround' && enc.legend &&
                      (!layer.get('fti') || (layer.get('fti')))
                  ) {
                    enc.legend.classes = res.data[iRes].classes;
                    enc.legend.theme = layer.theme;
                    outParams.encLegends.push(enc.legend);
                  }
                }
                break;
              }
              if (iRes == res.data.length) {
                //-- La zone à imprimer ne contient pas d'objet de cette couche.
                if (layer.get('fti') != undefined)
                  $scope.printLegendLayersWithoutObjects.push(
                    layer.get('fti').alias
                  );
              }
            }
          }
        }
        defer.resolve();
      });
      return defer.promise;
    };


    /**
     * Vérifie que la couche est à prendre en compte pour l'impresssion
     * parcequ'elle est dessinée au niveau d'échelle demandée et
     * qu'elle n'a pas encore été prise en compte.
     *
     * @param {*} featuresList : Liste des couches visibles
     * @param {*} addedLayer : liste des couches déjà prises en comptes
     *                         pour l'impression
     * @param {*} layer : couche à tester
     * @returns : TRUE -> inclure la couche dans l'impression, FALSE sinon.
     */
    const layerInResolutionAndNotAdded = (featuresList, addedLayer, layer) => {
      if (layer.get('fti')) {
        //-- Le FTI du layer est OK
        if (featuresList.length === 0) {
          //-- Aucune couche n'est visible tout court
          //-- ou n'est visible pour le niveau de zoom.
          return false;
        }
        //-- La couche est elle dans la liste des couches visibles
        //-- sans être dans celle déjà prises en compte ?
        return  featuresList.indexOf(layer.get('fti').uid) !== -1 &&
            addedLayer.indexOf(layer.get('fti').uid) === -1;
      }
      return false;
    };


    /**
     * Préparation de la liste des couches à imprimer, ici,
     * nous sommes dans le cas où l'utilisateur demande à imprimer
     * la même chose que ce que l'on voit à l'écran sans tenir compte
     * de la configuration par défaut.
     *
     * @param {*} layers: liste des couches à imprimer
     * @param {*} proj: système de projection pour l'impression
     * @param {*} encLayers: description des couches pour le service
     *                       d'impression
     * @param {*} outParams: paramétres supplémentaire pour le service
     *                       d'impression
     * @param {*} extentp: étendu à imprimer en coordonnées terrain
     * @returns
     */
    const setLayersToPrintAsVisibleOnMap = (layers, proj, encLayers, outParams,
      extentp) => {

      const kisLayers = ['Edition', 'Mesure', 'measure-tooltip', 'measure-tooltip-pointer'];

      const featuresList = getFeaturesInResolution(layers, extentp);
      const addedLayer = [], layers0 = [];
      const arcgisLayers = [];
      let prevLayer;

      const layerArray = layersService.sortLayersOnPriority(layers.getArray(), null, true);
      //-- "gsPrioIndex" est le numéro de priorité de dessin de la couche
      //-- à utiliser dans l'ordre pour insérer les couches GeoServer
      //-- entre, avant ou aprés les groupes de couche ArcGIS.
      let gsPrioIndex = 0;
      for (let ind = 0; ind < layerArray.length; ind++) {
        const layer = layerArray[ind];
        if (arcgisLayerGroupEnded(prevLayer,layer) && arcgisLayers.length!==0) {
          //-- On change de groupe de couches.
          getArcGisLayer(arcgisLayers, encLayers);
          arcgisLayers.splice(0, arcgisLayers.length);
          gsPrioIndex++;
        }
        const pp = layer.getProperties();
        if (pp.gctype === 'esri'
          && layerInResolutionAndNotAdded(featuresList,addedLayer,layer)) {
          //-- Prise en compte de la couche
          arcgisLayers.push(layer);
          prevLayer = layer;
          layers0.push(layer);
          console.log(' type ' + layer.name + ' : ' + layer.type);
        }
        else if ( kisLayers.includes(layer.name) || pp.theme === 'WebBackGround' ||
          layerInResolutionAndNotAdded(featuresList,addedLayer,layer)) {
          let alreadyAdded = false;
          if (pp && pp.theme == 'WebBackGround') {
            alreadyAdded = addedLayer.indexOf(layer.name) != -1;
          }
          if (!alreadyAdded) {

            // les couches KIS ont une propriété name définie sans utiliser les méthodes OL
            const layername = pp.name ? pp.name : layer.name;

            // les couches de mesure n'ont pas de fti
            if (!layersService.isBackgroundLayer(pp) && !kisLayers.includes(layername)) {
              addedLayer.push(layer.getProperties().fti.uid);
            }
            console.log(' type ' + layer.name + ' : ' + layer.type);
            if (layer instanceof ol.layer.Group) {
              var encs = pv2LayerServices.getEncodedLayer($scope, 'Group',
                layer, proj );
              encLayers = encLayers.concat(encs);
            }
            else {
              var enc = pv2LayerServices.encodeLayer(layer, proj, $scope,
                osmUrl, extentp);
              if (enc && enc.layer) {
                layer.prioIndex = gsPrioIndex++;
                layers0.push(layer);
              }
            }
          }
          prevLayer = layer;
        }
      }
      if (prevLayer && prevLayer.gctype === 'esri') {
        //-- On passe d'une liste de couche ArcGIS à des couches GeoServer.
        getArcGisLayer(arcgisLayers, encLayers);
      }

      return setMinLegend(layers0, outParams, encLayers, proj, extentp);
    };


    const getExtentFromPrintExtent = () => {
      const printExtent = calculatePageBoundsPixels($scope.scale);
      return $scope.map
        .getCoordinateFromPixel([printExtent[0], printExtent[1]])
        .concat(
          $scope.map.getCoordinateFromPixel([printExtent[2], printExtent[3]])
        );
    };


    const setLayersToPrint = (layers, proj, encLayers, outParams, extentp) => {
      //-- Modèle sans carte !!!
      var defer = $q.defer();

      if (printRectangle == undefined) {
        defer.reject();
        return defer.promise;
      }
      if (gcRestrictionProvider.hasRestrictionQuery()) {
        extentp = getExtentFromPrintExtent();
        var geometry = gcRestrictionProvider.createGeometryFromExtent(extentp);
        var promise = gcRestrictionProvider.GeometryInRestriction(
          geometry,
          $scope.map
            .getView()
            .getProjection()
            .getCode()
        );
        promise.then(function(res) {
          if (JSON.parse(res.data)) {
            if ($scope.options.asVisibleOnMap == 'asVisibleOnMap')
              setLayersToPrintAsVisibleOnMap(layers, proj, encLayers,
                outParams, extentp) .then(() => {
                defer.resolve('terminé');
                gaDomUtils.hideGlobalLoader();
              });
            else {
              setLayersToPrintAsConfigured(layers, proj, encLayers,
                outParams, extentp).then(() => {
                defer.resolve('terminé');
                gaDomUtils.hideGlobalLoader();
              });
            }
          } else {
            gcRestrictionProvider.showErrorMessage();
            defer.reject();
          }
        });
      } else {
        if ($scope.options.asVisibleOnMap == 'asVisibleOnMap')
          setLayersToPrintAsVisibleOnMap(layers, proj, encLayers,
            outParams, extentp).then(() => {
            defer.resolve('terminé');
            gaDomUtils.hideGlobalLoader();
          });
        else {
          setLayersToPrintAsConfigured(layers, proj, encLayers,
            outParams, extentp).then(() => {
            defer.resolve('terminé');
            gaDomUtils.hideGlobalLoader();
          });
        }
      }
      return defer.promise;
    };

    /**
     *     Création de la géométrie de la bulle de l'annotation avec bulle.
     */

    $scope.cleanCurrentConfigForPrinting = function() {
      var iRes, iLegLyr, res;

      for (iRes = 0; iRes < $scope.currentConfig.length; iRes++) {
        res = $scope.currentConfig[iRes];
        for (
          iLegLyr = res.askedLegendLayers.length - 1;
          iLegLyr >= 0;
          --iLegLyr
        ) {
          if (!res.selected[res.askedLegendLayers[iLegLyr]])
            res.askedLegendLayers.splice(iLegLyr, 1);
        }
      }
    };


    /**
     * Auteur: EDG
     * Date: 02/08/2018
     *
     *     Obtention de la configuration d'impression soit appliquée
     *  soit par défaut par rapport au modèle et aux couches à dessiner
     *  (comme configuré ou visible à l'écran).
     *  Une fois obtenue, le nom du paramétrage est stocké pour la bulle
     *  d'aide de la commande d'ouverture de la fenêtre de paramétrage.
     *     Si le paramétre "doPrint" est VRAI on lance l'impression avec
     *  l'éventuel paramétrage appliqué ou par défaut lié au modèle
     *  et au type de visibilite.
     *
     *  Note:
     *    Le paramétrage des impressions ne concerne à ce jour
     *  que la configuration de la présentation de la légende.
     */
    $scope.getPrintConfig = ( doPrint, layers, pdfLegendsToDownload,
      spec, bool ) => {
      //-- Construction du nom du type de paramétre
      //-- des paramétres en base des paramétrage d'impression.
      if ($scope.layout == undefined) return;
      $scope.ConfigNameTemplate =
        'modele_print_' +
        $scope.layout.name +
        '_' +
        $scope.options.asVisibleOnMap;
      $scope.DEFAULT_DB_PARAM_CONFIGURATION_NAME =
        $scope.ConfigNameTemplate + '_LAST_EDITED' + $rootScope.xgos.user.uid;
      $scope.defaulLegPrintCfg = undefined;
      ParametersFactory.getbytype(
        $scope.DEFAULT_DB_PARAM_CONFIGURATION_NAME
      ).then(function(res) {
        if (res.data.length > 0) {
          $scope.defaulLegPrintCfg = res.data[0].data;
        }
        $scope.currentConfig = $scope.currentConfigId = undefined;
        if ($scope.appliedLegConfig) {
          //-- Un paramétrage est appliqué.
          $scope.currentConfig = angular.copy($scope.appliedLegConfig);
          if ($scope.appliedLegConfig.name == undefined)
            $scope.currentConfigName = $filter('translate')(
              'print.workingConfig'
            );
          else $scope.currentConfigName = $scope.appliedLegConfig.name;
          $scope.currentConfigId = $scope.appliedLegConfigId;
          $scope.cleanCurrentConfigForPrinting();
        }
        else if ($scope.defaulLegPrintCfg !== undefined) {
          //-- Un paramétrage est défini comme paramétrage par défaut.
          $scope.appliedLegConfig = angular.copy(
            $scope.defaulLegPrintCfg.result
          );
          $scope.currentConfig = $scope.defaulLegPrintCfg.result;
          $scope.currentConfigId = $scope.appliedLegConfigId =
            $scope.defaulLegPrintCfg.id;
          $scope.currentConfigName = $scope.appliedLegConfig.name =
            $scope.defaulLegPrintCfg.name;
          $scope.printLegCfg = $scope.defaulLegPrintCfg;
        }
        else {
          //-- Aucun paramétrage à utiliser.
          $scope.currentConfigName = $filter('translate')('print.none');
          if (
            $scope.printLegCfg == undefined ||
            $scope.printLegCfg.result == undefined
          ) {
            $scope.printLegCfg = {};
            pv2Config.setDefaultParamValuesFromlayout('parametrage', $scope);
          }
        }

        if (doPrint) {
          //-- Impression ou ouverture de la fenêtre de gestion
          //-- des paramétrres avec l'éventuel paramétrage défini.
          spec.pages[0].forceConfig = $scope.currentConfig;
          createInfo(layers, pdfLegendsToDownload, spec, bool);
        }
      });
    };


    $scope.layoutChanged = function() {
      $scope.resultConfig = undefined;
      $scope.lastAction = 'none';
      delete $scope.appliedLegConfig;
      delete $scope.printLegCfg;
      $scope.printLegCfg = {};
      pv2Config.setDefaultParamValuesFromlayout('parametrage', $scope);
    };


    const loadBackgroundLayers = (layers) => {
      const backl = $scope.map.getLayers();
      layersToSplice.push(layers.getLength());
      layersToSplice.push(backl.getLength());
      const backgroundTypes = ['OSM', 'GEOWEBCACHE', 'WMSBACK', 'WMTS'];
      backl.forEach(function(item) {
        if (backgroundTypes.includes(item.type)) {
          layers.insertAt(0, item);
        }
      });
    };


    const getGraticuleCoords = () => {
      return {
        baseURL:
            '/services/' +
            PortalsFactory.getPortalId() +
            '/geoserver/wms?token=' +
            localStorage.auth_token,
        opacity: 1,
        singleTile: true,
        type: 'WMS',
        layer2280s: [$scope.options.selectedGraticule.shpName + '_label'],
        format: 'image/png',
        styles: [''],
        customParams: {
          TRANSPARENT: true,
        },
      };
    };


    const getgraticuleLines = () => {
      return {
        baseURL:
            '/services/' +
            PortalsFactory.getPortalId() +
            '/geoserver/wms?token=' +
            localStorage.auth_token,
        opacity: 1,
        singleTile: true,
        type: 'WMS',
        layers: [$scope.options.selectedGraticule.shpName],
        format: 'image/png',
        styles: [''],
        customParams: {
          TRANSPARENT: true,
        },
      };
    };


    const setGraticuleLayers = (encLayers) => {
      if ($scope.options.selectedGraticule !=
        $scope.options.graticuleList[0]) {
        encLayers.push(getgraticuleLines());
        encLayers.push(getGraticuleCoords());
      }
    };


    const getMarker = (center) => {
      return {
        type: 'Vector',
        styles: {
          '1': {
            externalGraphic: $scope.options.markerUrl,
            graphicWidth: 20,
            graphicHeight: 30,
            // the icon is not perfectly centered in the image
            // these values must be the same in map.less
            graphicXOffset: -12,
            graphicYOffset: -30,
          },
        },
        styleProperty: '_gx_style',
        geoJson: {
          type: 'FeatureCollection',
          features: [
            {
              type: 'Feature',
              properties: {
                _gx_style: 1,
              },
              geometry: {
                type: 'Point',
                coordinates: [center[0], center[1], 0],
              },
            },
          ],
        },
        name: 'drawing',
        opacity: 1,
      };
    };


    const setMarkersLayers = (encLayers) => {

      // FIXME this is a temporary solution
      // i.e. use shit to make free shit and force the next ones to handle shit
      const overlays = $scope.map.getOverlays();

      overlays.forEach((overlay) => {
        const center = overlay.getPosition();
        const isMeasureOverlay = MeasureFactory.isMeasureOverlay(overlay.getElement());
        if (center && overlay.getProperties().origin !== 'annotations' && !isMeasureOverlay) {
          encLayers.push(getMarker(center));
        }
      });
    };


    /**
     * Build the manuel variables to page
     *
     * @param {*} pageIn
     * @returns page modifiée
     */
    const addVariablesToPage =  (pageIn) => {
      let page = {};
      variablesToExport = preparePageVariables(
        $scope.managevars.variables
      );

      angular.forEach(variablesToExport, function (variable) {
        page = angular.extend(pageIn, variable);
      });

      return page;
    };


    /**
     * Construction des pages à imprimer
     *
     * @param {*} view
     * @param {*} defaultPage
     * @returns Liste des pages à imprimer
     */
    const buildPages =  (view, defaultPage) => {
      const pages = [];
      var page = angular.extend(
        {
          center: getPrintRectangleCenterCoord(),
          // scale has to be one of the advertise by the print server
          scale: $scope.scale.value,
          rotation: -((view.getRotation() * 180.0) / Math.PI),
        },
        defaultPage
      );

      if ($scope.managevars.variables.length != 0) {
        page = addVariablesToPage(page);
      }

      pages.push(page);

      return pages;
    };


    /**
     * Construire les paramétres de spécification définissant le document
     * à faire imprimer par MapFishPrint.
     *
     * @param {*} that
     * @param {*} that_name
     * @param {*} that_dpi
     * @param {*} proj
     * @param {*} lang
     * @param {*} view
     * @param {*} encLayers
     * @param {*} outParams
     * @param {*} defaultPage
     * @returns Description de l'impression à obtenir
     */
    const getSpec = (that, that_name, that_dpi, proj, lang, view, encLayers,
      outParams, defaultPage) => {

      return {
        layout: that_name,
        srs: view.getProjection().getCode(),
        units: proj.getUnits() || 'm',
        rotation: -((view.getRotation() * 180.0) / Math.PI),
        app: PortalsFactory.getPortalId() + '.json',
        lang: lang,
        dpi: that_dpi,
        layers: encLayers,
        legends: outParams.encLegends || [],
        enableLegends:
              outParams.encLegends && outParams.encLegends.length > 0,
        pages: buildPages(view, defaultPage),
        outputFormat: that.outputformat.name //"pdf"
      };
    };


    $scope.submit = function(bool) {
      if (!$scope.options.active) {
        return;
      }
      if ($scope.rptCfg == undefined) $scope.rptCfg = {};
      if (!bool) $scope.rptCfg.reportCurrentConfigName = '';

      getBaseMapConfig();
      // http://mapfish.org/doc/print/protocol.html#print-pdf
      const view = $scope.map.getView();
      const proj = view.getProjection();
      const lang = 'fr'; //$translate.uses();
      const defaultPage = {};
      defaultPage['lang' + lang] = true;

      const encLayers = [];

      const layers = gclayers.getOperationalLayerCollection();
      loadBackgroundLayers(layers);

      //-- Ajout des annotations dans layers d'impression'
      $scope.extentp = getExtentFromPrintExtent();
      pv2Annotations.addAnnotationsAsLayer($scope.extentp, layers,
        $scope.scale.value);

      // Ajoute les cotations dans les layers d'impression
      MeasureFactory.addMeasureToolLayers($scope.map, layers, Number($scope.scale.value));

      pdfLegendsToDownload = [];

      var that = this;
      var that_name = that.layout.name;
      var that_dpi = that.dpi.value;

      var outParams = {};
      gaDomUtils.showGlobalLoader();
      //-- Timeout pour mettre au showGlobalLoader précédent
      //-- de s'afficher de suite.
      $timeout(() => {
        setLayersToPrint(layers, proj, encLayers, outParams,
          $scope.extentp).then(() => {
          setGraticuleLayers(encLayers);
          setMarkersLayers(encLayers);

          const spec = getSpec(that, that_name, that_dpi, proj, lang, view,
            encLayers, outParams, defaultPage);
          $scope.getPrintConfig(true, layers, pdfLegendsToDownload, spec, bool);
        },
        () => {
          gaDomUtils.hideGlobalLoader();
        }
        );
      }, 0);
      //-- END OF SUBMIT
    };


    $scope.filterFunc = function(elements, name) {
      var b = false;
      if (elements && name) {
        if (name.toLowerCase().score(elements.toLowerCase()) > 0.1) b = true;
      } else {
        b = true;
      }
      return b;
    };

    $scope.emptyConfig = function() {
      var callback = function(isconfirm) {
        if (isconfirm) {
          $scope.printLegCfg.result = angular.copy($scope.savedLastConfig);
          try {
            $scope.$apply();
          } catch (err) {}
        }
      };
      var message =
        $filter('translate')('print.dialog.emptymodif') +
        '. ' +
        $filter('translate')('print.dialog.sur');
      swal(
        {
          title: $filter('translate')('print.dialog.warning'),
          text: message,
          type: 'warning',
          confirmButtonColor: '#F50072',
          showCancelButton: true,
          cancelButtonText: $filter('translate')('common.no'),
          confirmButtonText: $filter('translate')('common.yes'),
          showConfirmButton: true,
        },
        callback
      );
    };

    $scope.closeRptCfg = function() {
      document.getElementById('closePrintParametersPopup').click();
    };

    $scope.getLegParamModifications = function(data) {
      if (data.result && data.result.length > 0) {
        data.result.map(function(x) {
          var obj = {
            status: x.status,
            name: x.name,
            shrinkFactor: x.shrinkFactor,
            layerFontSize: x.layerFontSize,
            classFontSize: x.classFontSize,
            themeFontSize: x.themeFontSize,
            askedColumnNumber: x.askedColumnNumber,
            forcedFontSize: x.forcedFontSize,
            forceFactor: x.forceFactor,
            forceThemeFontSize: x.forceThemeFontSize,
            forceLayerFontSize: x.forceLayerFontSize,
            forceClassFontSize: x.forceClassFontSize,
            forceColumnNumber: x.forceColumnNumber,
          };
          //if ( x.status === "overflow" ){
          var askedLayers = [];
          var ignoredLayers = [];
          for (var key in x.selected) {
            if (
              key &&
              x.selected.hasOwnProperty(key) &&
              x.selected[key] &&
              askedLayers.indexOf(key) === -1
            )
              askedLayers.push(key);
            else if (key) ignoredLayers.push(key);
          }
          obj.askedLegendLayers = askedLayers;
          obj.ignoredLegendLayers = ignoredLayers;
          //}
          data.spec.pages[0].forceConfig.push(obj);
        });
      }
    };

    $scope.checkNumberIsCorrect = function(params) {
      if (params == undefined) return;
      if (params.min != undefined) {
        $timeout(function() {
          if ($scope.printLegCfg.result[params.legInd][params.val] < params.min)
            $scope.printLegCfg.result[params.legInd][params.val] = params.min;
        }, 1500);
      }
    };

    /**
     *     Dans le cas où MFP a calculé un nombre de colonnes
     * différent de celui que  l'on a indiqué, il est bien
     * de repartir de ce nombre de colonne pour optimiser la légende.
     * On le fait si l'opérateur joue sur le facteur de réduction.
     */
    $scope.manageColumnNumber = function(params) {
      var res;
      if (params == undefined) return;
      if (params.src == 'shrinkFactor') {
        res = $scope.printLegCfg.result[params.legInd];
        res.columnNumberSet = res.realColumnNumber;
      }
    };

    $scope.reportDescChanged = function(cfg, params) {
      $scope.currentConfigId = $scope.printLegCfg.id = $scope.appliedLegConfigId = undefined;
      $scope.paramData = cfg;
      if ($scope.paramData != undefined) {
        $scope.paramData.id = undefined;
      }
      $scope.checkNumberIsCorrect(params);
      $scope.manageColumnNumber(params);
      $scope.$broadcast('dbParamInfoUnselectCurrent', {});
    };

    $scope.setForceIt = function(cfg, forceIt) {
      var ind;
      for (ind = 0; ind < cfg.length; ind++) {
        cfg[ind].layersWithoutObjects = $scope.printLegendLayersWithoutObjects;
        cfg[ind].forceIt = forceIt;
      }
    };

    var propertiesToCheck = [
      'shrinkFactor',
      'layerFontSize',
      'classFontSize',
      'themeFontSize',
      'askedColumnNumber',
    ];
    $scope.checkValues = function(result) {
      var response = false;
      if (result != undefined)
        for (var i = 0; i < result.length; i++) {
          var r = result[i];
          for (var j = 0; j < propertiesToCheck.length; j++) {
            if (r && angular.isUndefined(r[propertiesToCheck[j]])) {
              response = true;
              return response;
            }
          }
        }
      return response;
    };


    const createInfo02 = (spec, layers, pdfLegendsToDownload) => {
      gaDomUtils.showGlobalLoader();

      spec.mergeableParams = {
        cql_filter: {
          defaultValue: 'INCLUDE',
          separator: ';',
          c_ontext: 'http://labs.metacarta.com/wms/vmap0',
        },
      };
      if ($scope.dictfilename) {
        // -- Un nom de fichier impression est fourni (cas des DICTs)
        // -- on le passe donc à MapFishPrint (à partir de version 1.6)
        spec.outputFilename = $scope.dictfilename;
      }
      var http = $http.post(
        /*that.capabilities.createURL*/ '/printv2/pdf/create.json' +
        '?url=' + encodeURIComponent('/printv2/pdf/create.json'),
        spec
      );
      http.then((data) => {
        $scope.prevAction = $scope.lastAction;
        $scope.lastAction = 'print';
        //gaWaitCursor.remove();
        gaDomUtils.hideGlobalLoader();
        $scope.downloadUrl(data.data.getURL);
        if (checkLegendContent(data, spec, pdfLegendsToDownload, layers)) {
          $scope.resultConfig = angular.copy(data.resultConfig);
          var ok = true;
          if ($scope.options.legend)
            //-- Ne plus afficher la fenêtre de synthèse lorsque
            //-- la légende a pu être entièrement complétée même
            //-- si le système a du modifier certains paramètres.
            ok =
              $scope.resultConfig
                .map(function (x) {
                  return x.status;
                })
                .indexOf('overflow') === -1;
          if (!ok)
            pv2Config.getDialogConfig(
              data.resultConfig,
              layers,
              pdfLegendsToDownload,
              spec,
              'synthese',
              $scope
            );
          if (layers.item(0).theme == 'WebBackGround') {
            console.log('JE RETIRE LE PREMIER ');
            layers.removeAt(0);
          }
        } else {
          $scope.lastAction = $scope.prevAction;
          if (layers.item(0).theme == 'WebBackGround') {
            console.log('JE RETIRE LE PREMIER ');
            layers.removeAt(0);
          }

          //After standard print, download the pdf Legends
          //if there are any
          for (var i = 0; i < pdfLegendsToDownload.length; i++) {
            $window.open(pdfLegendsToDownload[i]);
          }

          //-- On s assure que les layers ajoutés pour traiter
          //-- le cas des annotations ne reste pas dans le circuit.
          //-- Effectivement, ils ne servent plus à rien.
          if (!layers.removeAt)
            layers.splice(layersToSplice[0], layersToSplice[1]);
          else pv2Annotations.removeAnnotationLayers(layers); //reset layers config
        }
      });
      http.catch(function () {
        //gaWaitCursor.remove();
        gaDomUtils.hideGlobalLoader();
        if (layers.item(0).theme == 'WebBackGround') {
          console.log('JE RETIRE LE PREMIER ');
          layers.removeAt(0);
        }
        require('toastr').error($filter('translate')('print.printError'));
      });
    };



    var createInfo = function(layers, pdfLegendsToDownload, spec, bool) {
      if (bool) {
        $scope.prevAction = $scope.lastAction;
        gaDomUtils.hideGlobalLoader();
        pv2Config
          .initResultConfig($scope.layout.name, spec.legends, $scope)
          .then(function() {
            pv2Config.getDialogConfig(
              $scope.resultConfig,
              layers,
              pdfLegendsToDownload,
              spec,
              'parametrage',
              $scope
            );
          });
      }
      else {
        if ($scope.appliedLegConfig == undefined)
          createInfo02(spec, layers, pdfLegendsToDownload);
        else
          pv2Config
            .checkConfigModified(
              $scope.appliedLegConfigId,
              $scope.appliedLegConfig.name,
              $scope.prevCfg,
              spec.pages[0].forceConfig,
              $scope.prevCfgId,
              $scope
            )
            .then(function() {
              createInfo02(spec, layers, pdfLegendsToDownload);
            });
      }
    };

    $scope.selectAllCorrection = function(b, report) {
      if (report.selected == undefined) report.selected = {};
      if (
        report &&
        report.askedLegendLayers &&
        report.askedLegendLayers.length > 0
      ) {
        report.askedLegendLayers.map(function(x) {
          if (x) {
            report.selected[x] = b;
          }
        });
      }
    };

    var checkLegendContent = function(data) {
      if (data.resultConfig && data.resultConfig.length > 0) {
        var ok =
          data.resultConfig
            .map(function(x) {
              return x.status;
            })
            .indexOf('overflow') === -1;
        if (ok) {
          //-- Ne plus afficher aucun message lorsque
          //-- la légende a pu être entièrement complétée même
          //-- si le système a du modifier certains paramètres.
          /*
                  swal({
                      title: $filter('translate')("print.dialog.report"),
                      text: $filter('translate')('print.printOk'),
                      type: "info",
                      icon: "success",
                      showConfirmButton: false,
                      showCancelButton: false,
                      confirmButtonColor: "#DD6B55",
                      confirmButtonText: $filter('translate')("common.yes"),
                      timer: 2000
                  });
                  */
          return true;
        } else {
          return true;
        }
      } else {
        return false;
      }
    };

    var getPrintRectangleCenterCoord = function() {
      // Framebuffer size!!
      var bottomLeft = printRectangle.slice(0, 2);
      var width = printRectangle[2] - printRectangle[0];
      var height = printRectangle[3] - printRectangle[1];
      var center = [bottomLeft[0] + width / 2, bottomLeft[1] + height / 2];
      // convert back to map display size
      var mapPixelCenter = [
        center[0] / DEVICE_PIXEL_RATIO,
        center[1] / DEVICE_PIXEL_RATIO,
      ];
      var mapCenter = $scope.map.getCoordinateFromPixel(mapPixelCenter);
      //return $scope.map.getCoordinateFromPixel(mapPixelCenter);
      return mapCenter;
    };

    var updatePrintRectanglePixels = function(scale) {
      if ($scope.options.active) {
        printRectangle = calculatePageBoundsPixels(scale);
        $scope.map.render();
      }
    };

    var getOptimalScale = function() {
      console.log('titi : ' + $scope.layout);
      if ($scope.layout == undefined) {
        alert('Pas de modèle utilisable !');
        return;
      }
      var size = $scope.map.getSize();
      var resolution = $scope.map.getView().getResolution();
      if ($scope.options.widthMargin == undefined)
        $scope.options.widthMargin = 0;
      if ($scope.options.heightMargin == undefined)
        $scope.options.heightMargin = 0;
      var width = resolution * (size[0] - $scope.options.widthMargin * 2);
      var height = resolution * (size[1] - $scope.options.heightMargin * 2);
      var layoutSize = $scope.layout.map;
      var scaleWidth =
        (width * UNITS_RATIO * POINTS_PER_INCH) / layoutSize.width;
      var scaleHeight =
        (height * UNITS_RATIO * POINTS_PER_INCH) / layoutSize.height;
      var testScale = scaleWidth;
      if (scaleHeight < testScale) {
        testScale = scaleHeight;
      }
      var nextBiggest = null;
      //The algo below assumes that scales are sorted from
      //biggest (1:500) to smallest (1:2500000)
      angular.forEach($scope.scales, function(scale) {
        if (nextBiggest == null || testScale > scale.value) {
          nextBiggest = scale;
        }
      });
      return nextBiggest;
    };

    function rotate(center, coord, angle) {
      let cos = Math.cos(angle);
      let sin = Math.sin(angle);
      let nx =
        cos * (coord[0] - center[0]) + sin * (coord[1] - center[1]) + center[0];
      let ny =
        cos * (coord[1] - center[1]) - sin * (coord[0] - center[0]) + center[1];
      return [nx, ny];
    }

    /**
     * calcul de la résolution en tenant compte de l'orientation.
     */
    function getMapWorldCoordinatesResolution(center, mapSize) {
      let axy, bxy;
      let mapAngle = $scope.map.getView().getRotation();

      //-- Tourner à l'inverse le rectangle écran pour avoir des dimensions
      //-- en coordonnées terrain puis des dimensions (dx,dy) correspondant
      //-- correctement à la dimension pixel de l'écran.
      let pixelCenter = [mapSize[0] / 2, mapSize[1] / 2];
      //-- Rotation du coin bas gauche vers carte non orientée.
      let bottomLeft = [1, 1];
      axy = rotate(pixelCenter, bottomLeft, -mapAngle);
      //-- Obtention de la coordonnée terrain en non orientée.
      axy = $scope.map.getCoordinateFromPixel(axy);

      let topRight = mapSize;
      //-- Rotation du coin haut droit vers carte non orientée.
      bxy = rotate(pixelCenter, topRight, -mapAngle);
      //-- Obtention de la coordonnée terrain en non orientée.
      bxy = $scope.map.getCoordinateFromPixel(bxy);

      //-- La résolution se fait avec ds coordonnées non orientée.
      let mapWorldCoordinatesResolution = {};
      mapWorldCoordinatesResolution.x = Math.abs(
        (bxy[0] - axy[0]) / (mapSize[0] - 1)
      );
      mapWorldCoordinatesResolution.y = Math.abs(
        (axy[1] - bxy[1]) / (mapSize[1] - 1)
      );

      return mapWorldCoordinatesResolution;
    }


    const calculatePageBoundsPixels = (scale) => {
      var s = parseFloat(scale.value);
      var size = $scope.layout.map; // papersize in dot!
      var view = $scope.map.getView();

      var w, h;

      //-- Modèle sans carte .....
      if (size == undefined) return;

      //-- Taille papier du cadre en Metre terrain
      //            w = size.width / POINTS_PER_INCH * MM_PER_INCHES / 1000.0;
      //            h = size.height / POINTS_PER_INCH * MM_PER_INCHES / 1000.0;
      w = (((size.width * DEVICE_PIXEL_RATIO) / 72) * MM_PER_INCHES) / 1000.0;
      h = (((size.height * DEVICE_PIXEL_RATIO) / 72) * MM_PER_INCHES) / 1000.0;

      //-- Etendu terrain qui rentre dans le cadre de la carte papier
      w *= s;
      h *= s;

      //-- Centre en systeme carte (epsg:3857)

      var cc2 = view.getCenter();
      //-- Centre en systeme de projetion pour impression
      //-- Cadre d'impression en systeme de projection de l'impression
      let minx, miny, maxx, maxy;

      minx = cc2[0] - w / 2.0;
      miny = cc2[1] - h / 2.0;
      maxx = cc2[0] + w / 2.0;
      maxy = cc2[1] + h / 2.0;

      if ($scope.curPrintBbox == undefined) $scope.curPrintBbox = {};
      $scope.curPrintBbox.xmin = minx;
      $scope.curPrintBbox.xmax = maxx;
      $scope.curPrintBbox.ymin = miny;
      $scope.curPrintBbox.ymax = maxy;

      w = maxx - minx;
      h = maxy - miny;

      let mapSize = $scope.map.getSize();
      let res = getMapWorldCoordinatesResolution(cc2, mapSize);

      w /= res.x;
      h /= res.y;

      var center = [
        (mapSize[0] * DEVICE_PIXEL_RATIO) / 2,
        (mapSize[1] * DEVICE_PIXEL_RATIO) / 2,
      ];

      minx = center[0] - w / 2;
      miny = center[1] - h / 2;
      maxx = center[0] + w / 2;
      maxy = center[1] + h / 2;
      return [minx, miny, maxx, maxy];
    };


    $scope.$watch('options.active', function(newVal) {
      if (newVal === true) {
        activate();
      } else {
        deactivate();
      }
    });

    $scope.propertiestoexclude = { askedLegendLayers: [] };
    $scope.getReturnedTemplate = function(data, filename) {
      if (data) {
        $scope.rptCfg.reportCurrentConfigName = filename;
        if (
          $scope.printLegCfg &&
          $scope.printLegCfg.result &&
          $scope.printLegCfg.result.length > 0 &&
          data &&
          data.savedata &&
          data.savedata.length > 0
        ) {
          var names = $scope.printLegCfg.result
            .map(function(x) {
              if (x && angular.isDefined(x.name)) return x.name;
            })
            .filter(function(x) {
              if (angular.isDefined(x)) return x;
            });
          data.savedata.map(function(x) {
            if (x && angular.isDefined(x.name)) {
              var idx = names.indexOf(x.name);
              if (~idx) {
                var ex = $scope.printLegCfg.result[idx];
                ex.status = 'overflow';
                ex.shrinkFactor = x.shrinkFactor;
                ex.layerFontSize = x.layerFontSize;
                ex.classFontSize = x.classFontSize;
                ex.themeFontSize = x.themeFontSize;
                ex.askedColumnNumber = x.askedColumnNumber;
                ex.forcedFontSize = x.forcedFontSize;

                ex.forceFactor = x.forceFactor;
                ex.forceThemeFontSize = x.forceThemeFontSize;
                ex.forceLayerFontSize = x.forceLayerFontSize;
                ex.forceClassFontSize = x.forceClassFontSize;
                ex.forceColumnNumber = x.forceColumnNumber;

                if (ex.askedButNotDrawn == undefined) ex.askedButNotDrawn = [];
                if (x.selected && ex.selected) {
                  Object.keys(x.selected).map(function(y) {
                    if (angular.isDefined(y) && ex.selected.hasOwnProperty(y))
                      ex.selected[y] = x.selected[y];
                    ex.askedButNotDrawn[y] = '';
                  });
                }
              }
            }
          });
          swal({
            title: $filter('translate')('print.dialog.get'),
            text: $filter('translate')('print.dialog.sucess'),
            type: 'success',
            icon: 'success',
            showConfirmButton: false,
            buttons: false,
            timer: 1000,
          });
        } else {
          swal({
            title: $filter('translate')('print.dialog.get'),
            text: $filter('translate')('print.dialog.fail'),
            icon: 'error',
            type: 'error',
            confirmButtonColor: '#F50072',
            showConfirmButton: true,
          });
        }
      }
    };

    $scope.getVisibleLayers = function(proj) {
      var layers = gclayers.getOperationalLayerCollection();
      var resolution = $scope.map.getView().getResolution();
      var layers0 = [],
        fti;
      const addedLayer = [];

      angular.forEach(layers, function(layer) {
        fti = layer.get('fti');
        if (
          layer.name == 'Edition' ||
          (layer.visible &&
            (layer.getMinResolution() == undefined ||
              resolution >= layer.getMinResolution()) &&
            (layer.getMaxResolution() == Infinity ||
              resolution < layer.getMaxResolution()) &&
            (!fti || (fti && addedLayer.indexOf(fti.name) === -1)))
        ) {
          addedLayer.push(layer.name);
          if (fti && !(layer instanceof ol.layer.Group)) {
            const enc = pv2LayerServices.encodeLayer(
              layer,
              proj,
              $scope,
              osmUrl,
              $scope.extentp
            );
            if (enc && enc.layer) {
              layers0.push(fti.alias);
            }
          }
        }
      });
      return layers0;
    };

    $scope.getLayersConfiguredForScale = function(proj) {
      var layers = gclayers.getOperationalLayerCollection();
      var layers0 = [],
        fti;
      var addedLayer = [];

      angular.forEach(layers, function(layer) {
        fti = layer.get('fti');
        if (
          layer.name == 'Edition' ||
          ((layer.minScale == undefined ||
            Number($scope.scale.value) >= layer.minScale) &&
            (layer.maxScale == undefined ||
              Number($scope.scale.value) < layer.maxScale) &&
            (!fti || (fti && addedLayer.indexOf(fti.name) === -1)))
        ) {
          addedLayer.push(layer.name);
          if (!(layer instanceof ol.layer.Group)) {
            const enc = pv2LayerServices.encodeLayer(
              layer,
              proj,
              $scope,
              osmUrl,
              $scope.extentp
            );
            if (enc && enc.layer && fti != undefined) {
              layers0.push(fti.alias);
            }
          }
        }
      });
      return layers0;
    };

    $scope.setParamData = function(paramData) {
      var comp,
        rcn = [],
        ind;

      if (paramData.savedata) {
        if ($scope.printLegCfg == undefined) {
          $scope.printLegCfg = {};
          $scope.printLegCfg.cfg = {};
        }
        if ($scope.dialogConfigCallType == 'parametrage')
          $scope.printLegCfg.result = paramData.savedata;
        else {
          //-- Dans le cas de synthese suite à emploi
          //-- d'une configuration de la légende,
          //-- on préserve e nombre réel de colonnes
          //-- mis dans la légende retourné par l'impression.
          for (ind = 0; ind < $scope.printLegCfg.result.length; ind++)
            rcn.push($scope.printLegCfg.result[ind].realColumnNumber);
          $scope.printLegCfg.result = paramData.savedata;
          for (ind = 0; ind < $scope.printLegCfg.result.length; ind++)
            $scope.printLegCfg.result[ind].realColumnNumber = rcn[ind];
        }
        $scope.printLegCfg.name = paramData.name;
        $scope.printLegCfg.id = paramData.id;
      } else $scope.paramData = $scope.printLegCfg = paramData;
      if ($scope.dialogConfigCallType == 'parametrage') {
        $scope.printLegCfg.result.map(function(it1) {
          if (it1.askedButNotDrawn) {
            for (comp in it1.askedButNotDrawn) it1.askedButNotDrawn[comp] = '';
          }
        });
      }
      pv2Config.addMissingLayersToAskedLayers(
        $scope.printLegCfg.result,
        $scope
      );
    };

    $scope.prepareParamInfo = function() {
      $scope.paramData = {};
      if ($scope.printLegCfg.pdfLegendsToDownload)
        $scope.paramData.pdfLegendsToDownload = angular.copy(
          $scope.printLegCfg.pdfLegendsToDownload
        );
      if ($scope.printLegCfg.result)
        $scope.paramData.result = angular.copy($scope.printLegCfg.result);
      if ($scope.printLegCfg.spec)
        $scope.paramData.spec = angular.copy($scope.printLegCfg.spec);
      return $scope.paramData;
    };
  };

  // ajout directive
  printV2Ctrl.$inject = [ '$scope', '$http', '$window', '$translate',
    '$timeout', 'gaDomUtils', 'gclayers', 'gaBrowserSniffer',
    'GraticulesFactory', 'BaseMapFactory', 'PrintModelFactory',
    'gcRestrictionProvider', '$q', '$rootScope', '$filter',
    'SridFactory', 'PrintLegendFactory', 'ParametersFactory',
    'pv2LayerServices', 'pv2Config', 'pv2Annotations',
    '$location', 'PortalsFactory', 'layersService', 'MeasureFactory'
  ];
  return printV2Ctrl;
});
