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

//@include lib_Class.js

/**
 * Shifts dates
 *
 * @author MW, ELO Digital Office GmbH
 * @version 1.03.000
 *
 * @elojc
 * @eloas
 * @eloix
 * @requires moment
 * @requires sol.common.DateUtils
 * @requires sol.common.SordUtils
 * @requires sol.common.RepoUtils
 */
sol.define("sol.dev.DateShiftUtils", {
  singleton: true,

  /**
   * Shift Dates
   * @param {Object} params Parameters
   * @returns {Object} Result
   */
  shiftDates: function (params) {
    var me = this,
        result, refDate, now, unit,
        sords, i, sord, sordResult;

    if (!params) {
      throw "Parameters are emtpy";
    }

    if (!params.parentId) {
      throw "Parent ID is empty";
    }

    result = {
      sords: []
    };

    sords = sol.common.RepoUtils.findChildren(params.parentId, {
      maskId: params.mask,
      level: -1,
      recursive: true,
      includeReferences: true
    });

    refDate = sol.common.DateUtils.isoToDate(params.refDateIso);
    now = new Date();

    params.units = {
      y: {},
      Q: {},
      M: {},
      w: {},
      d: {}
    };

    for (unit in params.units) {
      params.units[unit].number = Math.floor(sol.common.DateUtils.diff(refDate, now, unit));
    }

    result.params = params;

    for (i = 0; i < sords.length; i++) {
      sord = sords[i];
      sordResult = me.shiftSordDates(sord, params);
      result.sords.push(sordResult);
    }

    return result;
  },

  /**
   * @private
   * Shift sord dates
   * @param {de.elo.ix.client.Sord} sord Sord
   * @param {Object} params Parameters
   */

  shiftSordDates: function (sord, params) {
    var me = this,
        newMapKeyValues = [],
        sordChanged = false,
        result, i, j, shift, key, oldMapKeyValues,
        oldValue, newValue, newKeyValue, sordIdInt;

    if (!sord) {
      throw "Sord is empty";
    }

    if (!params) {
      throw "Parameters are empty";
    }

    if (!params.refDateIso) {
      throw "Reference date is empty";
    }

    result = {
      id: sord.id + "",
      name: sord.name + "",
      shifts: []
    };

    for (i = 0; i < params.shifts.length; i++) {
      shift = params.shifts[i];
      if (!shift.key) {
        throw "Shift key is empty";
      }

      shift.unit = shift.unit || "d";

      if (!params.units[shift.unit]) {
        throw "Unkown shift unit '" + shift.unit + "'";
      }
      switch (shift.type) {
        case "SORD":
          oldValue = sol.common.SordUtils.getValue(sord, shift) + "";
          if (me.isIsoDate(oldValue)) {
            newValue = me.shift(oldValue, params, shift);
            sol.common.SordUtils.updateSord(sord, [{ type: shift.type, key: shift.key, value: newValue }]);
            sordChanged = true;
            result.shifts.push({ type: shift.type, key: shift.key, oldValue: oldValue, withTime: shift.withTime, unit: shift.unit, endOfUnit: shift.endOfUnit, newValue: newValue });
          }
          break;

        case "GRP":
          oldValue = sol.common.SordUtils.getObjKeyValue(sord, shift.key) + "";
          if (me.isIsoDate(oldValue)) {
            newValue = me.shift(oldValue, params, shift);
            sol.common.SordUtils.setObjKeyValue(sord, shift.key, newValue);
            sordChanged = true;
            result.shifts.push({ type: shift.type, key: shift.key, oldValue: oldValue, withTime: shift.withTime, unit: shift.unit, endOfUnit: shift.endOfUnit, newValue: newValue });
          }
          break;

        case "MAP":

          oldMapKeyValues = oldMapKeyValues || ixConnect.ix().checkoutMap(MapDomainC.DOMAIN_SORD, sord.id + "", null, LockC.NO).items;

          if (shift.key.indexOf("{i}") > -1) {
            j = 1;
            while (true) {
              key = shift.key.replace("{i}", j);
              oldValue = me.getMapValue(oldMapKeyValues, key);
              if (me.isIsoDate(oldValue)) {
                newValue = me.shift(oldValue, params, shift);
                newKeyValue = new KeyValue(key, newValue);
                newMapKeyValues.push(newKeyValue);
                result.mapKeys = result.mapKeys || {};
                result.shifts.push({ type: shift.type, key: key, oldValue: oldValue, withTime: shift.withTime, unit: shift.unit, endOfUnit: shift.endOfUnit, newValue: newValue });
                j++;
              } else {
                break;
              }
            }
          } else {
            oldValue = me.getMapValue(oldMapKeyValues, shift.key);
            if (me.isIsoDate(oldValue)) {
              newValue = me.shift(oldValue, params, shift);
              newKeyValue = new KeyValue(shift.key, newValue);
              newMapKeyValues.push(newKeyValue);
              result.mapKeys = result.mapKeys || {};
              result.shifts.push({ type: shift.type, key: shift.key, oldValue: oldValue, withTime: shift.withTime, unit: shift.unit, endOfUnit: shift.endOfUnit, newValue: newValue });
            }
          }
          break;

        default:
          throw "Shift field type '" + shift.type + "' is unsupported";
      }
    }

    if (sordChanged) {
      ixConnect.ix().checkinSord(sord, SordC.mbAllIndex, LockC.NO);
    }

    if (newMapKeyValues.length > 0) {
      sordIdInt = java.lang.Integer.valueOf(sord.id + "");
      ixConnect.ix().checkinMap(MapDomainC.DOMAIN_SORD, sord.id + "", sordIdInt, newMapKeyValues, LockC.NO);
    }

    return result;
  },

  /**
   * @private
   * Returns a map key value
   * @param {de.elo.ix.client.KeyValue[]} keyValues Map key values
   * @param {String} keyName Key name
   * @return {String} Value
   */
  getMapValue: function (keyValues, keyName) {
    var i, keyValue, value;

    if (!keyValues) {
      throw "Key values are empty";
    }

    if (!keyName) {
      throw "Key name is empty";
    }

    for (i = 0; i < keyValues.length; i++) {
      keyValue = keyValues[i];
      if (keyValue.key == keyName) {
        value = keyValue.value + "";
        return value;
      }
    }

    return "";
  },

  /**
   * @private
   * Calculates the new date
   * @param {String} oldDateIso Old date ISO
   * @param {Object} params Parameters
   * @param {Object} shift Shift parameters
   * @return {String} New ISO date
   */
  shift: function (oldDateIso, params, shift) {
    var oldDate, newDate, newDateIso, momentDate, number;

    if (!params) {
      throw "Parameters are empty";
    }

    if (!shift) {
      throw "Shift parameters are empty";

    }

    shift.unit = shift.unit || "d";

    oldDate = sol.common.DateUtils.isoToDate(oldDateIso);
    number = params.units[shift.unit].number;
    newDate = sol.common.DateUtils.shift(oldDate, number, { unit: shift.unit });

    if (shift.endOfUnit) {
      momentDate = moment(newDate.getTime());
      newDate = momentDate.endOf(shift.endOfUnit).toDate();
    }

    newDateIso = sol.common.DateUtils.dateToIso(newDate, { withoutTime: !shift.withTime });

    if ((oldDateIso.length > 8) && (newDateIso.length == 8)) {
      newDateIso += "000000";
    }

    return newDateIso;
  },

  isIsoDate: function (isoDate) {
    var result;

    if (!isoDate) {
      return false;
    }
    result = /^2\d{7,13}$/.test(isoDate);
    return result;
  }
});