    importPackage(Packages.java.io);
    importPackage(Packages.de.elo.ix.client);

    //@include lib_Class.js
    //@include lib_sol.common.RepoUtils.js
    //@include lib_sol.common.Config.js
    //@include lib_sol.common.ix.ServiceBase.js

    var logger = sol.create("sol.Logger", { scope: "sol.common.ix.services.GetConfig" });

    /**
     * Returns content of a configuration json file that is stored in ELO.
     *
     * This service is useful if information should be retrieved within external web applications.
     *
     * # Simple configuration
     * This loads a configuration from a single JSON configuration file.
     *
     * As IX service call
     *
     *     sol.common.IxUtils.execute('RF_sol_common_service_GetConfig', {
     *       objId: "ARCPATH:/Administration/Business Solutions/pubsec/Configuration/pubsec.Config",
     *       forceReload: true  // optional, if true, the cache will be refreshed
     *     });
     *
     * Returns content of the configuration as followed:
     *
     *     {
     *       config: {
     *         // config content
     *         version: '9.00.001',
     *         ruleSetName: "MY_RULE",
     *         ...
     *       }
     *     }
     *
     * # Merged configuration
     * This loads a merged configuration from a hierarchy of JSON configuration files.
     *
     * As IX service call
     *
     *     sol.common.IxUtils.execute('RF_sol_common_service_GetMergedConfig', {
     *       compose: "ARCPATH:/Administration/Business Solutions/pubsec/Configuration/pubsec.Config"
     *       forceReload: true  // optional, if true, the cache will be refreshed
     *     });
     *
     * Returns content of the configuration as followed:
     *
     *     {
     *       config: {
     *         // config content
     *         version: '9.00.001',
     *         ruleSetName: "MY_CUSTOM_RULE",
     *         ...
     *       }
     *     }
     *
     * # Configuration hierarchy
     * This loads all JSON configuration files from the merge hierarchy, without performing the merge.
     * By default, this just returns the GUIDs.
     *
     * As IX service call
     *
     *     sol.common.IxUtils.execute('RF_sol_common_service_GetConfigHierarchy', {
     *       compose: "/pubsec/Configuration/pubsec.Config",
     *       content: true  //optional, if not set, or none `true` value, only GUIDs will be returned
     *       forceReload: true  // optional, if true, the cache will be refreshed
     *     });
     *
     * Returns the hierarchy of the configuration as followed:
     *
     *     {
     *       defaultConfig: {
     *         guid: "(3A348D43-2C82-CA21-4812-1A10AB368125)",
     *         content: { ... } // opional, only returned, if content parameter was `true`
     *       },
     *       customConfigs: [
     *         { guid: "(BA8C4F65-7DFA-5F02-23C1-3680A4E8A94E)", content: { ... } },
     *         ...
     *       ]
     *     }
     *
     * @author NM, ELO Digital Office GmbH
     * @version 1.05.000
     *
     * @eloix
     * @requires  sol.common.Config
     * @requires  sol.common.RepoUtils
     * @requires  sol.common.ix.ServiceBase
     */
    sol.define("sol.common.ix.services.GetConfig", {
      extend: "sol.common.ix.ServiceBase",

      /**
       * @cfg {String} objId (optional) The object id of the configuration (also guid and arcpath allowed). The config will be loaded plain.
       */

      /**
       * @cfg {String} compose (optional) A relative path inside the 'Business Solutions' (or its 'Custom') folders or even an objId. The config will be loaded composed.
       */

      /**
       * @since 1.05.000
       * @cfg {String[]} paths (optional) an array of relative paths inside the 'Business Solutions' (or its 'Custom') folders or even an objId. The configs will be loaded composed.
       */

      /**
       * @cfg {Boolean} [hierarchical=false] (optional) If `true` the result will contain all GUIDs of configurations which would be part of the merging. Only works with {@link #compose}.
       */

      /**
       * @cfg {Boolean} [content=false] (optional) If `true` the hierarchical result will contain the configs themself. Only works with {@link #compose} and {@link #hierarchical}.
       */

      /**
       * @cfg {Boolean} [forceReload=false] (optional) If `true` cache will be refreshed.
       */

      /**
       * @cfg {Boolean} [exceptionOnBrokenConfig=false] (optional)
       * If `true` there will be an exception, if one of the merged configs has errors.
       * The function {@link #RF_sol_common_service_GetMergedConfig} overrides the default value always with `true`, except the call specifies the parameter as `false`.
       */

      initialize: function (config) {
        var me = this;
        if (!config.objId && !config.compose && !config.paths) {
          throw "InitializationException: either 'objId', 'compose' or 'paths' has to be defined";
        }
        me.$super("sol.common.ix.ServiceBase", "initialize", [config]);
      },

      /**
       * Downloads the given file content as string
       * @return {Object}
       */
      process: function () {
        var me = this,
            mode, result;

        mode = me.determineMode();

        switch (mode) {
          case "SIMPLE":
            result = me.getSimpleConfig();
            break;
          case "MERGED":
            result = me.getMergedConfig();
            break;
          case "HIERARCHICAL":
            result = me.getExplodedConfig(me.compose);
            break;
          case "MULTI_HIERARCHICAL":
            result = me.getMultipleExplodedConfigs();
            break;
          default:
            throw "IllegalStateException: can not determine result mode";
        }

        return result;
      },

      /**
       * @private
       * Determines in which mode the class is executed ("SIMPLE"|"MERGED"|"HIERARCHICAL").
       * @return {String}
       */
      determineMode: function () {
        var me = this;
        if (me.objId) {
          return "SIMPLE";
        }
        if (me.compose && (me.hierarchical === true)) {
          return "HIERARCHICAL";
        }
        if (me.paths && (me.hierarchical === true)) {
          return "MULTI_HIERARCHICAL";
        }
        if (me.compose) {
          return "MERGED";
        }
      },

      /**
       * @private
       * Retrieves a simple configuration from an objId
       * @return {Object}
       */
      getSimpleConfig: function () {
        var me = this,
            config;

        config = sol.create("sol.common.Config", { load: me.objId, forceReload: me.forceReload }).config;
        return { config: config };
      },

      /**
       * @private
       * Retrieves a merged configuration from an objId or a path
       * @return {Object}
       */
      getMergedConfig: function () {
        var me = this,
            config;
        config = sol.create("sol.common.Config", { compose: me.compose, forceReload: me.forceReload, exceptionOnBrokenConfig: me.exceptionOnBrokenConfig }).config;
        return { config: config };
      },

      /**
       * @private
       * Retrieves multiple simple configuration from an objId.
       * @return {Object}
       */
      getMultipleExplodedConfigs: function () {
        var me = this,
            result = {};

        me.paths.forEach(function (path) {
          if (path) {
            result[path] = me.getExplodedConfig(path);
          }
        });

        return result;
      },

      /**
       * @private
       * Retrieves a simple configuration from an objId
       * @param {String} compose
       * @return {Object}
       */
      getExplodedConfig: function (compose) {
        var me = this,
            result = {},
            cfg, hierarchyObjs;

        cfg = sol.create("sol.common.Config", { compose: compose });

        if (cfg.validForMergeing()) { // config is in merge hierarchy
          hierarchyObjs = cfg.retrieveMergeHierarchy(true);

          result.defaultConfig = hierarchyObjs.shift();
          if (me.content === true && result.defaultConfig && result.defaultConfig.guid) {
            result.defaultConfig.content = sol.create("sol.common.Config", { load: result.defaultConfig.guid, forceReload: me.forceReload }).config;
          }

        } else { // config is not in merge hierarchy
          hierarchyObjs = [{ guid: compose }];
        }

        if (hierarchyObjs.length > 0) {
          result.customConfigs = [];
          hierarchyObjs.forEach(function (customObj) {
            if (me.content === true && customObj && customObj.guid) {
              customObj.content = sol.create("sol.common.Config", { load: customObj.guid, forceReload: me.forceReload }).config;
            }
            result.customConfigs.push(customObj);
          });
        }

        return result;
      }

    });

    /**
     * @member sol.common.ix.services.GetConfig
     * @method RF_sol_common_service_GetConfig
     * @static
     * @inheritdoc sol.common.ix.ServiceBase#RF_ServiceBaseName
     */
    function RF_sol_common_service_GetConfig(ec, args) {
      var params, service, result;
      logger.enter("RF_sol_common_service_GetConfig", args);

      params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args, "objId");
      service = sol.create("sol.common.ix.services.GetConfig", params);
      result = service.process();
      logger.exit("RF_sol_common_service_GetConfig", result);
      return sol.common.JsonUtils.stringifyAll(result);
    }

    /**
     * @member sol.common.ix.services.GetConfig
     * @method RF_sol_common_service_GetMergedConfig
     * @static
     * @inheritdoc sol.common.ix.ServiceBase#RF_ServiceBaseName
     */
    function RF_sol_common_service_GetMergedConfig(ec, args) {
      var params, service, result;
      logger.enter("RF_sol_common_service_GetMergedConfig", args);

      if (!args) {
        throw "Args are empty";
      }

      params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args, "compose");
      params.exceptionOnBrokenConfig = (params.exceptionOnBrokenConfig === false) ? false : true;
      service = sol.create("sol.common.ix.services.GetConfig", params);
      result = service.process();
      logger.exit("RF_sol_common_service_GetMergedConfig", result);
      return sol.common.JsonUtils.stringifyAll(result);
    }

    /**
     * @member sol.common.ix.services.GetConfig
     * @method RF_sol_common_service_GetConfigHierarchy
     * @static
     * @inheritdoc sol.common.ix.ServiceBase#RF_ServiceBaseName
     */
    function RF_sol_common_service_GetConfigHierarchy(ec, args) {
      var params, service, result;
      logger.enter("RF_sol_common_service_GetConfigHierarchy", args);

      params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args, "compose");
      params.hierarchical = true;
      service = sol.create("sol.common.ix.services.GetConfig", params);
      result = service.process();
      logger.exit("RF_sol_common_service_GetConfigHierarchy", result);
      return sol.common.JsonUtils.stringifyAll(result);
    }

    /**
     * @member sol.common.ix.services.GetConfig
     * @method RF_sol_common_service_GetConfigHierarchies
     * @since 1.05.000
     * @static
     * @inheritdoc sol.common.ix.ServiceBase#RF_ServiceBaseName
     */
    function RF_sol_common_service_GetConfigHierarchies(ec, args) {
      var params, service, result;
      logger.enter("RF_sol_common_service_GetConfigHierarchies", args);

      params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args, "paths");
      params.hierarchical = true;
      service = sol.create("sol.common.ix.services.GetConfig", params);
      result = service.process();
      logger.exit("RF_sol_common_service_GetConfigHierarchies", result);
      return sol.common.JsonUtils.stringifyAll(result);
    }