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

//@include lib_Class.js
//@include lib_sol.common.IxUtils.js
//@include lib_sol.common.Template.js
//@include lib_sol.common.Injection.js
//@include lib_sol.common.UserUtils.js
//@include lib_sol.common.JsonUtils.js
//@include lib_sol.common.SordUtils.js
//@include lib_sol.common.ObjectUtils.js
//@include lib_sol.common.ix.FunctionBase.js
//@include lib_sol.common.ObjectFormatter.MapTableToArray.js

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

/**
 * Creates a new ELO group and fills it with members by default.
 * Returns an object with the name of the group and the groupId.
 *
 * ### Output
 *  {
 *    "name": "groupname",
 *    "groupId": "4711"
 *  }
 *
 * If no predefined groupId is passed, one is automatically generated by ELO
 *
 *
 * It is possible to add some members to the created group directly
 * {@link sol.common.ix.functions.ChangeGroup}
 *
 *  {
 *     addMembers: [
 *       "renz",
 *       { "type": "GRP", "key": "ELOINDEX" },
 *       { "type", "MAP", "key": "USERNAME", table: true }
 *      ]
 *    }
 *
 * In addition when you want to add the created group is memberOf another group you can declare
 * the following configuration
 *
 *    {
 *      memberOf: [sol.common.roles.StandardUsers]
 *    }
 * This is really handy when you want to give some default rights to the new created groups.
 * For example the new created group should be have the role `StandardUsers`
 *
 * If the group already exists, no further operations will be performed with this
 * groups. Only if the group is newly created.
 *
 * ### saveToField
 *
 * Finally save the newly created group in a field so that it can be easily retrieved later
 *
 *   {
 *      saveGroupToField: { type: "GRP", key: "ELOINDEX" }
 *   }
 *
 * Internal is {@link sol.common.ix.function.Set} used, so the config is delegate to the
 * set function {@see sol.common.ix.function.Set#entries}.
 *
 *
 * # As workflow node
 *
 * ObjId is set based on the element that the workflow is attached to.
 * Following additional configuration can be applied to the comments field.
 *
 *     {
 *      "groupName": "New Group",
 *      "groupId": "new group id"
 *     }
 *
 * # As IX function call
 *
 * In addition to the workflow node configuration the objId must be passed.
 *
 *     sol.common.IxUtils.execute("RF_sol_function_CreateGroup", {
 *       objId: "4712",
 *       name: "New Group"
 *       memberOf: [ "sol.common.roles.StandardUsers" ],
 *       addMembers: ["renz", "kraft"]
 *     });
 *
 * @eloix
 * @requires sol.common.IxUtils
 * @requires sol.common.WfUtils
 * @requires sol.common.Template
 * @requires sol.common.Injection
 * @requires sol.common.ix.RfUtils
 * @requires sol.common.ix.JsonUtils
 * @requires sol.common.ix.ObjectUtils
 * @requires sol.common.ix.FunctionBase
 * @requires sol.common.ObjectFormatter.MapTableToArray
 *
 */
