//@include lib_Class.js

/**
 * Helper function for dynamic keyword lists
 *
 * @author MW, ELO Digital Office GmbH
 * @version 1.0
 *
 * @eloix
 * @requires sol.common.ObjectUtils
 * @requires sol.common.SordUtils
 */
sol.define("sol.common.ix.DynKwlUtils", {
  singleton: true,

  /**
   * Fills the object keys of an ELO object by a dynamic keyword list
   * @param {de.elo.ix.client.Sord} sord ELO object
   * @param {String} focusedFieldName Field name of the queried field
   * @param {Object} params (optional)
   * @param {Boolean} [params.ignoreMissingFields=false] (optional) If `true` missing fields on the mask will be ignored (therefore no exception will be thrown)
   * @return {Boolean} True if the sord has been changed
   */
  fillSord: function (sord, focusedFieldName, params) {
    var sordChanged = false,
        keywordsDynamicInfo = new KeywordsDynamicInfo(),
        keywordsDynamicResult, keyIterator, valueIterator, key, value;
    keywordsDynamicInfo.sord = sord;
    keywordsDynamicInfo.maskLineFocus = sol.common.SordUtils.getDocMaskLine(sord.maskName, focusedFieldName);
    keywordsDynamicResult = ixConnect.ix().checkoutKeywordsDynamic(keywordsDynamicInfo);
    if (keywordsDynamicResult.table.size() != 1) {
      return;
    }
    keyIterator = keywordsDynamicResult.keyNames.iterator();
    valueIterator = keywordsDynamicResult.table.iterator().next().iterator();
    while (keyIterator.hasNext()) {
      key = keyIterator.next();
      value = valueIterator.next();
      if (key && (key.indexOf("$") !== 0)) {
        try {
          sol.common.SordUtils.setObjKeyValue(sord, key, value);
          sordChanged = true;
        } catch (ex) {
          if (!params || !params.ignoreMissingFields) {
            throw ex;
          }
        }

      }
    }
    return sordChanged;
  },

  /**
   * Fills the map fields and object keys of an ELO object by a dynamic keyword list
   * @param {Object} map Input data
   * @param {de.elo.ix.client.Sord} sord ELO object
   * @param {String} focusedFieldName Field name of the queried field
   * @param {String} scriptName Name of the dynamic keyword list script
   * @param {Object} params Parameters
   * @param {Boolean} [params.append=false] Append lines
   */
  fillMap: function (map, sord, focusedFieldName, scriptName, params) {
    var me = this,
        mapKeys = [],
        keywordsDynamicInfo, keywordsDynamicResult, keyValues, linesIterator, keyIterator, valueIterator, key, i, value,
        sordMap, sordMapTable, filterValue,
        mapKeysWithoutIndex = [];

    keywordsDynamicInfo = new KeywordsDynamicInfo();

    params = params || {};
    map = map || {};

    if (sord) {
      sol.common.ObjectUtils.forEach(sord.objKeys, function (objKey) {
        map[objKey.name] = (objKey.data && (objKey.data.length > 0)) ? objKey.data[0] : "";
      }, this);
    }

    keywordsDynamicInfo.mapData = map;
    keywordsDynamicInfo.mapLineFocus = focusedFieldName;
    keywordsDynamicInfo.mapScriptName = scriptName;
    keywordsDynamicResult = ixConnect.ix().checkoutKeywordsDynamic(keywordsDynamicInfo);
    keyValues = [];

    filterValue = map[focusedFieldName];

    if (!filterValue && (keywordsDynamicResult.table.size() > 1)) {
      me.logger.info("Filter value is empty and there are multiple result lines. Fields won't be filled. scriptName=" + scriptName + ", focusedFieldName=" + focusedFieldName);
      return;
    }

    keyIterator = keywordsDynamicResult.keyNames.iterator();
    while (keyIterator.hasNext()) {
      key = keyIterator.next() + "";
      if ((key.indexOf("IX_MAP_") == 0) && (key.indexOf("{i}") < 0)) {
        mapKeysWithoutIndex.push(key);
      }
    }

    if ((mapKeysWithoutIndex.length > 0) && (keywordsDynamicResult.table.size() > 1)) {
      me.logger.info("Result with multiple lines, but destination map keys without index. Fields won't be filled. scriptName=" + scriptName + ", mapKeysWithoutIndex=" + mapKeysWithoutIndex);
      return;
    }

    linesIterator = keywordsDynamicResult.table.iterator();

    if (params.append) {
      keyIterator = keywordsDynamicResult.keyNames.iterator();
      while (keyIterator.hasNext()) {
        key = keyIterator.next() + "";
        if ((key.indexOf("IX_MAP_") == 0) || (key.indexOf("IX_GRP_") == 0)) {
          key = key.substring(7);
        }
        key = key.replace("{i}", "");
        mapKeys.push(key);
      }
      sordMap = sol.create("sol.common.SordMap", { objId: sord.id });
      sordMapTable = sol.create("sol.common.MapTable", { map: sordMap, columnNames: mapKeys });
      i = sordMapTable.getLength();
    } else {
      i = 0;
    }

    while (linesIterator.hasNext()) {
      i++;
      keyIterator = keywordsDynamicResult.keyNames.iterator();
      valueIterator = linesIterator.next().iterator();
      while (keyIterator.hasNext()) {
        key = keyIterator.next();
        value = valueIterator.next();
        if (key.startsWith("IX_MAP_")) {
          key = key.substring(7);
          key = key.replace("{i}", String(i));
          keyValues.push(new KeyValue(key, value));
        } else {
          if (key.startsWith("IX_GRP_")) {
            key = key.substring(7);
          }
          sol.common.SordUtils.setObjKeyValue(sord, key, value);
        }
      }
    }
    if (keyValues.length > 0) {
      ixConnect.ix().checkinMap(MapDomainC.DOMAIN_SORD, sord.id, sord.id, keyValues, LockC.NO);
    }
  }
});


