(function () {
  'use strict';

  /*
   * 2ndFA Session explorer
   */
  /*
   * AngularJS applications
   */
  var categories, hiddenAttributes, llapp, max, menu, overScheme, schemes;

  // Max number of session to display (see overScheme)
  max = 25;

  // Queries to do each type of display: each array item corresponds to the depth
  // of opened nodes in the tree
  schemes = {
    _whatToTrace: [function (t, v) {
      return `groupBy=substr(${t},1)`;
    }, function (t, v) {
      return `${t}=${v}*`;
    }]
  };
  overScheme = {
    _whatToTrace: function (t, v, level, over) {
      console.debug('overSchema => level', level, 'over', over);
      if (level === 1 && v.length > over) {
        return `${t}=${v}*&groupBy=substr(${t},${level + over + 1})`;
      } else {
        return null;
      }
    }
  };
  hiddenAttributes = '_password';

  // Attributes to group in session display
  categories = {
    dateTitle: ['_utime', '_startTime', '_updateTime'],
    sfaTitle: ['_2fDevices']
  };

  // Menu entries
  menu = {
    home: []
  };
  llapp = angular.module('llngSessionsExplorer', ['ui.tree', 'ui.bootstrap', 'llApp']);

  // Main controller
  llapp.controller('SessionsExplorerCtrl', ['$scope', '$translator', '$location', '$q', '$http', function ($scope, $translator, $location, $q, $http) {
    var autoId, c, pathEvent, sessionType;
    $scope.links = links;
    $scope.menulinks = menulinks;
    $scope.staticPrefix = staticPrefix;
    $scope.scriptname = scriptname;
    $scope.formPrefix = formPrefix;
    $scope.availableLanguages = availableLanguages;
    $scope.waiting = true;
    $scope.showM = false;
    $scope.showT = true;
    $scope.data = [];
    $scope.currentScope = null;
    $scope.currentSession = null;
    $scope.menu = menu;
    $scope.searchString = '';
    $scope.sfatypes = {};
    // Import translations functions
    $scope.translateP = $translator.translateP;
    $scope.translate = $translator.translate;
    $scope.translateTitle = function (node) {
      return $translator.translateField(node, 'title');
    };
    sessionType = 'persistent';
    // Handle menu items
    $scope.menuClick = function (button) {
      if (button.popup) {
        window.open(button.popup);
      } else {
        if (!button.action) {
          button.action = button.title;
        }
        switch (typeof button.action) {
          case 'function':
            button.action($scope.currentNode, $scope);
            $scope[button.action]();
            break;
          case 'string':
            $scope[button.action]();
            break;
          default:
            console.warn('Unknown action type', typeof button.action);
        }
      }
      return $scope.showM = false;
    };
    //# SESSIONS MANAGEMENT
    // Search 2FA sessions
    $scope.search2FA = function (clear) {
      if (clear) {
        $scope.searchString = '';
      }
      $scope.currentSession = null;
      $scope.data = [];
      return $scope.updateTree2('', $scope.data, 0, 0);
    };

    // Delete 2FA device
    $scope.delete2FA = function (type, epoch) {
      var e, i, items, len;
      items = document.querySelectorAll(`.data-${epoch}`);
      for (i = 0, len = items.length; i < len; i++) {
        e = items[i];
        e.remove();
      }
      $scope.waiting = true;
      $http['delete'](`${scriptname}sfa/${sessionType}/${$scope.currentSession.id}?type=${type}&epoch=${epoch}`).then(function (response) {
        return $scope.waiting = false;
      }, function (resp) {
        return $scope.waiting = false;
      });
      return $scope.showT = false;
    };
    // Open node
    $scope.stoggle = function (scope) {
      var node;
      node = scope.$modelValue;
      if (node.nodes.length === 0) {
        $scope.updateTree(node.value, node.nodes, node.level, node.over, node.query, node.count);
      }
      return scope.toggle();
    };
    // Display selected session
    $scope.displaySession = function (scope) {
      var sessionId, transformSession;
      // Private functions

      // Session preparation
      transformSession = function (session) {
        var _stToStr, array, arrayDate, attr, attrs, category, epoch, i, k, key, len, len1, name, pattern, res, sfDevice, subres, time, type, value;
        _stToStr = function (s) {
          return s;
        };
        time = session._utime;
        // 1. Replace values if needed
        for (key in session) {
          value = session[key];
          if (!value) {
            delete session[key];
          } else {
            if (typeof session === 'string' && value.match(/; /)) {
              session[key] = value.split('; ');
            }
            if (typeof session[key] !== 'object') {
              if (hiddenAttributes.match(new RegExp('\b' + key + '\b'))) {
                session[key] = '********';
              } else if (key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)) {
                session[key] = $scope.localeDate(value);
              } else if (key.match(/^(_startTime|_updateTime)$/)) {
                value = _stToStr(value);
                pattern = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/;
                arrayDate = value.match(pattern);
                session[key] = `${arrayDate[3]}/${arrayDate[2]}/${arrayDate[1]} à ${arrayDate[4]}:${arrayDate[5]}:${arrayDate[6]}`;
              }
            }
          }
        }
        res = [];
        // 2. Push session keys in result, grouped by categories
        for (category in categories) {
          attrs = categories[category];
          subres = [];
          for (i = 0, len = attrs.length; i < len; i++) {
            attr = attrs[i];
            if (session[attr]) {
              if (attr === "_2fDevices" && session[attr]) {
                array = JSON.parse(session[attr]);
                if (array.length > 0) {
                  subres.push({
                    title: "2fid",
                    value: "name",
                    type: "type",
                    epoch: "date"
                  });
                  for (k = 0, len1 = array.length; k < len1; k++) {
                    sfDevice = array[k];
                    for (key in sfDevice) {
                      value = sfDevice[key];
                      if (key === 'type') {
                        type = value;
                      }
                      if (key === 'name') {
                        name = value;
                      }
                      if (key === 'epoch') {
                        epoch = value;
                      }
                    }
                    subres.push({
                      title: '[' + type + ']' + epoch,
                      type: type,
                      value: name,
                      epoch: epoch,
                      sfrow: true
                    });
                  }
                }
                delete session[attr];
              } else if (session[attr].toString().match(/\w+/)) {
                subres.push({
                  title: attr,
                  value: session[attr]
                });
                delete session[attr];
              } else {
                delete session[attr];
              }
            } else {
              delete session[attr];
            }
          }
          if (subres.length > 0) {
            res.push({
              title: `__${category}__`,
              nodes: subres
            });
          }
        }
        return {
          _utime: time,
          nodes: res
        };
      };
      $scope.currentScope = scope;
      sessionId = scope.$modelValue.session;
      $http.get(`${scriptname}sfa/${sessionType}/${sessionId}`).then(function (response) {
        $scope.currentSession = transformSession(response.data);
        return $scope.currentSession.id = sessionId;
      });
      return $scope.showT = false;
    };
    $scope.localeDate = function (s) {
      var d;
      d = new Date(s * 1000);
      return d.toLocaleString();
    };
    // Function to change interface language
    $scope.getLanguage = function (lang) {
      $scope.lang = lang;
      $scope.form = 'white';
      $scope.init();
      return $scope.showM = false;
    };
    // URI local path management
    pathEvent = function (event, next, current) {
      var n;
      n = next.match(/#!?\/(\w+)/);
      if (n === null || n[1].match(/^(persistent)$/)) {
        $scope.type = '_session_uid';
      }
      return $scope.init();
    };
    $scope.$on('$locationChangeSuccess', pathEvent);
    // Functions to update tree: download value of opened subkey
    autoId = 0;
    $scope.updateTree = function (value, node, level, over, currentQuery, count) {
      var query, scheme, tmp;
      $scope.waiting = true;
      // Query scheme selection:

      //  - if defined above
      //  - default to _whatToTrace scheme
      scheme = schemes[$scope.type] ? schemes[$scope.type] : schemes._whatToTrace;
      // Build query using schemes
      query = scheme[level]($scope.type, value, currentQuery);
      // If number of session exceeds "max" and overScheme exists, call it
      if (count > max && overScheme[$scope.type]) {
        if (tmp = overScheme[$scope.type]($scope.type, value, level, over, currentQuery)) {
          over++;
          query = tmp;
          level = level - 1;
        } else {
          over = 0;
        }
      } else {
        over = 0;
      }
      // Launch HTTP query
      return $http.get(`${scriptname}sfa/${sessionType}?${query}` + Object.entries($scope.sfatypes).map(function (x) {
        if (x[1]) {
          return "&type=" + x[0];
        } else {
          return "";
        }
      }).join("")).then(function (response) {
        var data, i, len, n, ref;
        data = response.data;
        if (data.result) {
          ref = data.values;
          for (i = 0, len = ref.length; i < len; i++) {
            n = ref[i];
            autoId++;
            n.id = `node${autoId}`;
            if (level < scheme.length - 1) {
              n.nodes = [];
              n.level = level + 1;
              n.query = query;
              n.over = over;
            }
            node.push(n);
          }
          if (value === '') {
            $scope.total = data.total;
          }
        }
        return $scope.waiting = false;
      }, function (resp) {
        return $scope.waiting = false;
      });
    };

    // Functions to filter U2F sessions tree : download value of opened subkey
    $scope.updateTree2 = function (value, node, level, over, currentQuery, count) {
      var query, scheme, tmp;
      $scope.waiting = true;
      // Query scheme selection:

      //  - if defined above
      //  - _updateTime must be displayed as startDate
      //  - default to _whatToTrace scheme
      scheme = schemes[$scope.type] ? schemes[$scope.type] : $scope.type === '_updateTime' ? schemes._startTime : schemes._whatToTrace;
      // Build query using schemes
      query = scheme[level]($scope.type, value, currentQuery);
      // If number of session exceeds "max" and overScheme exists, call it
      if (count > max && overScheme[$scope.type]) {
        if (tmp = overScheme[$scope.type]($scope.type, value, level, over, currentQuery)) {
          over++;
          query = tmp;
          level = level - 1;
        } else {
          over = 0;
        }
      } else {
        over = 0;
      }
      // Launch HTTP
      return $http.get(`${scriptname}sfa/${sessionType}?_session_uid=${$scope.searchString}*&groupBy=substr(_session_uid,${$scope.searchString.length})` + Object.entries($scope.sfatypes).map(function (x) {
        if (x[1]) {
          return "&type=" + x[0];
        } else {
          return "";
        }
      }).join("")).then(function (response) {
        var data, i, len, n, ref;
        data = response.data;
        if (data.result) {
          ref = data.values;
          for (i = 0, len = ref.length; i < len; i++) {
            n = ref[i];
            autoId++;
            n.id = `node${autoId}`;
            if (level < scheme.length - 1) {
              n.nodes = [];
              n.level = level + 1;
              n.query = query;
              n.over = over;
            }
            node.push(n);
          }
          if (value === '') {
            $scope.total = data.total;
          }
        }
        return $scope.waiting = false;
      }, function (resp) {
        return $scope.waiting = false;
      });
    };
    // Intialization function
    // Simply set $scope.waiting to false during $translator and tree root
    // initialization
    $scope.init = function () {
      $scope.waiting = true;
      $scope.data = [];
      $q.all([$translator.init($scope.lang), $scope.updateTree('', $scope.data, 0, 0)]).then(function () {
        return $scope.waiting = false;
      }, function (resp) {
        return $scope.waiting = false;
      });
      // Colorized link
      $scope.activeModule = "2ndFA";
      return $scope.myStyle = {
        color: '#ffb84d'
      };
    };
    // Query scheme initialization
    // Default to '_whatToTrace'
    c = $location.path().match(/^\/(\w+)/);
    return $scope.type = c ? c[1] : '_whatToTrace';
  }]);

})();