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

//@include lib_Class.js
//@include lib_sol.common.AclUtils.js
//@include lib_sol.common.UserUtils.js
//@include lib_sol.common.WfUtils.js
//@include lib_sol.common.ix.FunctionBase.js

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

/**
 * Decides, which direction the workflow should be dispatched, regarding the configured requirements.
 *
 * Can be used as node exit script. It updates the ELO_WF_STATUS field as configured. The status can be used in a decision node.
 *
 * # As workflow node
 *
 * Following configuration can be applied to the comments field.
 *
 *     {
 *       "wfStatus": { "onSuccess": "IS_IN_GROUP", "onFailure": "NOT_IN_GROUP" },
 *       "requirements": [
 *         { "type": "inGroup", "value": "sol.pubsec.admin.Record" }
 *       ]
 *     }
 *
 * @author PZ, ELO Digital Office GmbH
 * @version 1.03.000
 *
 * @eloix
 * @requires  sol.common.UserUtils
 * @requires  sol.common.WfUtils
 * @requires  sol.common.ix.FunctionBase
 *
 */
sol.define("sol.common.ix.functions.UserDispatcher", {
  extend: "sol.common.ix.FunctionBase",

  requiredConfig: ["wfDiagram", "userId", "objId"],

  /**
   * @cfg {de.elo.ix.client.WFDiagram} wfDiagram (required)
   * The workflow which should be checked.
   */

  /**
   * @cfg {String} userId (required)
   * The ID of the user, who should be checked.
   */

  /**
   * @cfg {String} objId (required)
   * ID of the element which should be checked
   */

  /**
   * @cfg {Object} wfStatus
   *
   *     "wfStatus": { "onSuccess": "left", "onFailure": "right" }
   *
   * This object can override the default workflow states which will be set after the check, if ths was used in a workflow node.
   * If the is `undefined`, the function will throw an exception in case the checke fails.
   *
   * - `onSuccess`: set as ELO_WF_STATUS after a successfull check
   * - `onFailure`: set as ELO_WF_STATUS after a check failure
   */

  /**
   * @cfg {Object[]} requirements
   * This is an array with configurations which requirements a user has to fullfill. If empty, the check always succeeds.
   *
   *     "requirements": [
   *        { "type": "inGroup", "value": "sol.pubsec.admin.Record" },
   *        { "type": "inGroup", "value": "sol.pubsec.sysadmin.Record" },
   *        { "type": "hasEffectiveRights", "rights": { "rights": { "d": "true" } } }
   *     ]
   *
   * With this configuration the check would only succeed, if the user is in both groups ('sol.pubsec.admin.Record' and 'sol.pubsec.sysadmin.Record').
   * The value can also be the group ID.
   */

  /**
   * @cfg {Object} nextNodes
   *
   *     "nextNodes": { "onSuccess": ["OK", "Approve"], "onFailure": ["Cancel", "Reject"] }
   *
   *     or
   *
   *     "nextNodes": { "onSuccess": "OK", "onFailure": "Cancel" }
   *
   * This object determines the next nodes to activate in dependence of the workflow status.
   *
   * - `onSuccess`: array of next nodes or string of one next node to activate after a successfull check
   * - `onFailure`: array of next nodes or string of one next node to activate after a check failure
   */

  /**
   * @private
   * @property {String} [DEFAULT_PASSED_STATUS="SUCCESS"] Default workflow status in case of a successful check
   */
  DEFAULT_PASSED_STATUS: "SUCCESS",

  /**
   * @private
   * @property {String} [DEFAULT_FAILED_STATUS="FAILURE"] Default workflow status in case of a check failure
   */
  DEFAULT_FAILED_STATUS: "FAILURE",

  initialize: function (config) {
    var me = this;
    me.$super("sol.common.ix.FunctionBase", "initialize", [config]);
  },

  /**
   * Performs the check.
   */
  process: function () {
    var me = this,
        status, nextNodes, i, node, succNodes;

    if (me.checkRequirements()) {
      status = (me.wfStatus && me.wfStatus.onSuccess) ? me.wfStatus.onSuccess : me.DEFAULT_PASSED_STATUS;
      nextNodes = (me.nextNodes && me.nextNodes.onSuccess) ? me.nextNodes.onSuccess : undefined;
    } else {
      status = (me.wfStatus && me.wfStatus.onFailure) ? me.wfStatus.onFailure : me.DEFAULT_FAILED_STATUS;
      nextNodes = (me.nextNodes && me.nextNodes.onFailure) ? me.nextNodes.onFailure : undefined;
    }

    sol.common.WfUtils.setWorkflowStatus(me.wfDiagram, status);
    if (nextNodes) {
      if (sol.common.ObjectUtils.isString(nextNodes)) {
        nextNodes = [nextNodes];
      } else if (!sol.common.ObjectUtils.isArray(nextNodes)) {
        throw "nextNodes has incorrect datatype";
      }
      succNodes = sol.common.WfUtils.getSuccessorNodes(me.wfDiagram, me.nodeId);
      for (i = 0; i < succNodes.length; i++) {
        node = succNodes[i];
        if (nextNodes.indexOf(String(node.name)) < 0) {
          node.allowActivate = false;
        } else {
          node.isNext = 1;
        }
      }
    }
  },

  /**
   * @private
   * Checks, if the configured requirements are meet.
   * @return {Boolean}
   */
  checkRequirements: function () {
    var me = this,
        checkResult = false;

    if (me.requirements && (me.requirements.length > 0)) {
      checkResult = me.requirements.every(function (requirement) {
        return me.checkRequirement(requirement);
      });
    } else {
      checkResult = true;
    }
    return checkResult;
  },

  /**
   * @private
   * Checks an inividual requirement.
   * @param {Object} requirement
   * @return {Boolean}
   */
  checkRequirement: function (requirement) {
    var me = this;
    switch (requirement.type) {
      case "inGroup":
        return sol.common.UserUtils.isInGroup(requirement.value, { userId: me.userId });
      case "hasEffectiveRights":
        return sol.common.AclUtils.hasEffectiveRights(me.objId, { rights: requirement.rights });
      default:
        return false;
    }
  }

});


/**
 * @member sol.common.ix.functions.UserDispatcher
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#onExitNode
 */
function onExitNode(clInfo, userId, wFDiagram, nodeId) {
  var params, module;

  logger.enter("onExitNode_UserDispatcher", { flowId: wFDiagram.id, nodeId: nodeId });

  params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId);
  params.wfDiagram = wFDiagram;
  params.userId = userId;
  params.objId = wFDiagram.objId;
  params.nodeId = nodeId;

  module = sol.create("sol.common.ix.functions.UserDispatcher", params);
  module.process();

  logger.exit("onExitNode_UserDispatcher");
}