/**
 * Helper functions for the dynamic keywordlist iterators.
 *
 * @author PZ, ELO Digital Office GmbH
 * @version 1.03.000
 *
 * @eloix
 *
 */
sol.define("sol.common.ix.DynKwlMixin", {
  mixin: true,

  initialize: function (config) {
    var me = this;
    me.tableKeyNames_default = config.tableKeyNames_default || me.tableKeyNames_default;
    me.tableKeyNames_configOverride = config.tableKeyNames_configOverride || me.tableKeyNames_configOverride;

    me.formatting = config.formatting || me.formatting;
  },

  /**
   * @protected
   * Determines the table keys for the output of the dynamic kwl.
   * @param {String} focusFieldName
   * @return {String[]}
   */
  getTableKeyNames: function (focusFieldName) {
    var me = this,
        tableKeyNames;

    if (typeof me.tableKeyNames === "function") {
      me.log.debug(["Determine table key names by function. FucusFieldName='{0}', DefaultConfig='{1}' OverrideConfig='{2}'", focusFieldName, JSON.stringify(me.tableKeyNames_default), JSON.stringify(me.tableKeyNames_configOverride)]);
      tableKeyNames = me.tableKeyNames.call(me, focusFieldName, (me.tableKeyNames_default || "No default configuration"), (me.tableKeyNames_configOverride || {}));
    } else {
      tableKeyNames = me.tableKeyNames;
    }

    if (!tableKeyNames) {
      me.log.warn(["Can not determine 'tableKeyNames' in class '{0}'", me.$className]);
    }

    me.log.debug(["tableKeyNames='{0}'", JSON.stringify(tableKeyNames)]);
    return tableKeyNames;
  },

  /**
   * @protected
   * Uses `this.formatting` to apply formatting to a table row.
   *
   * # Format decimal
   * See also {@link sol.common.Locale#formatDecimal}.
   *
   *     formatting = [
   *       { columnNames: ["MY_OUTPUT_COLUMN1"], minimumFractionDigits: 0, maximumFractionDigits: 2 },
   *       { columnNames: ["MY_OUTPUT_COLUMN2", "ANOTHER_OUTPUT_COLUMN"], maximumFractionDigits: 4 }
   *     ];
   *
   * @param {String[]} row
   */
  formatRow: function (row) {
    var me = this,
        i, def, iteratorArray, containsIdx, j, columnIndex, value, formatedValue;

    if (me.formatting && (typeof me.tableKeyNames === "function")) {
      throw "Formating can not be used when 'tableKeyNames' is a function";
    }

    if (me.formatting && (me.formatting.length > 0)) {
      for (i = 0; i < me.formatting.length; i++) {
        def = me.formatting[i];

        iteratorArray = def.columnNames || def.columnIndexes || [];
        containsIdx = !!def.columnIndexes;

        for (j = 0; j < iteratorArray.length; j++) {
          columnIndex = (containsIdx) ? iteratorArray[j] : me.tableKeyNames.indexOf(iteratorArray[j]);
          if (columnIndex > -1) {
            value = String(row[columnIndex]);

            switch (def.type) {
              case "NUMBER":
                formatedValue = me.formatNumber(value, def);
                break;
              default:
                throw "Unsupported format type";
            }
            row[columnIndex] = formatedValue;
          }
        }
      }
    }
  },

  /**
   * @private
   * Formats decimal numbers using {@link sol.common.Locale#formatDecimal}.
   * @param {String} value
   * @param {Object} params
   * @return {String}
   */
  formatNumber: function (value, params) {
    var me = this;

    if (!value || value == "null") {
      value == "";
    } else {
      if (!me.$locale) {
        me.$locale = sol.create("sol.common.Locale", { ec: me.ec });
        me.$locale.read();
      }
      value = me.$locale.formatDecimal(value, params);
    }
    return value;
  }

});