sol.define("sol.common.ix.functions.CreateGroup", {
  extend: "sol.common.ix.FunctionBase",

  /**
   * @cfg {String} groupName
   * The name of the new group. Templating is possible if objId/flowId is passed to the function
   */

  /**
   * @cfg {String|number} groupId (optional)
   * If `groupId` is set the passed id will be used by creation otherwise the id will generate randomily
   */

  /**
   * @cfg {Array<String>} memberOf (optional)
   * Assign the nwe created group to each group which contains `memberOf`
   */

  /**
   * @cfg {Array} addUsers (optional)
   * Add each user to the new created group. usernames could be added directly or from sord fields
   */

  /**
   * @cfg {Boolean} [asAdmin=false] (optional)
   * When `asAdmin` is set to true the operation will be execute with an admin connection
   */

  mixins: ["sol.common.mixins.Inject"],

  inject: {
    name: { prop: "groupName", template: true },
    sord: { sordIdFromProp: "objId", flowIdFromProp: "flowId", optional: false }
  },

  /**
   * @cfg {String} name
   */

  /**
   * @param {String | Array<String>} memberOf
   */

   initialize: function (config) {
    var me = this;

    if (config.memberOf && !sol.common.ObjectUtils.isArray(config.memberOf)) {
      config.memberOf = [config.memberOf];
    }

    if (config.addMembers && !sol.common.ObjectUtils.isArray(config.addMembers)) {
      config.addMembers = [config.addMembers];
    }

    me.$super("sol.common.ix.FunctionBase", "initialize", [config]);
    me.connection = ((me.asAdmin === true) && (typeof ixConnectAdmin !== "undefined")) ? ixConnectAdmin : ixConnect;
  },

  /**
   *
   */
  process: function () {
    var me = this, createdGroupId, saveGroupToField;

    try {
      createdGroupId = me.createGroup(me.name, me.prepareGroupConfig());

      if (!createdGroupId) {
        me.logger.warn(["Group {0} already exists. Skip creation...", me.name]);
      }

      if (me.memberOf) {
        // add created group to specific group (for example roles `sol.meeting.roles.Organizer`)
        me.addMemberToGroup([me.name], me.memberOf);
      }

      if (me.addMembers) {
        sol.common.IxUtils.execute("RF_sol_function_ChangeGroup", {
          objId: me.objId,
          flowId: me.flowId,
          groupName: me.name,
          addMembers: me.addMembers,
          asAdmin: me.asAdmin || false
        });
      }

      if (me.shouldSaveGroupToField(createdGroupId)) {
        saveGroupToField = {
          type: me.saveGroupToField.type,
          key: me.saveGroupToField.key,
          value: me.name
        };

        sol.common.IxUtils.execute("RF_sol_function_Set", {
          objId: me.objId,
          entries: [saveGroupToField]
        });
      }

    } catch (ex) {
      me.logger.warn(["An error occured {0}", ex.message], ex);
      throw ex;
    }

    return {
      name: me.name,
      groupId: createdGroupId
    };
  },

  shouldSaveGroupToField: function (createdGroupId) {
    var me = this;
    me.logger.info(["should save objId={0}, createdGroupId={1}, {2}", me.objId, createdGroupId])
    return me.objId && createdGroupId && me.saveGroupToField;
  },

  createGroup: function (name, groupConfig) {
    var me = this, groupId;
    try {
      // Attention: groupConfig is not serializable
      groupId = String(sol.common.UserUtils.createUser(name, groupConfig));
    } catch (ex) {
      me.logger.error(["could not create group {0}", name], ex);
      throw ex;
    }

    // api function here is a little bit weird we can create groups here as well
    me.logger.info(["created elo group {0} groupId= {1}", name, groupId]);
    return groupId;
  },

  addMemberToGroup: function (names, targetGroups) {
    var me = this;
    me.logger.debug(["addUsersToGroups {0} {1}", names, targetGroups]);
    sol.common.UserUtils.addUsersToGroups(names, targetGroups, {
      connection: me.connection
    });
  },

  prepareGroupConfig: function () {
    var me = this, config = {
      type: "group",
      connection: me.connection
    };

    // set fix elo group id
    me.groupId && (config.id = me.groupId);
    return config;
  }
});




/**
 * @member sol.common.ix.functions.CreateGroup
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#onEnterNode
 */
function onEnterNode(clInfo, userId, wFDiagram, nodeId) {
  logger.enter("onEnterNode_CreateGroup", { flowId: wFDiagram.id, nodeId: nodeId });
  var params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId),
      module;

  sol.common.WfUtils.checkMainAdminWf(wFDiagram);

  params.objId = String(wFDiagram.objId);
  params.flowId = String(wFDiagram.id);
  module = sol.create("sol.common.ix.functions.CreateGroup", params);

  module.process();

  logger.exit("onEnterNode_CreateGroup");
}


/**
 * @member sol.common.ix.functions.CreateGroup
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#onExitNode
 */
function onExitNode(clInfo, userId, wFDiagram, nodeId) {
  logger.enter("onExitNode_CreateGroup", { flowId: wFDiagram.id, nodeId: nodeId });
  var params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId),
      module;

  sol.common.WfUtils.checkMainAdminWf(wFDiagram);

  params.objId = wFDiagram.objId;
  params.flowId = String(wFDiagram.id);
  module = sol.create("sol.common.ix.functions.CreateGroup", params);

  module.process();

  logger.exit("onExitNode_CreateGroup");
}


/**
 * @member sol.common.ix.functions.CreateGroup
 * @method RF_sol_function_CreateGroup
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#RF_FunctionName
 */
function RF_sol_function_CreateGroup(ec, args) {
  logger.enter("RF_sol_function_CreateGroup", args);
  var module, result, params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args);

  sol.common.ix.RfUtils.checkMainAdminRights(ec.user, params);
  module = sol.create("sol.common.ix.functions.CreateGroup", params);

  result = module.process();
  logger.exit("RF_sol_function_CreateGroup");
  return sol.common.JsonUtils.stringifyQuick(result);
}