<commit_before>'use strict';
/* This service handles everything related to configuration files
 *
 * It is a provider of resources and services.
 *
 * this.configuration needs to be set from the outside through
 * defineConfiguration(), typically by a route that enters the application.
 *
 *
 *
 * As of now a valid conf file contains four sections
 *   main
 *   navbar
 *   plugins
 *   resources
 *
 * Uses $http to retrieve additional configuration files that are embedded
 * through the fileUrl property.
 * This could eventually be replaced by using the arethusa resource service
 * once it's clear where such conf files will be stored. Or maybe not,
 * we'll see.
 *
 */
angular.module('arethusa.core').service('configurator', [
  '$injector',
  '$http',
  '$rootScope',
  'Resource',
  'Auth',
  '$timeout',
  '$location',
  '$q',
  'Loader',
  function ($injector, $http, $rootScope, Resource, Auth,
            $timeout, $location, $q, Loader) {
    var self = this;
    var includeParam = 'fileUrl';

    var loader = new Loader();

    function filesToInclude(obj) {
      return arethusaUtil.findNestedProperties(obj, includeParam)[includeParam];
    }

    function checkLoadStatus() {
      if (loader.allLoaded()) {
        broadcastLoading();
      }
    }

    function broadcastLoading() {
      $rootScope.$broadcast('confLoaded');
    }

    // While using a timeout might seem hacky, it's just the write tool for the
    // job.
    // A run of the program looks like this:
    //
    // 1 Route with resolve function waits for the configurator to start
    // 2 Route resolves to start the MainCtrl
    // 3 MainCtrl waits for confLoaded event
    // 4 MainCtrl initializes the State object
    // 5 MainCtrl waits for stateLoaded event
    // 6 MainCtrl initializes itself and all plugins
    //
    // When the configurator needs to load external files (in 1)
    // the route resolves before the configurator is finished.
    // Only when it is finished the confLoaded event is fired.
    // External files are loaded asynchonously, the event is fired
    // from within a callback.
    // It is therefore guaranteed to happen after 2. Step 2 starts
    // the MainCtrl - it is the place where the listener to the
    // confLoaded event is defined.
    //
    // If there are no external files to load, the configurator gets
    // a chance to fire his confLoaded event while still being in step 1.
    // The event is fired, but as 2 hasn't run yet, there are no listeners.
    // The application fails to load properly.
    //
    // We therefore wrap the confLoaded event in a $timeout function.
    // Timeout with a delay of 0 defers the execution of the wrapped
    // function to the end of the current execution queue.
    // This is just what we need. Step 2 is already in the execution queue
    // at this time - if we can guarantee that the confLoaded event
    // happens after 2, everything is fine.
    function delayedBroadcast() {
      $timeout(function () {
        broadcastLoading();
      });
    }

    function includeExternalFiles(arrayOfObjects) {
      // If we have multiple files to include on the same level,
      // we need to declare all unloaded before we start including
      // files.
      angular.forEach(arrayOfObjects, function(obj, i) {
        loader.declareUnloaded(obj);
      });

      angular.forEach(arrayOfObjects, function (obj, i) {
        $http.get(obj[includeParam]).then(function (res) {
          // We have to delete fileUrl upfront.
          // When the object gets extended by a response, this response
          // might contain another fileUrl property. If that is the case
          // we then go on to look for such properties and call the function
          // recursively.
          delete obj[includeParam];
          angular.extend(obj, res.data);
          // As we want to load all potential external conf file BEFORE the application
          // starts, we have to apply this little trick:
          // Before the asynchronous call to retrieve an external file is made, we
          // declare a false load status, which we resolve inside the callback.
          //
          // Once we say we are loaded, we immediately check if our now extended object
          // has another external file to load. If it does, the load status of our
          // object will be immediately false again.
          // On the end of each callback we check all load states. If everything has
          // loaded successfully, we broadcast an event an let others now that the
          // configurator is finished.
          loader.declareLoaded(obj);
          includeExternalFiles(filesToInclude(obj));
          checkLoadStatus();
        });
      });
    }

    // Receives an external file and resolves it to a valid configuration file.
    // The second param is optional.
    this.defineConfiguration = function (confFile, location) {
      var conf = this.loadConfFile(confFile, location);
      this.configuration = conf.data;
      this.confFileLocation = conf.location;
    };

    this.loadConfFile = function (confFile, location) {
      var conf = {
          location: location,
          data: confFile
        };
      var fti = filesToInclude(conf.data);
      if (fti.length === 0) {
        delayedBroadcast();
      } else {
        // this function will eventually broadcast the load event
        includeExternalFiles(fti);
      }
      return conf;
    };

    this.loadAdditionalConf = function(confs) {
      var proms = arethusaUtil.inject([], confs, function(memo, plugin, url) {
        // Use the notifier for error handling!
        $http.get(url).then(function(res) {
          angular.extend(self.configurationFor(plugin), res.data);
        });
      });
      return $q.all(proms);
    };

    // Returns an empty configuration files with all sections
    // as empty object properties.
    // Useful for the configuration editor.
    this.getConfTemplate = function () {
      return {
        main: {},
        navbar: {},
        plugins: {},
        resources: {}
      };
    };

    // Merges two configuration objects.
    // There is a clear contract that has to be fulfilled to make this work:
    //
    // The datatypes of individual properties need to be static.
    // E.g.
    //
    // {<commit_msg>Works better when we really catch the promise...<commit_after>'use strict';
/* This service handles everything related to configuration files
 *
 * It is a provider of resources and services.
 *
 * this.configuration needs to be set from the outside through
 * defineConfiguration(), typically by a route that enters the application.
 *
 *
 *
 * As of now a valid conf file contains four sections
 *   main
 *   navbar
 *   plugins
 *   resources
 *
 * Uses $http to retrieve additional configuration files that are embedded
 * through the fileUrl property.
 * This could eventually be replaced by using the arethusa resource service
 * once it's clear where such conf files will be stored. Or maybe not,
 * we'll see.
 *
 */
angular.module('arethusa.core').service('configurator', [
  '$injector',
  '$http',
  '$rootScope',
  'Resource',
  'Auth',
  '$timeout',
  '$location',
  '$q',
  'Loader',
  function ($injector, $http, $rootScope, Resource, Auth,
            $timeout, $location, $q, Loader) {
    var self = this;
    var includeParam = 'fileUrl';

    var loader = new Loader();

    function filesToInclude(obj) {
      return arethusaUtil.findNestedProperties(obj, includeParam)[includeParam];
    }

    function checkLoadStatus() {
      if (loader.allLoaded()) {
        broadcastLoading();
      }
    }

    function broadcastLoading() {
      $rootScope.$broadcast('confLoaded');
    }

    // While using a timeout might seem hacky, it's just the write tool for the
    // job.
    // A run of the program looks like this:
    //
    // 1 Route with resolve function waits for the configurator to start
    // 2 Route resolves to start the MainCtrl
    // 3 MainCtrl waits for confLoaded event
    // 4 MainCtrl initializes the State object
    // 5 MainCtrl waits for stateLoaded event
    // 6 MainCtrl initializes itself and all plugins
    //
    // When the configurator needs to load external files (in 1)
    // the route resolves before the configurator is finished.
    // Only when it is finished the confLoaded event is fired.
    // External files are loaded asynchonously, the event is fired
    // from within a callback.
    // It is therefore guaranteed to happen after 2. Step 2 starts
    // the MainCtrl - it is the place where the listener to the
    // confLoaded event is defined.
    //
    // If there are no external files to load, the configurator gets
    // a chance to fire his confLoaded event while still being in step 1.
    // The event is fired, but as 2 hasn't run yet, there are no listeners.
    // The application fails to load properly.
    //
    // We therefore wrap the confLoaded event in a $timeout function.
    // Timeout with a delay of 0 defers the execution of the wrapped
    // function to the end of the current execution queue.
    // This is just what we need. Step 2 is already in the execution queue
    // at this time - if we can guarantee that the confLoaded event
    // happens after 2, everything is fine.
    function delayedBroadcast() {
      $timeout(function () {
        broadcastLoading();
      });
    }

    function includeExternalFiles(arrayOfObjects) {
      // If we have multiple files to include on the same level,
      // we need to declare all unloaded before we start including
      // files.
      angular.forEach(arrayOfObjects, function(obj, i) {
        loader.declareUnloaded(obj);
      });

      angular.forEach(arrayOfObjects, function (obj, i) {
        $http.get(obj[includeParam]).then(function (res) {
          // We have to delete fileUrl upfront.
          // When the object gets extended by a response, this response
          // might contain another fileUrl property. If that is the case
          // we then go on to look for such properties and call the function
          // recursively.
          delete obj[includeParam];
          angular.extend(obj, res.data);
          // As we want to load all potential external conf file BEFORE the application
          // starts, we have to apply this little trick:
          // Before the asynchronous call to retrieve an external file is made, we
          // declare a false load status, which we resolve inside the callback.
          //
          // Once we say we are loaded, we immediately check if our now extended object
          // has another external file to load. If it does, the load status of our
          // object will be immediately false again.
          // On the end of each callback we check all load states. If everything has
          // loaded successfully, we broadcast an event an let others now that the
          // configurator is finished.
          loader.declareLoaded(obj);
          includeExternalFiles(filesToInclude(obj));
          checkLoadStatus();
        });
      });
    }

    // Receives an external file and resolves it to a valid configuration file.
    // The second param is optional.
    this.defineConfiguration = function (confFile, location) {
      var conf = this.loadConfFile(confFile, location);
      this.configuration = conf.data;
      this.confFileLocation = conf.location;
    };

    this.loadConfFile = function (confFile, location) {
      var conf = {
          location: location,
          data: confFile
        };
      var fti = filesToInclude(conf.data);
      if (fti.length === 0) {
        delayedBroadcast();
      } else {
        // this function will eventually broadcast the load event
        includeExternalFiles(fti);
      }
      return conf;
    };

    this.loadAdditionalConf = function(confs) {
      var proms = arethusaUtil.inject([], confs, function(memo, plugin, url) {
        // Use the notifier for error handling!
        var promise = $http.get(url).then(function(res) {
          angular.extend(self.configurationFor(plugin), res.data);
        });
        memo.push(promise);
      });
      return $q.all(proms);
    };

    // Returns an empty configuration files with all sections
    // as empty object properties.
    // Useful for the configuration editor.
    this.getConfTemplate = function () {
      return {
        main: {},
        navbar: {},
        plugins: {},
        resources: {}
      };
    };

    // Merges two configuration objects.
    // There is a clear contract that has to be fulfilled to make this work:
    //
    // The datatypes of individual properties need to be static.
    // E.g.
    //
    // {
{'fraction_non_alphanumeric': 0.08632190222082713, 'fraction_numerical': 0.002354233696931649, 'mean_word_length': 2.327415143603133, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5199103', 'n_tokens_mistral': 3308, 'n_tokens_neox': 3229, 'n_words': 1398}