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

//@include lib_Class.js
//@include lib_sol.common.SordUtils.js
//@include lib_sol.common.UserUtils.js
//@include lib_sol.common.AsyncUtils.js
//@include lib_sol.common.ix.FunctionBase.js

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

/**
 * This module handles the inheritance of index fields from the parent.
 *
 * The configuration, which fields should be inherited is done via {@link #fields}.
 * If inherited fields already have a value, they will not be overridden by default.
 * This behaviour can be altered via an `override` flag in each field configuration.
 * 
 * Without any fields-configuration the ELO standard mechanism for inheritance
 * will be triggered. The objId and it's children will be passed to the mechanism.
 * All fields will be inherited according to their mask field configuration.
 * You can wait until the inheritance is finished with the {@link #waitUntilFinished} parameter.
 *
 * # As workflow node
 *
 * ObjId is set based on the element that the workflow is attached to.
 * Following configuration should be applied to the comments field and would inherit the name of the parent,
 * the field 'MY_INHERITED' and the map field 'MY_INHERITED_MAP' (existing values will not be overridden).
 * Additionally the field MY_INHERITED_2 will be <i>inherited</i> from the field 'MY_OTHER' from the parent
 *
 *     {
 *       "fields": [
 *         { "type": "SORD", "key": "name" },
 *         { "type": "GRP", "key": "MY_INHERITED" },
 *         { "type": "MAP", "key": "MY_INHERITED_MAP" },
 *         { "type": "GRP", "key": "MY_INHERITED_2", "source": { "type": "GRP", "key": "MY_OTHER" } }
 *       ]
 *     }
 *
 * # As IX function call
 *
 * In addition to the workflow node configuration the objId must be passed.
 * The following example would inherit the field 'MY_INHERITED' from the parent and override an exiting value.
 *
 *     sol.common.IxUtils.execute("RF_sol_function_Inherit", {
 *       objId: "4711",
 *       fields: [
 *         { "type": "GRP", "key": "MY_INHERITED", "override": true }
 *       ]
 *     });
 *
 * @author PZ, ELO Digital Office GmbH
 * @version 1.02.003
 *
 * @eloix
 *
 * @requires sol.common.Config
 * @requires sol.common.ConfigMixin
 * @requires sol.common.ObjectUtils
 * @requires sol.common.StringUtils
 * @requires sol.common.JsonUtils
 * @requires sol.common.SordUtils
 * @requires sol.common.RepoUtils
 * @requires sol.common.WfUtils
 * @requires sol.common.AsyncUtils
 * @requires sol.common.ix.RfUtils
 * @requires sol.common.ix.FunctionBase
 */
