'use strict';
define(function() {
  var mapLeftMenu = function(
    UsersFactory,
    $rootScope,
    $timeout,
    $interval,
    versionsFactory,
    ConfigFactory,
    $sce,
    $window,
    authFactory,
    gcDirectivesList,
    ngDialog,
    $filter,
    ThemesFactory,
    homeFactory
  ) {
    return {
      templateUrl: 'js/XG/modules/common/views/directives/mapleftmenu.html',
      restrict: 'EA',
      link: function(scope) {
        const BASE_MENU_WIDTH = 380;

        /**
         * Info : we use indexes for :
         * categories : cause category can have the same name
         * tools : cause the same category can include the same tool multiple times
         */

        var portalid = angular.module('gcMain').portalid;

        scope.currenttool = {};
        scope.firstUpload = true;
        // -1 = closed
        // -2 = specialTool
        scope.currentCategoryIndex = -1;
        scope.wrapper = {
          active: false,
          width: BASE_MENU_WIDTH,
          isPinned: true,
        };


        scope.currentAppName = localStorage.getItem('app');

        function prepareCurrentUer() {
          scope.userAvatar = 'img/common/admin.png';

          if (
            $rootScope.xgos.user &&
            angular.isDefined($rootScope.xgos.user.thumbnail) &&
            $rootScope.xgos.user.thumbnail != null
          ) {
            var imgUrl =
              '/services/' +
              portalid +
              '/thumbnail/getthumb?f=json&fileName=' +
              $rootScope.xgos.user.thumbnail;

            scope.userAvatar = imgUrl;
          }
        }

        prepareCurrentUer();

        scope.kisHomeCfg = false;

        function prepareKisHomeInfo() {
          ConfigFactory.get('home', 'config', 'kis_home').then(function(res) {
            if (res.data != '') {
              scope.kisHomeCfg = res.data;
            }
          });
        }

        prepareKisHomeInfo();

        /**
         * Return app icon
         * @param app
         * @returns {string}
         */
        scope.getKisAppIcon = function(app) {
          var icon = 'fa fa-gears';
          if (app.type == 'MapApp') icon = 'fa fa-map-o';
          if (app.type == 'FormApp') icon = 'fa fa-check-square-o';
          if (app.type == 'SirocoApp') icon = 'fa fa-graph';
          if (app.type == 'CustomHtml') icon = 'fa fa-gear';
          if (~app.uid.indexOf('external_app')) icon = 'fa fa-link';

          return icon;
        };

        scope.getHomeContent = function() {
          return $sce.trustAsHtml(scope.kisHomeCfg.content);
        };

        /**
         * Reformate fonction avec homeAppSwitcher, homeAppCarousel, homepageNews
         * dans homeFactory.
         * @param app objet application issu de ApplicationFactory.resources.applications
         */
        scope.gotoApp = function(app) {
          const distinctAppname = scope.currentAppName !== app.name;
          homeFactory.gotoApp(portalid,app,distinctAppname);
        };

        let toggleSubMenu = function() {
          scope.wrapper.active = !scope.wrapper.active;
          needToOpenMenu = !needToOpenMenu;
        };

        let needToOpenMenu = true;
        scope.selectCategory = function(idx) {
          const tool = Object.assign({}, scope.currenttool);
          scope.currentToolIndex = -1;
          scope.currenttool = {};

          if (tool.directive === 'ancmapwidget') {
            scope.$broadcast('ancmapwidget_tool_click');
          }
          if (tool.directive === 'bacmapwidget') {
            scope.$broadcast('bacmapwidget_tool_click');
          }

          if(!needToOpenMenu){
            tool.active = false;

            // we broadcast these two events to close the overlay of
            // the map and also destroy the component because
            // every time we open it we create a new one.
            scope.$broadcast('openCloseTools_gaprintv2', tool);
            scope.$broadcast('openCloseTools_esriprint');
            scope.$broadcast('destroy_gaprintv2');
            scope.$broadcast('destroy_atlas');
            scope.$broadcast('destroy_ancMapWidget');
            scope.$broadcast('destroy_bacMapWidget');
            scope.$broadcast('destroy_mapModelMgtWidget');
            scope.$broadcast('openCloseTools_' + tool.directive, tool);
          }

          scope.wrapper.width = BASE_MENU_WIDTH;
          scope.categoryTools = [];
          scope.specialTool = false;

          if (needToOpenMenu) {
            toggleSubMenu();
          }
          else if (scope.currentCategoryIndex == idx) {
            //-- On a recliqué sur la catégorie ouverte, pour la fermer.
            scope.$broadcast('closingCategory');
            scope.currentCategoryIndex = -1;
            scope.currenttool = {};
            toggleSubMenu();
            return;
          }
          else {
            //-- On a cliqué une autre catégorie que celle ouverte.
            scope.$broadcast('switchingCategory');
          }
          $timeout(() => {
            scope.categoryTools = scope.tools[idx].modules;
            scope.currentCategoryIndex = idx;
            $rootScope.MapLeftMenucategory = scope.tools[idx].categorie;
            if(scope.categoryTools && scope.categoryTools.length ===1) {
              $timeout(() => {
                // Timeout pour laisser le temps à la directive du widget de charger
                scope.onToolclick(scope.categoryTools[0],0,scope.tools[idx].categorie);
              }, 200);
            }
          });
        };

        scope.specialTool = false;
        scope.selectSpecialTool = function(toolName) {
          scope.wrapper.width = 480;
          switch (toolName) {
            case 'versions':
              scope.wrapper.width = 980;
              break;
          }
          scope.currentCategoryIndex = -2;

          if (needToOpenMenu) {
            toggleSubMenu();
          } else if (scope.specialTool === toolName) {
            scope.specialTool = false;
            toggleSubMenu();
            return;
          }
          $timeout(function() {
            scope.specialTool = toolName;
          });
        };

        // alimente la liste des directives (pour voir si elles existent encore)
        // et des metadata (aide, urlwiki)
        let directivesList = gcDirectivesList.listtools();
        let directivesMetaData = gcDirectivesList.listtoolsMetaData();

        scope.existingDirectives = {};
        scope.widgetTooltips = {};
        directivesList.forEach(function(x) {
          scope.existingDirectives[x.directive] = true;
        });

        /**
         * Récupère les URL des fichiers d'aide personnalisés pour construire les tooltips d'aide des widgets
         * L'url est personnalisée ou bien is s'agit de l'url par défaut présente dans la propriété [directive] de l'objet renvoyé par <code>listtoolsMetaData</code>
         * @see directivesMetaData
         */
        ConfigFactory.getWikiConfig().then(
            res => {
                if (res.data) {
                  scope.customWiki = res.data;
                }else{
                  scope.customWiki = [];
                }
                for (let category of scope.tools) {
                  for (let tool of category.modules){
                    // boucle sur tous les widgets
                    if (directivesMetaData.hasOwnProperty(tool.directive)){
                      // recherche du rang du widget dans le tableau des widgets ayant un fichier d'aide custom
                      const indexInCustomWikiList = scope.customWiki.findIndex(
                          cfg => cfg.directive === tool.directive && cfg.config === tool.config
                              && cfg.name === tool.name && cfg.title === $filter('translate')(tool.title));
                      const isWidgetPresentInCustomWikiList = indexInCustomWikiList > -1;

                      // initialise le tableau des widgets ayant le même nom de directive (i.e instances d'un même widget)
                      scope.widgetTooltips[tool.directive] = scope.widgetTooltips.hasOwnProperty(tool.directive) ? scope.widgetTooltips[tool.directive] : [];

                      // implémentation de la possibilité de différencier les fichiers d'aide entre instance d'un même widget
                      // ajoute un nouvel objet contenant les propriétés nécessaires pour relier une configuration de widget à une instance de widget
                      // il n'y a pas de propriété unique non null permettant d'identifier une instance de widget
                      scope.widgetTooltips[tool.directive].push({
                        description: directivesMetaData[tool.directive].description,
                        title: $filter('translate')(tool.title),
                        category: category.categorie,
                        wiki: isWidgetPresentInCustomWikiList
                            ? scope.customWiki[indexInCustomWikiList].wiki
                            : directivesMetaData[tool.directive].wiki,
                      });
                    }
                  }
                }
            },
            (error) => {
              require('toastr').info(
                  $filter('translate')('layermanager.wikiretrieveerror') + error.data.message
              );
            }
        )

        scope.onToolclick = function(tool, index, widgetCategory) {
          scope.currentToolIndex = index;

          if (scope.currenttool.directive === 'ancmapwidget') {
            scope.$broadcast('ancmapwidget_tool_click');
          }
          if (scope.currenttool.directive === 'bacmapwidget') {
            scope.$broadcast('bacmapwidget_tool_click');
          }

          if (scope.currenttool != tool) {
            if (tool.directive == 'mapModelMgtWidget') {
              tool.widgetCategory = widgetCategory;
            }

            if (tool.directive !== 'mapcatalogwidget') {
              angular.element('#large_catalog_container').remove();
            }

            switch (tool.directive) {
              case 'exportgeopackage':
              case 'imexmbtiles':
                scope.wrapper.width = 620;
                break;
              case 'csvgeocoder':
              case 'selectfeaturetreewidget':
              case 'elasticwidget':
                scope.wrapper.width = 420;
                break;
              default:
                scope.wrapper.width = BASE_MENU_WIDTH;
                break;
            }

            if (angular.isDefined(tool.active) || !scope.firstUpload) {
              tool.active = true;
              scope.currenttool.active = false;
              scope.firstUpload = false;
            } else {
              tool.active = !tool.active;
              scope.currenttool.active = !scope.currenttool.active;
            }

            scope.$broadcast(
              'closeTools_' + scope.currenttool.directive,
              scope.currenttool
            );

            scope.$broadcast('openTools_' + tool.directive, tool);
            scope.currenttool = tool;
            UsersFactory.user_monitoring({
              sector: $rootScope.xgos.sector,
              path: 'map',
              category: 'map_widget',
              parameters: '[Ouverture][' + tool.name + ']',
            });
          } else {
            scope.currentToolIndex = -1;
            scope.currenttool = {};
            tool.active = !tool.active;
            scope.$broadcast('openCloseTools_' + tool.directive, tool);
          }
        };

        // ------ Scroll sidebar --------------

        scope.categoriesSidebar = $("#tools-wrapper")[0];

        let scrollUpInterval;
        let scrollDownInterval;

        scope.startScrollUp = function() {
          scope.stopScrollUp();
          scrollUpInterval = $interval(function() {
            if (scope.categoriesSidebar.scrollTop > 0) {
              scope.categoriesSidebar.scrollTop -= 1;
            }
          }, 5);
        };
    
        scope.stopScrollUp = function() {
          $interval.cancel(scrollUpInterval);
        };
    
        scope.startScrollDown = function() {
          scope.stopScrollDown();
          scrollDownInterval = $interval(function() {
            if (scope.categoriesSidebar.scrollTop < (scope.categoriesSidebar.scrollHeight - scope.categoriesSidebar.clientHeight)) {
              scope.categoriesSidebar.scrollTop += 2;
            }
          }, 5);
        };

        scope.stopScrollDown = function() {
          $interval.cancel(scrollDownInterval);
        };

        // évalue si la barre peut être scrollée vers le bas
        scope.canScrollBottom = () => {
          if (scope.categoriesSidebar) {
            return !((scope.categoriesSidebar.scrollHeight - scope.categoriesSidebar.clientHeight) >= Math.ceil(scope.categoriesSidebar.scrollTop) - 1
                && (scope.categoriesSidebar.scrollHeight - scope.categoriesSidebar.clientHeight) <= Math.ceil(scope.categoriesSidebar.scrollTop) + 1);
          }
        }

        // évalue si la barre peut être scrollée vers le haut
        scope.canScrollTop = () => {
          if (scope.categoriesSidebar) {
            return scope.categoriesSidebar.scrollTop !== 0;
          }
        }

        // ------ gestion des versions --------------
        scope.versionsData = {};
        versionsFactory.getVersions().then(function(res) {
          scope.versionsData = res[0];
          scope.versionTreeData = res[1];
        });

        scope.displayFirstLevel = true;

        // ----- calendar tmp -----------------------
        var date = new Date();
        var d = date.getDate();
        var m = date.getMonth();
        var y = date.getFullYear();
        let events = [
          {
            id: 1,
            title: 'Événement important',
            description: "RDV avec le responsable métier et l'élu",
            lieu: '22 avenue victor Hugo, 75001 Paris',
            start: new Date(y, m, 1, 9, 0),
            end: new Date(y, m, 1, 12, 0),
          },
          {
            id: 2,
            title: 'Essai terrain',
            description: 'Essai sur le terrain des nouvelles tablettes',
            lieu: "Centre d'entrainement",
            start: new Date(y, m, d - 5, 12, 0),
            end: new Date(y, m, d - 5, 13, 0),
          },
          {
            id: 3,
            title: 'Réunion 1',
            description: 'COPIL hebdo',
            lieu: 'Siège',
            start: new Date(y, m, d - 3, 16, 0),
            end: new Date(y, m, d - 3, 18, 0),
            allDay: false,
          },
          {
            id: 4,
            title: 'Réunion 2',
            description: 'COPERF mensuel',
            lieu: 'Siège',
            start: new Date(y, m, d + 4, 16, 0),
            end: new Date(y, m, d + 4, 17, 0),
            allDay: false,
          },
          {
            id: 5,
            title: 'Enteretien technicien',
            description: 'Entretien Jean Pierre Dupont',
            lieu: 'Siège',
            start: new Date(y, m, d + 1, 19, 0),
            end: new Date(y, m, d + 1, 22, 30),
            allDay: false,
          },
        ];
        scope.eventSources = [events];
        scope.eventData = {};
        scope.eventClick = function(event) {
          console.log(event.start);

          scope.eventData.data = {
            id: event.id,
            title: event.title,
            description: event.description,
            lieu: event.lieu,
            jour: event.start.format('DD'),
            heureDebut: event.start.format('HH:mm'),
            heureFin: event.end.format('h:mm'),
            mois: event.start.format('MMMM').toUpperCase(),
          };
        };

        scope.uiConfig = {
          calendar: {
            height: 450,
            editable: true,
            header: {
              left: 'title',
              center: '',
              right: 'prev,next',
            },
            eventClick: scope.eventClick,
            eventRender: scope.eventRender,
          },
        };

        scope.logout = function() {
          authFactory.logout();
        };
        var accountModale;
        scope.change_password = function() {
          scope.currentuserdata = {};
          scope.currentuser = scope.xgos.user;
          scope.currentuserdata.login = scope.xgos.user.login;
          scope.currentuserdata.password = scope.xgos.user.pass;
          scope.currentuserdata.confirm_password = scope.xgos.user.pass;
          initPattern();
          scope.checkPassword();
          accountModale = ngDialog.open({
            template:
              'js/XG/modules/authentication/views/modals/modal.user.edit.html',
            className: 'ngdialog-theme-plain width500 miniclose nopadding',
            closeByDocument: false,
            scope: scope,
          });
        };
        scope.updateuser = function() {
          if (!scope.currentuserdata.password.match(scope.pattern)) {
            alert($filter('translate')('rights.users.passwordDontMatchPattern'));
            return;
          }
          scope.currentuser.pass = scope.currentuserdata.password;
          UsersFactory.update(scope.currentuser, scope.currentuserdata.password);
          getUser();
          accountModale.close();
        };

        var getUser = function() {
          UsersFactory.token().then(function(res) {
            if (res.data.code == 403) {
              authFactory.goToLogin(true);
            } else {
              scope.currentuser = res.data;
              scope.currentuserdata.login = res.data.login;
              scope.currentuserdata.password = res.data.pass;
              scope.currentuserdata.confirm_password = res.data.pass;
            }
          });
        };
        scope.close_dialog = function() {
          accountModale.close();
        };

        let initPattern = () => {
          if(!$rootScope.xgos.portal.parameters || !$rootScope.xgos.portal.parameters.settingPwd){
            scope.pattern = '(?=(.*[A-Z]){1,})(?=(.*[a-z]){1,})(?=(.*\\d){1,})(?=(.*\\W){1,}).{10,50}';
            scope.minimumNumberUppercase = 1;
            scope.minimumNumberLowercase = 1;
            scope.minimumNumberDigits = 1;
            scope.minimumNumberSpecialCharacters = 1;
            scope.minimumNumberTotalCharacters = 10;
          } else{
            scope.pattern = '(?=(.*[A-Z]){$1,})(?=(.*[a-z]){$2,})(?=(.*\\d){$3,})(?=(.*\\W){$4,}).{$5,50}';
            if($rootScope.xgos.portal.parameters.settingPwd.minimumNumberUppercase){
              scope.pattern = scope.pattern.replace('$1',$rootScope.xgos.portal.parameters.settingPwd.minimumNumberUppercase)
              scope.minimumNumberUppercase = $rootScope.xgos.portal.parameters.settingPwd.minimumNumberUppercase;
            }else{
              scope.pattern = scope.pattern.replace('$1',0)
            }
            if($rootScope.xgos.portal.parameters.settingPwd.minimumNumberLowercase){
              scope.pattern = scope.pattern.replace('$2',$rootScope.xgos.portal.parameters.settingPwd.minimumNumberLowercase)
              scope.minimumNumberLowercase = $rootScope.xgos.portal.parameters.settingPwd.minimumNumberLowercase;
            }else{
              scope.pattern = scope.pattern.replace('$2',0)
            }
            if($rootScope.xgos.portal.parameters.settingPwd.minimumNumberDigits){
              scope.pattern = scope.pattern.replace('$3',$rootScope.xgos.portal.parameters.settingPwd.minimumNumberDigits)
              scope.minimumNumberDigits = $rootScope.xgos.portal.parameters.settingPwd.minimumNumberDigits;
            }else{
              scope.pattern = scope.pattern.replace('$3',0)
            }
            if($rootScope.xgos.portal.parameters.settingPwd.minimumNumberSpecialCharacters){
              scope.pattern = scope.pattern.replace('$4',$rootScope.xgos.portal.parameters.settingPwd.minimumNumberSpecialCharacters)
              scope.minimumNumberSpecialCharacters = $rootScope.xgos.portal.parameters.settingPwd.minimumNumberSpecialCharacters;
            }else{
              scope.pattern = scope.pattern.replace('$4',0)
            }
            if($rootScope.xgos.portal.parameters.settingPwd.minimumNumberTotalCharacters){
              scope.pattern = scope.pattern.replace('$5',$rootScope.xgos.portal.parameters.settingPwd.minimumNumberTotalCharacters)
              scope.minimumNumberTotalCharacters = $rootScope.xgos.portal.parameters.settingPwd.minimumNumberTotalCharacters;
            }else{
              scope.pattern = scope.pattern.replace('$5',0)
            }
          }
        }

        scope.checkPassword = () => {
          if(scope.minimumNumberUppercase && scope.currentuserdata.password && scope.currentuserdata.password.match(
            '(?=(.*[A-Z]){'+scope.minimumNumberUppercase+',}).{'+scope.minimumNumberUppercase+',50}')){
              scope.minimumNumberUppercaseValid = true;
          } else{
            scope.minimumNumberUppercaseValid = false;
          }
          if(scope.minimumNumberLowercase && scope.currentuserdata.password &&  scope.currentuserdata.password.match(
            '(?=(.*[a-z]){'+scope.minimumNumberLowercase+',}).{'+scope.minimumNumberLowercase+',50}')){
              scope.minimumNumberLowercaseValid = true;
          } else{
            scope.minimumNumberLowercaseValid = false;
          }
          if(scope.minimumNumberDigits && scope.currentuserdata.password && scope.currentuserdata.password.match(
            '(?=(.*\\d){'+scope.minimumNumberDigits+',}).{'+scope.minimumNumberDigits+',50}')){
              scope.minimumNumberDigitsValid = true;
          } else{
            scope.minimumNumberDigitsValid = false;
          }
          if(scope.minimumNumberSpecialCharacters && scope.currentuserdata.password && scope.currentuserdata.password.match(
            '(?=(.*\\W){'+scope.minimumNumberSpecialCharacters+',}).{'+scope.minimumNumberSpecialCharacters+',50}')){
              scope.minimumNumberSpecialCharactersValid = true;
          } else{
            scope.minimumNumberSpecialCharactersValid = false;
          }
          if(scope.minimumNumberTotalCharacters && scope.currentuserdata.password && scope.currentuserdata.password.match(
            '.{'+scope.minimumNumberTotalCharacters+',50}')){
              scope.minimumNumberTotalCharactersValid = true;
          } else{
            scope.minimumNumberTotalCharactersValid = false;
          }
        }

        /**
         * Recherche l'url du wiki du widget suivant la directive, le titre et la catégorie du widget.<br>
         * Il peut exister plusieurs instance du même widget. Un widget n'a pas une propriété unique
         * capable de l'identifier.
         * @param directive nom de la directive équivalent à une propriété de l'objet renvoyé par
         * <code>listtoolsMetaData</code>
         * @param title titre du widget donné lors de la configuration des outils de la carte
         * @param category catégorie de widgets à laquelle appartient le widget
         * @return {string} l'url personnalisée ou bien l'url par défaut présente dans la propriété
         * [directive] de l'objet renvoyé par <code>listtoolsMetaData</code>
         * @see gcDirectivesList.listtoolsMetaData
         */
        scope.getWiki = (directive, title, category) => {
          let wiki = '';
          if (scope.widgetTooltips.hasOwnProperty(directive)) {
            const widgetConfig = scope.widgetTooltips[directive].find(
                widget => (widget.title === title || widget.title === $filter('translate')(title))
                    && widget.category === category);
            if (widgetConfig && widgetConfig.hasOwnProperty('wiki')) {
              wiki = widgetConfig.wiki;
            }
          }
          return wiki;
        };

        /**
         * En mode config, ouvre la popup d'édition d'un lien de navigation
         * depuis la rubrique "Aide" au bas de la barre verticale gauche de l'application Map.
         * Au clic sur le bouton "Ajouter un lien"
         */
        scope.editHelpTool = () => {
          scope.$broadcast('openNewPortalNavLinkDialog');
        };

        /**
         * Au changement du bouton toggle switch du thème,<ul><li>
         * Enregistre le nouveau thème dans l'utilisateur</li><li>
         * Met à jour l'utilisateur</li></ul>
         */
        scope.addThemeToUser = () => {
          ThemesFactory.addDarkOrDefaultThemeToUser();
        };

        // Widgets nécessitant le maximum d'espace vertical
        // Directives pour lesquels la div id="tool" va prendre un padding-bottom = 0
        scope.maxHeightTools = ['layermanagerwidget', 'mapcatalogwidget', 'gcdefaultfilters'];
      },
    };
  };

  mapLeftMenu.$inject = [
    'UsersFactory',
    '$rootScope',
    '$timeout',
    '$interval',
    'versionsFactory',
    'ConfigFactory',
    '$sce',
    '$window',
    'authFactory',
    'gcDirectivesList',
    'ngDialog',
    '$filter',
    'ThemesFactory',
    'homeFactory'
  ];
  return mapLeftMenu;
});
