'use strict';
define(function() {
  var geolocalisationwidget = function(
    NominatimFactory,
    GoogleGeocodeFactory,
    ConfigFactory,
    $translate,
    ngDialog,
    $http,
    $filter,
    $rootScope,
    kisGeocodageFactory,
    gaJsUtils,
    GeolocalisationService
  ) {
    return {
      templateUrl:
        'js/XG/widgets/mapapp/geolocalisation/views/geolocalisationwidget.html',
      restrict: 'A',

      //methode executée au chargement de la page
      link: function(scope, element, attrs, ctrl) {
        scope.bycoordinate = angular.isDefined(attrs.bycoordinate)
          ? attrs.bycoordinate
          : false;
        scope.tabs = [
          {
            titleKey: 'geolocalisation.tabAdresse',
            title: 'geolocalisation.tabAdresse',
          },
          {
            titleKey: 'geolocalisation.tabCoordinate',
            title: 'geolocalisation.tabCoordinate',
          },
        ];

        if (
          gaJsUtils.checkNestedProperty(
            'portal.parameters.apikey.what3words',
            $rootScope.xgos
          )
        ) {
          scope.tabs.push({
            titleKey: 'what3words.tabWhat3words',
            title: 'what3words.tabWhat3words',
          });
        }

        scope.tabs.activeTab = 0;

        scope.landorcity = {};

        scope.$watch(
          'landorcity.value',
          function(landorcity) {
            var cityCountry;
            scope.config.forEach(function(cfg, index) {
              if (cfg.name == 'filter') cityCountry = scope.config[index];
            });
            if (landorcity == '') {
              cityCountry.value.city = '';
              cityCountry.value.land = '';
            } else {
              if (
                angular.isDefined(landorcity) &&
                landorcity.hasOwnProperty('address_components')
              ) {
                cityCountry.value.city = '';
                cityCountry.value.land = '';
                landorcity.address_components.forEach(function(cmp) {
                  if (cmp.types[0] == 'locality')
                    cityCountry.value.city = cmp.long_name;
                  if (cmp.types[0] == 'country')
                    cityCountry.value.land = cmp.long_name;
                });
              }
            }
          },
          1
        );

        scope.getValueMessage = function(messagekey, objet, objetkey) {
          $translate(messagekey).then(function(res) {
            objet[objetkey] = res;
          });
        };

        scope.getValueMessage(
          'geolocalisation.tabAdresse',
          scope.tabs[0],
          'title'
        );
        scope.getValueMessage(
          'geolocalisation.tabCoordinate',
          scope.tabs[1],
          'title'
        );

        scope.tabs.activeTab = 0;

        //////////////////////// Gestion de la configuration //////////////////////////////

        /**
         * get Kis Geocodage Config
         */
        var readKisGeocodageConfig = function() {
          scope.config.forEach(function(cfg, index) {
            if (cfg.name == 'service' && cfg.value.kisgeocodage_value) {
              for (var i = 0; i < cfg.value.kisgeocodage_value.length; i++) {
                if (cfg.value.kisgeocodage_value[i].value == true) {
                  for (var j = 0; j < scope.kisgeocodage.length; j++) {
                    if (
                      scope.kisgeocodage[j].label ==
                      cfg.value.kisgeocodage_value[i].label
                    ) {
                      scope.kisgeocodage[j].value = true;
                    }
                  }
                }
              }
            }
          });
        };

        scope.config = [
          { name: 'filter', value: { land: '', city: '' } },
          {
            name: 'service',
            value: {
              nominatim: '',
              google: '',
              kisgeocodage_value: [],
            },
          },
          { name: 'srid', value: {} },
        ];

        /**
         * Récupère la configuration et permet de la modifer.
         * @returns {undefined}
         */
        scope.getConfig = function() {
          ConfigFactory.get('widgets', 'geolocalisation').then(function(res) {
            if (res.data !== '' && res.status == 200) {
              scope.config = res.data;
              var cityCountry;
              res.data.forEach(function(cfg, index) {
                if (cfg.name == 'filter') cityCountry = scope.config[index];
              });

              if (cityCountry.value.hasOwnProperty('city'))
                scope.landorcity.value = cityCountry.value.city;
              if (cityCountry.value.hasOwnProperty('land'))
                scope.landorcity.value += ', ' + cityCountry.value.land;

              readConfig();
            }
          });
        };

        scope.getConfig();

        /**
         * Récupère la configuration et permet de la modifer.
         * @returns {undefined}
         *
         */
        var ngDialogPromise;
        scope.openConfig = function() {
          readKisGeocodageConfig();
          ConfigFactory.get('widgets', 'geolocalisation').then(function() {
            ngDialogPromise = ngDialog.openConfirm({
              template:
                'js/XG/widgets/mapapp/geolocalisation/views/configuration.html',
              className:
                'ngdialog-theme-plain overflowY width800 nopadding miniclose',
              scope: scope,
            });
            ngDialogPromise.then(function(data) {
              scope.saveconfig();
              require('toastr').success(data);
            });
          });
        };

        scope.currentsrid = {
          name: 'EPSG:3857',
          description:
            '+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.selectedsrid = scope.currentsrid;
        ConfigFactory.get('main', 'coordinate').then(function(res) {
          //console.log(res.data)   ;
          if (res.data != '') {
            scope.currentsrid = res.data;
            scope.selectedsrid = res.data;
          }
        });

        scope.saveconfig = function() {
          scope.config.forEach(function(cfg, index) {
            cfg.value.kisgeocodage_value = [];
            if (cfg.name == 'service') {
              scope.kisgeocodage.forEach(function(geocodage) {
                if (geocodage.value && geocodage.value == true) {
                  cfg.value.kisgeocodage_value.push(geocodage);
                }
              });
            }
          });

          ConfigFactory.add(scope.config, 'widgets', 'geolocalisation').then(
            function(res) {
              // require('toastr').success(res.data);
              readConfig();
              GeolocalisationService.readConfig(scope.config);
            },
            function(reason) {
              require('toastr').error(reason);
            }
          );
        };

        var queryFilter;
        /**
         * Utility Method to concat research filters from config.
         * @returns {[type]}
         */
        function getFilterFromConfig() {
          queryFilter = '';
          for (var index = 0; index < scope.config.length; ++index) {
            if (
              scope.config[index].hasOwnProperty('name') &&
              scope.config[index].name == 'filter'
            ) {
              var filterObject = scope.config[index].value;
              if (
                filterObject !== undefined &&
                filterObject.hasOwnProperty('city') &&
                String(filterObject['city']).length > 0
              ) {
                queryFilter += ', ' + filterObject.city;
              }
              if (
                filterObject !== undefined &&
                filterObject.hasOwnProperty('land') &&
                String(filterObject['land']).length > 0
              ) {
                queryFilter += ', ' + filterObject.land;
              }
              break;
            }
          }
        }

        var nominatimService = false;
        var googleService = false;
        function getServiceNameFromConfig() {
          for (var index = 0; index < scope.config.length; ++index) {
            if (
              scope.config[index].hasOwnProperty('name') &&
              scope.config[index].name == 'service'
            ) {
              var serviceObject = scope.config[index].value;
              if (
                serviceObject !== undefined &&
                serviceObject.hasOwnProperty('google') &&
                String(serviceObject['google']).length > 0
              ) {
                googleService = serviceObject.google;
              }
              if (
                serviceObject !== undefined &&
                serviceObject.hasOwnProperty('nominatim') &&
                String(serviceObject['nominatim']).length > 0
              ) {
                nominatimService = serviceObject.nominatim;
              }

              break;
            }
          }
        }

        function readConfig() {
          getFilterFromConfig();
          getServiceNameFromConfig();
          readKisGeocodageConfig();
        }

        //////////////////////// Fin Gestion de la configuration //////////////////////////////

        var map = scope.map;
        var projection = map.getView().getProjection();
        scope.vectorLayer = kisGeocodageFactory.getMarkerLayer();
        map.addLayer(scope.vectorLayer);
        scope.vectorSource = scope.vectorLayer.getSource();
        scope.geocodageGMarkerLayerLoaded = true;

        //scope.inputAdress = "";
        scope.wait = false;
        scope.adress = {};

        /**
         * Getting Coordinates Informations from GoogleMap api
         * @param address
         * @returns {*}
         */
        scope.getInformationsFromAddress = function(address) {
          if (address == '') return false;
          var params = { address: address, sensor: false };
          return $http
            .get('https://maps.googleapis.com/maps/api/geocode/json', {
              params: params,
            })
            .then(function(res) {
              return res.data.results;
            });
        };

        /**
         * [searchAdress Recherche les lieux correspondant à la valeur de 'inputAdress',
         * en appelant un service web.]
         * @return {[type]} [description]
         */
        scope.searchAdress = function() {
          scope.wait = true;
          scope.activeAddress = {};
          scope.adress = [];
          var atLeastOneService = false;

          if (nominatimService) {
            atLeastOneService = true;

            NominatimFactory.search(scope.inputAdress + queryFilter)
              .then( (res) => {
                scope.wait = false;
                for (let i = 0; i < res.data.length; i++) {
                  const address = res.data[i];
                  address.origin = 'nominatim';
                  scope.adress.push(res.data[i]);
                }
              });
          }

          var urls = [];
          scope.kisgeocodage.forEach(function(geocodage) {
            if (geocodage.value == true) {
              atLeastOneService = true;
              urls.push(geocodage.url);
              var promise = kisGeocodageFactory.search(
                geocodage.url,
                scope.inputAdress
              );
              promise.then(function(res) {
                scope.wait = false;
                var adressResults = res.data.features;
                for (var i = 0; i < adressResults.length; i++) {
                  var aResult = adressResults[i];
                  var anAdress = {
                    address: {
                      state: aResult.properties.city,
                    },
                    display_name: aResult.properties.label,
                    lat: aResult.geometry.coordinates[1],
                    lon: aResult.geometry.coordinates[0],
                  };
                  anAdress.origin = geocodage.label;
                  scope.adress.push(anAdress);
                }
              });
            }
          });

          if (googleService) {
            atLeastOneService = true;
            var cityCountry;
            scope.config.forEach(function(cfg, index) {
              if (cfg.name == 'filter') cityCountry = scope.config[index];
            });
            var filters = {
              country: cityCountry.value.land,
              locality: cityCountry.value.city,
            };

            GoogleGeocodeFactory.getInformationsFromAddress(
              scope.inputAdress,
              filters
            ).then(function(res) {
              console.log(res);
              scope.wait = false;
              var adressResults = res.data.results;
              for (var i = 0; i < adressResults.length; i++) {
                var aResult = adressResults[i];
                var anAdress = {
                  address: {
                    state: aResult.address_components[3].long_name,
                  },
                  display_name: aResult.formatted_address,
                  lat: aResult.geometry.location.lat,
                  lon: aResult.geometry.location.lng,
                };
                anAdress.origin = 'google';
                scope.adress.push(anAdress);
              }
            });
          }

          if (!atLeastOneService) {
            scope.wait = false;
            require('toastr').error(
              $filter('translate')('geolocalisation.no_service')
            );
          }
        };

        /**
         * [clear vide la liste de resultats]
         * @return {[type]} [vide la liste de resultat]
         */
        scope.clear = function() {
          scope.adress = undefined;
        };

        scope.markerSet = false;
        scope.activeAddress = {};
        scope.selectedsrid = {};
        /**
         *
         * [seeOnMap Centre la carte sur le lieu correspondant à 'anAdress' et positionne sur la carte un marqueur et une délimitation du lieu.]
         * @param  {[type]} anAdress [description]
         * @param  {[type]} index [description]
         * @return {[type]}          [description]
         */

        scope.seeOnMap = function(anAdress, index) {
          var formerCenter = map.getView().getCenter();
          scope.markerSet = true;
          scope.activeAddress.value = index;

          //Coordonnées géographiques (WGS84), du centre du lieu choisi.
          var myLong = Number(anAdress.lon);
          var lat = Number(anAdress.lat);

          //Test qui fonctionne: (Coordonnées de Berlin): var projetedCoord = ol.proj.transform([13.37, 52.50], 'EPSG:4326', 'EPSG:3857');

          var mapCode = projection.getCode();
          //Projection des coordonnées du lieu dans le systeme de la carte
          var projetedCoord = ol.proj.transform(
            [myLong, lat],
            'EPSG:4326',
            mapCode
          );
          //Centrage de la carte sur le lieu
          map.getView().setCenter(projetedCoord);

          //Visualisation du lieu sur la carte
          scope.vectorSource.clear(true);
          //Visualisation du centre du lieu
          var centerFeature = new ol.Feature({
            name: anAdress.display_name,
          });
          centerFeature.setGeometry(new ol.geom.Point(projetedCoord));
          scope.vectorSource.addFeature(centerFeature);

          if (anAdress.geojson === undefined){
            const zIndex = gaJsUtils.getZIndexMax(map) + 1;
            scope.vectorLayer.setZIndex(zIndex);
            return;
          }
          //Visualisation du lieu
          var geojson = anAdress.geojson;
          var featureGeoCoordinates = geojson.coordinates;

          var feature = new ol.Feature({
            name: anAdress.display_name,
          });
          if (geojson.type == 'LineString') {
            //(featureGeoCoordinates is an Array of [myLong,lat] )

            //Coordonnées de l'objet permettant la visualisation du lieu, dans le systeme de coordonnées de la carte.
            var featureCoordinates = [];
            var index, len;
            for (
              index = 0, len = featureGeoCoordinates.length;
              index < len;
              ++index
            ) {
              featureCoordinates.push(
                ol.proj.transform(
                  featureGeoCoordinates[index],
                  'EPSG:4326',
                  mapCode
                )
              );
            }
            feature.setGeometry(new ol.geom.LineString(featureCoordinates));
          }
          if (geojson.type == 'Polygon') {
            //(featureGeoCoordinates is an Array of Array of [myLong,lat] )
            var polyFeatureCoordinates = [];
            var index1, len1;
            for (
              index1 = 0, len1 = featureGeoCoordinates.length;
              index1 < len1;
              ++index1
            ) {
              var subGeoCoordinate = featureGeoCoordinates[index1];
              polyFeatureCoordinates.push([]);
              var index2, len2;
              for (
                index2 = 0, len2 = subGeoCoordinate.length;
                index2 < len2;
                ++index2
              ) {
                polyFeatureCoordinates[index1].push(
                  ol.proj.transform(
                    subGeoCoordinate[index2],
                    'EPSG:4326',
                    mapCode
                  )
                );
              }
            }
            feature.setGeometry(new ol.geom.Polygon(polyFeatureCoordinates));
          }
          const zIndex = gaJsUtils.getZIndexMax(map) + 1;
          scope.vectorLayer.setZIndex(zIndex);
          scope.vectorSource.addFeature(feature);
        };

        /**
         * [clearMarker description]
         * @return {[type]} [description]
         */
        scope.clearMarker = function() {
          scope.markerSet = false;
          scope.vectorSource.clear(true);
        };

        scope.kisgeocodage = [];
        if (
          $rootScope.xgos.portal.parameters.kisgeocodage &&
          $rootScope.xgos.portal.parameters.kisgeocodage.length > 0
        ) {
          scope.kisgeocodage = $rootScope.xgos.portal.parameters.kisgeocodage;
        }
      },
    };
  };

  geolocalisationwidget.$inject = [
    'NominatimFactory',
    'GoogleGeocodeFactory',
    'ConfigFactory',
    '$translate',
    'ngDialog',
    '$http',
    '$filter',
    '$rootScope',
    'kisGeocodageFactory',
    'gaJsUtils',
    'GeolocalisationService'
  ];
  return geolocalisationwidget;
});
