//@include lib_Class.js

/**
 * Helper functions for dynamic ad-hoc workflows
 *
 * @author MW, ELO Digital Office GmbH
 * @version 1.1
 *
 * @eloix
 *
 * @requires sol.common.UserUtils
 * @requires sol.common.WfMap
 * @requires sol.common.MapTable
 */
sol.define("sol.common.ix.DynAdHocFlowUtils", {
  singleton: true,

  /**
   * @private
   */
  logger: sol.create("sol.Logger", { scope: "sol.common.ix.DynAdHocFlowUtils" }),

  /**
   * Creates a new routing
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Array} userEntries User entries
   * @param {Object} config Configuration
   * @param {String} config.userNameKey User name key
   * @param {String} config.userIdKey User ID key
   * @param {String} config.append Append users
   */
  createDynAdHocFlow: function (flowId, objId, userEntries, config) {
    var me = this,
        wfMapTable, userEntry, userNames, i, userName;

    if (!flowId) {
      throw "Flow ID is empty";
    }

    if (!objId) {
      throw "Object ID is empty";
    }

    if (!userEntries) {
      throw "User entries are empty";
    }

    config = config || {};
    config.reset = false;

    config = me.buildConfig(config);
    wfMapTable = me.loadTable(flowId, objId, !config.append, config);

    for (i = 0; i < userEntries.length; i++) {
      userEntry = userEntries[i];

      if (!userEntry.name) {
        continue;
      }

      try {
        userNames = ixConnect.ix().getUserNames([userEntry.name], CheckoutUsersC.BY_IDS_RAW);
      } catch (ex) {
        userNames = undefined;
      }

      if (!userNames || (userNames.length == 0)) {
        throw "User '" + userEntry.name + "' doesn't exist.";
      }

      userName = userNames[0];

      wfMapTable.appendRow();
      wfMapTable.setValue(config.userNameKey, userName.name);
      wfMapTable.setValue(config.userIdKey, userName.id);
      wfMapTable.setValue(config.mandatoryKey, userEntry.mandatory ? "1" : "0");
    }

    wfMapTable.write();
  },

  /**
   * Loads the routing table
   * @private
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Boolean} initEmpty
   * @param {Object} config Configuration
   * @param {Object} config.reset Reset iterator
   * @return {sol.common.MapTable}
   */
  loadTable: function (flowId, objId, initEmpty, config) {
    var wfMap, wfMapTable;

    if (!flowId) {
      throw "Flow ID is emtpy";
    }
    if (!objId) {
      throw "Object ID is empty";
    }
    if (!config) {
      throw "Configuration is empty";
    }

    config = config || {};
    config.reset = (config.reset == false) ? false : true;

    wfMap = sol.create("sol.common.WfMap", { flowId: flowId, objId: objId });

    wfMapTable = sol.create("sol.common.MapTable", { map: wfMap, reset: config.reset, columnNames: [config.userNameKey, config.userIdKey, config.mandatoryKey], initEmpty: initEmpty });

    return wfMapTable;
  },

  /**
   * @private
   * Builds the DynAdHocFlow configuration
   * @param {Object} config Configuration
   * @return {Object} Complete configuration
   */
  buildConfig: function (config) {
    config = config || {};
    config.userNameKey = config.userNameKey || "USER";
    config.userIdKey = config.userNameKey + "_ID";
    config.mandatoryKey = config.userNameKey + "_MANDATORY";
    config.currentUserKey = config.currentUserKey || "CURRENT_USER";
    config.previousUserKey = config.previousUserKey || "PREVIOUS_USER";
    config.append = (config.append == true) ? true : false;
    return config;
  },

  /**
   * Returns the first user and removes the first row of the user table
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Object} config Configuration
   * @param {String} config.currentUserKey
   * @return {String} userName User name
   */
  shiftUser: function (flowId, objId, config) {
    var me = this,
        userName = "",
        wfMapTable, currentUser;

    if (!flowId) {
      throw "Flow ID is empty";
    }

    if (!objId) {
      throw "Object ID is empty";
    }

    config = me.buildConfig(config);

    wfMapTable = me.loadTable(flowId, objId, false, config);
    wfMapTable.map.read();

    currentUser = wfMapTable.map.getValue(config.currentUserKey);
    if (currentUser) {
      wfMapTable.map.setValue(config.currentUserKey, "");
      wfMapTable.map.write();
      return currentUser;
    }

    if (wfMapTable.hasNextRow()) {
      wfMapTable.nextRow();
      userName = wfMapTable.getValue(config.userNameKey);
      wfMapTable.shift();
    }
    wfMapTable.write();

    wfMapTable.map.setValue(config.currentUserKey, userName);
    wfMapTable.map.write();

    return userName;
  },

  /**
   * Checks whether there is a next user in the table
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Object} config Configuration
   * @param {String} config.userNameKey
   * @return {Boolean}
   */
  hasNextUser: function (flowId, objId, config) {
    var me = this,
        wfMapTable, userName;

    config = me.buildConfig(config);

    wfMapTable = me.loadTable(flowId, objId, false, config);
    if (wfMapTable.hasNextRow()) {
      wfMapTable.nextRow();
      userName = wfMapTable.getValue(config.userNameKey);
      if (userName) {
        return true;
      }
    }
    return false;
  },

  /**
   * Checks whether a current user is set
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Object} config Configuration
   * @param {String} config.currentUserKey
   * @return {Boolean}
   */
  hasCurrentUser: function (flowId, objId, config) {
    var me = this,
        wfMap, currentUser, hasCurrentUser;

    config = me.buildConfig(config);

    wfMap = sol.create("sol.common.WfMap", { flowId: flowId, objId: objId });
    wfMap.read();
    currentUser = wfMap.getValue(config.currentUserKey);
    hasCurrentUser = !!currentUser;

    return hasCurrentUser;
  },

  /**
   * Clears the current user
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Object} config Configuration
   * @param {String} config.currentUserKey
   */
  clearCurrentUser: function (flowId, objId, config) {
    var me = this,
        wfMap, previousUserName;

    config = me.buildConfig(config);

    wfMap = sol.create("sol.common.WfMap", { flowId: flowId, objId: objId });
    wfMap.read();
    previousUserName = wfMap.getValue(config.currentUserKey);
    wfMap.setValue(config.previousUserKey, previousUserName);
    wfMap.setValue(config.currentUserKey, "");
    wfMap.write();
  },

  /**
   * Sets the current user
   * @param {String} objId Object ID
   * @param {String} flowId Flow ID
   * @param {String} userName User name
   * @param {Object} config Configuration
   * @param {String} config.currentUserKey
   */
  setCurrentUser: function (objId, flowId, userName, config) {
    var me = this,
        wfMap;

    if (!flowId) {
      throw "Flow ID is empty";
    }

    if (!objId) {
      throw "Object ID is empty";
    }

    if (!userName) {
      throw "Username is empty";
    }

    config = me.buildConfig(config);

    wfMap = sol.create("sol.common.WfMap", { flowId: flowId, objId: objId });
    wfMap.setValue(config.currentUserKey, userName);
    wfMap.write();
  },

  /**
   * Back to previous user
   * @param {String} flowId Flow ID
   * @param {String} objId Object ID
   * @param {Object} config Configuration
   * @param {String} config.userNameKey User name key
   * @param {String} config.currentUserKey Current user key
   * @param {String} config.previousUserKey Previous user key
   */
  backToPreviousUser: function (flowId, objId, config) {
    var me = this,
        wfMapTable, currentUserName, previousUserName;

    config = me.buildConfig(config);

    wfMapTable = me.loadTable(flowId, objId, false, config);
    wfMapTable.map.read();

    previousUserName = wfMapTable.map.getValue(config.previousUserKey);
    if (previousUserName) {
      wfMapTable.insertRow();
      wfMapTable.nextRow();
      wfMapTable.setValue(config.userNameKey, previousUserName);
    }

    currentUserName = wfMapTable.map.getValue(config.currentUserKey);
    wfMapTable.insertRow();
    wfMapTable.nextRow();
    wfMapTable.setValue(config.userNameKey, currentUserName);
    wfMapTable.write();
  }
});