//@include lib_Class.js

// Nashorn
if (typeof Java != "undefined") {
  Object.defineProperty(this, "global", {
    configurable: true, enumerable: false, writable: true,
    value: this
  });
}

/**
 * Utility methods for the ELOas.
 *
 * @author PZ, ELO Digital Office GmbH
 * @version 1.0
 *
 * @eloas
 */
sol.define("sol.common.as.Utils", {
  singleton: true,

  /**
   * Checks if the current execution is in an users context and throws an exception if that is not the case.
   *
   * If an EM_USERID is set, `ixConnect` will be initialized for this user, while the original connection will be availabe via `ixConnectAdmin`.
   *
   * @param {Object} scope The ruleset object
   */
  requiresUserSession: function (scope) {
    var me = this,
        param3Obj, logTicket, ticketUserId;

    try {
      param3Obj = JSON.parse(EM_PARAM3 || "{}");
    } catch (ex) {
      // ignore
    }

    param3Obj = param3Obj || {};

    if (param3Obj.ticket) {
      logTicket = param3Obj.ticket.substr(0, 10) + "...";

      if (ixConnect.loginResult.clientInfo.ticket == param3Obj.ticket) {
        me.logger.debug(["User ticket corresponds to ELOas service ticket: ticket={0}", logTicket]);
        return;
      }

      ticketUserId = sol.common.UserUtils.getUserIdFromTicket(param3Obj.ticket);
      me.logger.debug(["Set current user from user ticket: ticket={0}, userId={1}", logTicket, ticketUserId]);

      EM_USERID = ticketUserId;
    }

    if (EM_USERID === -1) {
      throw "user ticket required";
    }
    if (typeof Java != "undefined") {
      global.ixConnectAdmin = ixConnect; // Nashorn
    } else {
      scope.__parent__.ixConnectAdmin = ixConnect; // Rhino
    }

    try {
      me.ensureRelogin(ixConnectAdmin);
      ixConnect = ixConnectAdmin.createConnectionForUser(EM_USERID);
    } catch (ex) {
      ixConnectAdmin = undefined;
      me.logger.error(["Error creating connection for user '{0}'", EM_USERID], ex);
      throw "Executing ELOas rules in the current users context is not supported by this AM version. 'CreateConnectionForUser' does not support local ELO accounts if LDAP is used for authentification.";
    }

    if (param3Obj.language) {
      ixConnect.loginResult.clientInfo.language = param3Obj.language;
    }

    if (param3Obj.timeZone) {
      ixConnect.loginResult.clientInfo.timeZone = param3Obj.timeZone;
    } else {
      me.logger.warn("The given time zone should not be empty.");
    }

    me.logger.info(["User session: user.id={0}, user.name={1}, language={2}, timeZone={3}, callId={4}]", ixConnect.loginResult.user.id + "", ixConnect.loginResult.user.name + "", ixConnect.loginResult.clientInfo.language + "", ixConnect.loginResult.clientInfo.timeZone + "", ixConnect.loginResult.clientInfo.callId + ""]);
  },

  /**
   * @private
   * Ensure a re-login if necessary
   * @param {de.elo.ix.client.IXConnection} [conn=ixConnect] Connection
   */
  ensureRelogin: function (conn) {
    conn = conn || ixConnect;
    conn.ix().createSord("0", "", EditInfoC.mbOnlyId);
  },

  /**
   * Changed connection settings (see {@link #requiresUserSession}) will be reseted and the user connection will be closed.
   */
  cleanupUserSession: function () {
    if (typeof ixConnectAdmin !== "undefined") {
      if (ixConnect !== ixConnectAdmin) { // do only reset if 'ixConnect' was created by 'requiresUserSession'
        ixConnect.close();
        ixConnect = ixConnectAdmin;
      }
      ixConnectAdmin = undefined; // always reset ixConnectAdmin variable
    }
  },

  /**
   * Executes an function
   * @param {String} funcName Function name
   * @param {Object} config Configuration
   * @param {Object} config.params Parameters
   * @param {Object} [config.adminOnly=false] If true then the function can only be called by an user with administrative rights
   * @param {Boolean} config.rawResult Returns the raw result
   */
  executeFunction: function (funcName, config) {
    var me = this,
        func, result;

    if (!funcName) {
      throw "Function name is empty";
    }

    config = config || {};

    me.logger = sol.create("sol.Logger", { scope: "sol.common.as.Utils" });

    if (!config.params) {

      if (!EM_PARAM2) {
        me.logger.info("EM_PARAM2 is empty.");
        return;
      }

      try {
        config.params = JSON.parse(EM_PARAM2);
      } catch (ex) {
        me.logger.info("Can't parse configuration: EM_PARAM2=" + EM_PARAM2);
        return;
      }
    }

    me.logger.enter(funcName, config.params);

    try {
      me.checkAdminOnly(funcName, config);

      me.logger.info("executeFunction(): timeZone=" + ixConnect.loginResult.clientInfo.timeZone + ", callId=" + ixConnect.loginResult.clientInfo.callId);

      func = sol.create(funcName, config.params);
      result = func.process();
    } catch (ex) {
      sol.common.ExceptionUtils.logAsException(ex, { logger: me.logger });
      result = { exception: sol.common.ExceptionUtils.parseException(ex) };
    }

    me.logger.exit(funcName, result);

    if (!result) {
      me.logger.info("Function '" + funcName + "' must provide a result");
    }

    if (config.rawResult) {
      result = new java.lang.String(result);
    } else {
      result = JSON.stringify(result);
    }
    me.logger.info("result=" + result);
    ruleset.statusMessage = result;
  },

  /**
   * Checks wether the function is called by an administrative user
   * @param {String} funcName Function name
   * @param {Object} config Configuration
   */
  checkAdminOnly: function (funcName, config) {
    var me = this,
        isAdmin = false,
        param3Obj, ticket, logTicket;

    config = config || {};

    if (config.adminOnly) {
      if (EM_PARAM3) {
        try {
          param3Obj = JSON.parse(EM_PARAM3);
        } catch (ignore) {
        }
      }

      if (param3Obj && param3Obj.ticket) {
        ticket = param3Obj.ticket + "";
        logTicket = ticket.substr(0, 10) + "...";
        param3Obj.ticket = logTicket;
        isAdmin = sol.common.UserUtils.isMainAdminTicket(ticket);
        me.logger.debug(["checkAdminOnly: ticket={0}, result={1}", logTicket, isAdmin]);

        if (!isAdmin) {
          throw "The ELOas function '" + funcName + "' can only be called with administrative rights. ticket=" + logTicket;
        }
      } else {
        if (EM_USERID > -1) {
          isAdmin = sol.common.UserUtils.isMainAdmin(EM_USERID);
        }
        me.logger.debug(["checkAdminOnly: userId={0}, result={1}", EM_USERID, isAdmin]);

        if (!isAdmin) {
          throw "The ELOas function '" + funcName + "' can only be called with administrative rights. userId=" + EM_USERID;
        }
      }
    }
  },

  /**
   * Returns the version of the ELOas
   * @return {String}
   */
  getAsVersion: function () {
    return String(Packages.de.elo.mover.main.ASConstants.VERSION);
  },

  /**
   * Returns true if the code runs within the ELOas debugger
   * @return {Boolean}
   */
  isDebugger: function () {
    return !!Packages.de.elo.mover.main.DebuggerConstants;
  },

  /**
   * Download fonts
   * @param {Object} params Parameters
   * @param {String[]} params.fontFolderRepoPaths Font folder repository path
   * @return {String[]} Font temporary directory paths
   */
  downloadFonts: function (params) {
    var me = this,
        downloadCounter = 0,
        fontFiles, fontFolderObjId, i, fontFolderRepoPath, j, fontFile;

    params = params || {};
    params.fontFolderRepoPaths = params.fontFolderRepoPaths || ["ARCPATH[(E10E1000-E100-E100-E100-E10E10E10E00)]:/ELOas Base/Fonts"];

    me.fontFolderRepoPathDownloaded = me.fontFolderRepoPathDownloaded || [];
    me.fontTempDirPath = me.fontTempDirPath || sol.common.FileUtils.getTempDirPath() + File.separator + "ELOasFonts";


    for (i = 0; i < params.fontFolderRepoPaths.length; i++) {
      fontFolderRepoPath = params.fontFolderRepoPaths[i];

      me.logger.debug("cache={0}, fontFolderRepoPath={1}", me.fontFolderRepoPathDownloaded, fontFolderRepoPath);

      if (me.fontFolderRepoPathDownloaded.indexOf(fontFolderRepoPath) > -1) {
        me.logger.debug(["Fonts already downloaded: fontFolderRepoPath={0}", fontFolderRepoPath]);
        continue;
      }

      fontFolderObjId = sol.common.RepoUtils.getObjId(fontFolderRepoPath);
      if (!fontFolderObjId) {
        me.logger.warn(["Font folder not found: {0}", fontFolderRepoPath]);
        continue;
      }

      me.logger.debug(["Download font files: fontFolderRepoPath={0}", fontFolderRepoPath]);

      fontFiles = sol.common.FileUtils.downloadDocuments(fontFolderObjId, me.fontTempDirPath, { makeDstDirs: true, includeReferences: true });
      for (j = 0; j < fontFiles.length; j++) {
        fontFile = fontFiles[j];
        me.logger.debug(["Font file downloaded: {0}", fontFile.canonicalPath]);
        downloadCounter++;
      }

      me.fontFolderRepoPathDownloaded.push(fontFolderRepoPath);
    }

    me.logger.info(["Downloaded font files available: fontDir={0}, numberOfDownloadedFonts={1}", me.fontTempDirPath, downloadCounter]);

    return me.fontTempDirPath;
  }
});