sol.define("sol.common.ix.functions.Inherit", {
  extend: "sol.common.ix.FunctionBase",

  requiredConfig: ["objId"],

  /**
   * @cfg {String} objId (required)
   * Object ID
   */

  /**
   * @cfg {Object[]} fields
   * Optional parameter. When empty we're using the server-side 
   * inheritKeywording feature to copy all inheritable fields
   * (as configured in the mask fields)
   * 
   * With this parameter you're independent of the mask configuration.
   * You can choose which fields should be inherited by defining them
   * in this parameter. 
   * 
   * Object containing the configuration for the inherited fields:
   *
   *     [
   *       { type: "SORD", key: "name" },
   *       { type: "GRP", key: "MY_FIELD", "override": true }
   *     ]
   *
   * Currently only "SORD" and "GRP" are supported as `type`.
   */

  /**
   * @cfg {Boolean} waitUntilFinished
   * This parameter only works when the fields parameter is empty
   * 
   * When true we're waiting for the inheritance to finish.
   * The inheritKeywording job is async when this parameter is false
   */

  waitUntilFinished: false,

  /**
   * @cfg {Integer} sleepTime
   * Miliseconds to wait between each check of the current
   * inheritance job state
   */
  sleepTime: 200,

  /**
   * @private
   * @property {de.elo.ix.client.Sord} sord
   */

  /**
   * @private
   * @property {de.elo.ix.client.Sord} parentSord
   */

  /**
   * @private
   * @property {Object[]} updates
   */

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

    me.logger.debug("initialize");

    if (me.fields) {
      me.sord = ixConnectAdmin.ix().checkoutSord(me.objId, SordC.mbAllIndex, LockC.FORCE);
      me.parentSord = ixConnectAdmin.ix().checkoutSord(me.sord.parentId, SordC.mbAllIndex, LockC.NO);
      me.updates = [];
    } else {
      me.sleepTime = (sol.common.ObjectUtils.isNumber(config.sleepTime)) ? config.sleepTime : me.sleepTime;
    }
  },

  /**
   * This module handles inheritance of index fields from the parent.
   */
  process: function () {
    var me = this,
        mapitems, jobState;

    if (me.fields) {
      me.fields.forEach(me.inheritField, me);
      me.logger.info("initial inheritance values initialized");

      if (me.updates.length > 0) {
        mapitems = sol.common.SordUtils.updateSord(me.sord, me.updates);
        ixConnectAdmin.ix().checkinSord(me.sord, SordC.mbAllIndex, LockC.YES);
        if (mapitems && (mapitems.length > 0)) {
          ixConnectAdmin.ix().checkinMap(MapDomainC.DOMAIN_SORD, me.objId, me.objId, mapitems, LockC.NO);
        }
      } else {
        ixConnectAdmin.ix().checkinSord(me.sord, SordC.mbOnlyUnlock, LockC.YES);
      }
    } else {
      jobState = me.startInheritKeywordingJob(me.objId);

      if (me.waitUntilFinished) {
        jobState = sol.common.AsyncUtils.waitForJob(jobState.getJobGuid(), { connection: ixConnectAdmin, interval: me.sleepTime });
      }
    }

    me.logger.info("initial inheritance successfull");
  },


  /**
   * @private
   * @param {String} objId Start ID for the processTree
  */
  startInheritKeywordingJob: function (startId) {
    var me = this, navInfo, procInfo;
    
    navInfo = new NavigationInfo();
    navInfo.startIDs = [startId];

    procInfo = new ProcessInfo();
    procInfo.desc = "sol.common.ix.functions.Inherit";
    procInfo.errorMode = ProcessInfoC.ERRORMODE_CRITICAL_ONLY;
    procInfo.procInheritKeywording = new ProcessInheritKeywording();
    
    me.logger.debug(["start copy process: startId={0}", startId]);
    return ixConnectAdmin.ix().processTrees(navInfo, procInfo);
  },

  /**
   * @private
   * @param {Object} cfg Configuration
   */
  inheritField: function (cfg) {
    var me = this,
        parentValue, targetValue, override;
    try {
      parentValue = sol.common.SordUtils.getValue(me.parentSord, (cfg.source) ? cfg.source : cfg);
      targetValue = sol.common.SordUtils.getValue(me.sord, cfg);
      override = (cfg.override === true) ? true : false;
      if (me.checkUpdate(parentValue, targetValue, override)) {
        cfg.value = parentValue;
        me.updates.push(cfg);
      }
    } catch (ex) {
      me.logger.error("error inheriting", ex);
    }
  },

  /**
   * @private
   * @param {String} parentValue Parent value
   * @param {String} targetValue Target value
   * @param {Boolean} override Override value
   * @return {String}
   */
  checkUpdate: function (parentValue, targetValue, override) {
    if (parentValue) {
      parentValue += "";
    }
    if (targetValue) {
      targetValue += "";
    }
    return (!targetValue || override) && (parentValue !== targetValue);
  }

});

/**
 * @member sol.common.ix.functions.Inherit
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#onEnterNode
 */
function onEnterNode(ci, userId, wfDiagram, nodeId) {
  var params, module;
  logger.enter("onEnterNode_Inherit", { flowId: wfDiagram.id, nodeId: nodeId });

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

  params.objId = wfDiagram.objId;

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

  logger.exit("onEnterNode_Inherit");
}

/**
 * @member sol.common.ix.functions.Inherit
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#onExitNode
 */
function onExitNode(ci, userId, wfDiagram, nodeId) {
  var params, module;
  logger.enter("onExitNode_Inherit", { flowId: wfDiagram.id, nodeId: nodeId });

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

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

  logger.exit("onExitNode_Inherit");
}

/**
 * @member sol.common.ix.functions.Inherit
 * @method RF_sol_function_Inherit
 * @static
 * @inheritdoc sol.common.ix.FunctionBase#RF_FunctionName
 */
function RF_sol_function_Inherit(ec, configAny) {
  var params, module;
  logger.enter("RF_sol_function_Inherit", configAny);

  params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, configAny, "objId");

  sol.common.ix.RfUtils.checkMainAdminRights(ec.user, params);

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

  logger.exit("RF_sol_function_Inherit");
}