//@include lib_Class.js
//@include lib_handlebars.js
//@include lib_sol.common.ObjectUtils.js
//@include lib_sol.common.Cache.js
//@include lib_sol.common.UserUtils.js
//@include lib_sol.common.Config.js
//@include lib_sol.common.Template.js
//@include lib_sol.common.JsonUtils.js
//@include lib_sol.common.RepoUtils.js
//@include lib_sol.common.SordUtils.js
//@include lib_sol.common.WfUtils.js
//@include lib_sol.common.FileUtils.js
//@include lib_sol.common.ExecUtils.js
//@include lib_sol.common.AsyncUtils.js
//@include lib_sol.common.SordTypeUtils.js
//@include lib_sol.common.ZipUtils.js

importPackage(java.io);

/**
 * Build packages
 *
 * @author ELO Digital Office GmbH
 *
 * @elojc
 *
 * @requires sol.common.RepoUtils
 * @requires sol.common.SordUtils
 * @requires sol.common.WfUtils
 */
sol.define("sol.dev.BuildPackages", {

  /**
   * @cfg {Array} objIds
   * Object IDs of the package folders
   */

  /**
   * @cfg {String} exportDirPath
   * Export directory path
   */

  /**
   * @cfg {Boolean} debug
   * Debug package
   */

  packageMask: "ELO Business Solution",


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

    me.logger = sol.create("sol.Logger", { scope: "sol.dev.BuildPackages" });
  },

  execute: function () {
    var me = this,
        objId, i, packageBuilder;

    if (!me.objIds || (me.objIds.length == 0)) {
      me.logger.info("Object IDs are empty");
      return;
    }

    me.params = me.params || {};

    me.exportDirPath = sol.create("sol.common.Template", { source: me.exportDirPath }).apply();

    sol.common.FileUtils.makeDirectories(new File(me.exportDirPath));
    if (me.cleanExportDir) {
      sol.common.FileUtils.deleteFiles({ dirPath: me.exportDirPath, suffix: ".eloinst" });
    }

    for (i = 0; i < me.objIds.length; i++) {
      objId = me.objIds[i];
      packageBuilder = sol.create("sol.dev.BuildPackage", {
        objId: objId,
        transport: me.transport,
        exportDirPath: me.exportDirPath
      });
      packageBuilder.execute();
    }
  }
});

/**
 * Build package
 *
 * @author Michael Weiler, ELO Digital Office GmbH
 * @version 1.0
 *
 * @elojc
 *
 * @requires  sol.sol.common.Json
 * @requires  sol.common.RepoUtils
 * @requires  sol.common.ZipUtils
 */
sol.define("sol.dev.BuildPackage", {

  /**
   * @cfg {String} objId
   * Object ID of the package folders
   */

  /**
   * @cfg {String} exportDirPath
   * Export directory
   */

  /**
   * @cfg {Boolean} debug
   * Debug package
   */

  /**
   * @cfg {Boolean} transport
   * Transport package
   */

  versionNoFieldName: "BS_VERSION_NO",
  buildNoFieldName: "BS_BUILD_NO",
  setupNameSuffixFieldName: "BS_SETUP_NAME_SUFFIX",

  repoDataFileName: "RepoData",

  pilcrow: "\u00b6",

  execute: function () {
    var me = this,
        debugDstFileNamePart = "",
        transportFileNamePart = "",
        sordZ, buildNo, setupNameSuffix, repoDataFile, dstFile, debugOnFile,
        datePos, installConfigFilePath, installConfig,
        repoDataFilePath, expInfoContent, expInfoIni, i, maskName, systemMasks,
        workflowTemplateNames, workflowTemplateName, workflowJson,
        workflowTemplateNamesWithinJson, j, workflowTemplateNameWithinJson, redundantWorkflowTemplates, redundantWorkflowTemplate, workflowNameIndex,
        deleteObjId, javaMainVersion;

    if (!me.objId) {
      throw "Object ID of the package folder is empty";
    }

    if (!me.exportDirPath) {
      throw "Export directory path is empty";
    }

    sordZ = new SordZ(SordC.mbAll);
    sordZ.add(SordC.mbRefPaths);
    me.packageSord = ixConnect.ix().checkoutSord(me.objId + "", sordZ, LockC.NO);

    me.buildConfig = me.getBuildConfig();

    me.setupFileRepoPaths = [
      "ARCPATH[(E10E1000-E100-E100-E100-E10E10E10E00)]:/Business Solutions/common/All",
      "ARCPATH[(E10E1000-E100-E100-E100-E10E10E10E00)]:/Business Solutions/common/All Rhino",
      "ARCPATH[(E10E1000-E100-E100-E100-E10E10E10E00)]:/Business Solutions/development/All Rhino",
      "ARCPATH[(E10E1000-E100-E100-E100-E10E10E10E00)]:/Business Solutions/development/Package Installer"
    ];

    if (me.buildConfig.exportRepoPath) {
      me.exportRepoPath = me.buildConfig.exportRepoPath;
    } else {
      me.exportRepoPath = sol.common.RepoUtils.getPath(me.packageSord, true);
    }

    if (!me.eloInstRepoPath) {
      me.eloInstRepoPath = sol.common.RepoUtils.getPath(me.packageSord, true) + "/.eloinst";
    }

    if (!me.buildConfig.packageName) {
      me.buildConfig.packageName = String(me.packageSord.name);
    }

    if (me.buildConfig.gitPackagePath) {
      me.gitIxPluginDirPath = me.buildConfig.gitPackagePath + "/install.data/IX Plug-ins";
      me.gitIxPluginDir = new File(me.gitIxPluginDirPath + "");
      me.gitIxPluginDir.mkdirs();
    }

    if (!me.installConfigRepoPath) {
      me.installConfigRepoPath = sol.common.RepoUtils.getPath(me.packageSord, true) + "/.eloinst/install";
    }

    if (!me.buildConfigRepoPath) {
      me.buildConfigRepoPath = sol.common.RepoUtils.getPath(me.packageSord, true) + "/.eloinst/build";
    }

    me.outputDirPath = sol.common.FileUtils.createTempDir({ prefix: "Setup_Package" });
    me.outputDir = new File(me.outputDirPath + "");
    me.outputDir.mkdirs();

    me.zipDirPath = me.outputDirPath + File.separator + me.buildConfig.setupName;
    me.zipDir = new File(me.zipDirPath + "");
    me.zipDir.mkdirs();

    me.manifestFilePath = me.zipDirPath + File.separator + "MANIFEST.MF";
    me.transportConfigFilePath = me.zipDirPath + File.separator + "transport.json";

    me.payloadDirPath = me.zipDirPath + File.separator + "install.data";
    me.payloadDir = new File(me.payloadDirPath + "");
    me.payloadDir.mkdirs();

    me.versionNoStr = (sol.common.SordUtils.getObjKeyValue(me.packageSord, me.versionNoFieldName) + "") || "1";
    if (me.buildConfig.appendTimeStamp) {
      datePos = me.versionNoStr.indexOf("_");
      if (datePos > -1) {
        me.versionNoStr = me.versionNoStr.substring(0, datePos) + "_" + Packages.org.apache.commons.lang.time.DateFormatUtils.format(new java.util.Date(), "yyyyMMddHHmmss");
        sol.common.SordUtils.setObjKeyValue(me.packageSord, me.versionNoFieldName, me.versionNoStr, { silent: true });
      }
    }

    me.versionNoStr = sol.create("sol.common.Template", { source: me.versionNoStr }).apply();

    me.buildNoStr = sol.common.SordUtils.getObjKeyValue(me.packageSord, me.buildNoFieldName);

    me.buildNoStrPaddedLeft = sol.common.StringUtils.padLeft(me.buildNoStr, 3, "0");

    buildNo = me.buildNoStr ? parseInt(me.buildNoStr, 10) + 1 : 1;
    me.buildNoStr = String(buildNo);
    sol.common.SordUtils.setObjKeyValue(me.packageSord, me.buildNoFieldName, me.buildNoStr, { silent: true });
    ixConnect.ix().checkinSord(me.packageSord, sordZ, LockC.NO);

    try {
      setupNameSuffix = sol.common.SordUtils.getObjKeyValue(me.packageSord, me.setupNameSuffixFieldName);
      if (setupNameSuffix) {
        me.buildConfig.setupName = me.buildConfig.setupName + "_" + setupNameSuffix;
      }
    } catch (e) { /* ignore, old mask definition */ }

    me.deleteLogFileSords();

    if (me.buildConfig.deleteSords) {
      for (i = 0; i < me.buildConfig.deleteSords.length; i++) {
        deleteObjId = me.buildConfig.deleteSords[i];
        try {
          sol.common.RepoUtils.deleteSord(deleteObjId, { deleteFinally: true });
        } catch (ex) {
          // ignore
        }
      }
    }

    if (me.buildConfig.createManifestFile) {
      me.createManifestFile();
    }

    me.setupFileRepoPaths.push(me.installConfigRepoPath);
    me.setupFileRepoPaths.push(me.buildConfigRepoPath);

    me.setupFileRepoPaths.forEach(function (setupFileRepoPath) {
      sol.common.FileUtils.downloadDocuments(setupFileRepoPath, me.zipDirPath, { makeDirectories: true });
    });

    if (me.buildConfig.forceMasks) {

      me.buildConfig.forceMasks.forEach(function (forceMaskConfig) {
        me.forceMask(forceMaskConfig);
      });
    }

    me.prepareBranchForInstallExport(me.exportRepoPath);

    repoDataFilePath = me.payloadDirPath + File.separator + me.repoDataFileName + ".zip";
    repoDataFile = new File(repoDataFilePath + "");

    me.exportObjId = sol.common.RepoUtils.getObjId(me.exportRepoPath);

    sol.common.RepoUtils.exportRepoData(repoDataFile, { srcList: [me.exportObjId], exportDocs: true, exportKeywords: true, replaceRefWithOriginal: false });

    javaMainVersion = sol.common.ExecUtils.getJavaMainVersionNumber();

    if (me.buildConfig.deleteBuzzwordFiles) {
      if (javaMainVersion > 8) {
        if (me.buildConfig.keepBuzzwordLists) {
          me.buildConfig.keepBuzzwordLists = me.buildConfig.keepBuzzwordLists.map(function (buzzwordList) {
            return sol.common.StringUtils.endsWith(buzzwordList, ".xml") ? buzzwordList : buzzwordList + ".xml";
          });
        }
        sol.common.ZipUtils.deleteFilesInZipFileFolder(repoDataFilePath, { startFolderPathInZipFile: "/buzzwds", fileNamePattern: "*.xml", keepFileNames: me.buildConfig.keepBuzzwordLists });
      } else {
        me.logger.info(["Building the package runs on Java version <= 8, so deleting the keyword lists is skipped. javaMainVersion={0}", javaMainVersion]);
      }
    }

    me.buildConfig.workflowTemplatesDirPath = me.payloadDirPath + File.separator + "workflowTemplates";
    me.buildConfig.workflowTemplatesDir = new File(me.buildConfig.workflowTemplatesDirPath + "");

    me.buildConfig.ixPluginsDirPath = me.payloadDirPath + File.separator + "IX Plug-ins";
    me.buildConfig.ixPluginsDir = new File(me.buildConfig.ixPluginsDirPath + "");

    me.buildConfig.sordTypesDirPath = me.payloadDirPath + File.separator + "Sord types";

    me.buildConfig.masksDirPath = me.payloadDirPath + File.separator + "Masks";
    me.buildConfig.masksDir = new File(me.buildConfig.masksDirPath + "");

    if (me.debug) {
      debugOnFile = new File(me.zipDirPath + File.separator + "debug.on");
      Packages.org.apache.commons.io.FileUtils.writeStringToFile(debugOnFile, "debug.on", "UTF-8");
      debugDstFileNamePart = "_debug";
    }

    if (me.buildConfig.workflowTemplates) {
      me.buildConfig.workflowTemplatesDir.mkdirs();

      workflowTemplateNames = me.buildConfig.workflowTemplates;

      redundantWorkflowTemplates = [];

      for (i = 0; i < workflowTemplateNames.length; i++) {
        workflowTemplateName = workflowTemplateNames[i];
        workflowJson = sol.common.WfUtils.getWorkflowAsJson(workflowTemplateName);
        workflowTemplateNamesWithinJson = sol.common.WfUtils.getAllWorkflowNamesFromJson(workflowJson);
        for (j = 0; j < workflowTemplateNamesWithinJson.length; j++) {
          workflowTemplateNameWithinJson = workflowTemplateNamesWithinJson[j];
          if (workflowTemplateNameWithinJson != workflowTemplateName) {
            redundantWorkflowTemplates.push(workflowTemplateNameWithinJson);
          }
        }
      }

      for (i = 0; i < redundantWorkflowTemplates.length; i++) {
        redundantWorkflowTemplate = redundantWorkflowTemplates[i];

        workflowNameIndex = workflowTemplateNames.indexOf(redundantWorkflowTemplate);
        if (workflowNameIndex > -1) {
          workflowTemplateNames.splice(workflowNameIndex, 1);
        }
      }

      for (i = 0; i < workflowTemplateNames.length; i++) {
        workflowTemplateName = workflowTemplateNames[i];
        me.processWorkflowTemplateExport(workflowTemplateName);
      }
    }

    if (me.buildConfig.sordTypes) {
      sol.common.SordTypeUtils.exportSordTypes(me.buildConfig.sordTypes, me.buildConfig.sordTypesDirPath);
    }

    if (me.transport) {
      installConfigFilePath = me.zipDirPath + File.separator + "install.json";
      installConfig = sol.common.FileUtils.readFileToObject(installConfigFilePath);
      installConfig.transport = true;
      sol.common.FileUtils.writeObjectToFile(installConfig, installConfigFilePath);

      transportFileNamePart = "_transport";
    }

    systemMasks = [
      "ELOScripts",
      "Basic Entry",
      "Folder"
    ];

    me.buildConfig.masks = me.buildConfig.masks || [];

    expInfoContent = sol.common.ZipUtils.readFileInZipToString(repoDataFilePath, "ExpInfo.ini", { encoding: "UTF-16LE" });

    expInfoIni = sol.create("sol.common.IniFile", {});
    expInfoIni.parse(expInfoContent);

    for (i = 0; i < 100; i++) {
      maskName = expInfoIni.getValue("MASKS", i);
      if (maskName) {
        me.buildConfig.masks.push(maskName);
      } else {
        break;
      }
    }

    systemMasks.forEach(function (mask) {
      var index;
      index = me.buildConfig.masks.indexOf(mask);
      if (index > -1) {
        me.buildConfig.masks.splice(index, 1);
      }
    });

    if (me.buildConfig.masks && (me.buildConfig.masks.length > 0)) {

      sol.common.RepoUtils.setSessionOption(SessionOptionsC.TRANSLATE_TERMS, false);

      me.buildConfig.masksDir.mkdirs();
      me.buildConfig.masks.forEach(function (mask) {
        me.processMaskExport(mask);
      });

      sol.common.RepoUtils.setSessionOption(SessionOptionsC.TRANSLATE_TERMS, true);
    }

    me.downloadIxPlugins();
    me.copyIxPlugins();

    me.zipFile = new File(me.zipDirPath + ".eloinst");
    sol.common.ZipUtils.zipFolder(me.zipDir, me.zipFile);

    dstFile = new File(me.exportDirPath + File.separator + (me.buildConfig.fileNamePrefix ? (me.buildConfig.fileNamePrefix + "_") : "") + me.buildConfig.setupName + "_" + me.versionNoStr + (me.buildConfig.fileNameWithBuildNo ? ("_" + me.buildNoStrPaddedLeft) : "") + transportFileNamePart + debugDstFileNamePart + ".eloinst");

    Packages.org.apache.commons.io.FileUtils.copyFile(me.zipFile, dstFile);

    sol.common.FileUtils.delete(me.outputDirPath, { quietly: true });

    me.logger.info("Package created: " + dstFile.canonicalPath);
  },

  /**
   * @private
   * Loads the build config
   * @param {de.elo.ix.client.Sord} packageSord Package sord
   * @return {Object}
   */
  getBuildConfig: function () {
    var me = this,
        buildConfigRepoPath, buildConfigObjId, configLoader;

    buildConfigRepoPath = sol.common.RepoUtils.getPath(me.packageSord) + "/.eloinst/build";
    buildConfigObjId = sol.common.RepoUtils.getObjId(buildConfigRepoPath);
    if (!buildConfigObjId) {
      throw "Build configuration not found: packageName=" + me.packageSord.name + ", configRepoPath=" + buildConfigRepoPath;
    }
    configLoader = sol.create("sol.common.Config", { load: "ARCPATH:" + buildConfigRepoPath });
    return configLoader.config;
  },

  /**
   * @private
   * Delete log fils
   */
  deleteLogFileSords: function () {
    var me = this,
        logFileNamePart, logFileSords;

    logFileNamePart = "log_install_" + me.buildConfig.packageName + "_";

    logFileSords = sol.common.RepoUtils.findChildren(me.eloInstRepoPath, { name: logFileNamePart, sordZ: SordC.mbMin });
    logFileSords.forEach(function (logFileSord) {
      me.logger.debug("Delete log file Sord: sord.id=" + logFileSord.id + ", sord.name=" + logFileSord.name);
      sol.common.RepoUtils.deleteSord(logFileSord.id);
    });
  },

  /**
   * Create manifest file
   */
  createManifestFile: function () {
    var me = this,
        content = [],
        createdDateString = "",
        createdDate;

    content.push("Setup-Name: " + me.buildConfig.setupName);
    content.push("Setup-Version: " + me.versionNoStr + " build " + me.buildNoStr);

    if (me.buildConfig.buildDateIso) {
      createdDate = Packages.org.apache.commons.lang.time.DateUtils.parseDate(me.buildConfig.buildDateIso, ["yyyyMMdd"]);
      createdDateString = String(Packages.org.apache.commons.lang3.time.DateFormatUtils.format(createdDate, "yyyy-MM-dd'T'HH:mm:ssZZ"));
    } else {
      createdDateString = sol.common.FileUtils.getTimeStampString("yyyy-MM-dd'T'HH:mm:ssZZ");
    }

    content.push("Created-At: " + createdDateString);
    content.push("Built-By: " + ixConnect.loginResult.user.name);
    sol.common.FileUtils.writeStringArrayToFile(me.manifestFilePath, content);
  },

  /**
   * @private
   * Force a specific Mask
   * @param {Object} forceMaskConfig Change mask find definition
   */
  forceMask: function (forceMaskConfig) {
    var me = this,
        sords, i, sord, logRepoPath;

    if (!forceMaskConfig) {
      throw "Force mask configution is empty";
    }

    if (!forceMaskConfig.findChildren) {
      throw "Find children configuation is empty";
    }

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

    if (!forceMaskConfig.mask) {
      throw "Mask is empty";
    }

    forceMaskConfig.findChildren.sordZ = SordC.mbAll;

    sords = sol.common.RepoUtils.findChildren(forceMaskConfig.findChildren.objId, forceMaskConfig.findChildren.params);

    for (i = 0; i < sords.length; i++) {
      sord = sords[i];
      if (sord.maskName != forceMaskConfig.mask) {
        sord = ixConnect.ix().changeSordMask(sord, forceMaskConfig.mask, EditInfoC.mbSord).sord;
        logRepoPath = sol.common.StringUtils.replaceAll(sord.refPaths[0].pathAsString + "", me.pilcrow, "/") + "/" + sord.name;

        me.logger.debug("Change sord mask: " + logRepoPath + " -> mask=" + sord.maskName);
        ixConnect.ix().checkinSord(sord, SordC.mbAll, LockC.NO);
      }
    }
  },

  /**
   * @private
   * Prepares a branch for installation export
   * @param {String} startId
   */
  prepareBranchForInstallExport: function (startId) {
    var me = this,
        sordZ, sords, startSord;
    me.logger.enter("prepareBranchForInstallExport", startId);

    if (!startId) {
      throw "Start ID is empty";
    }

    sordZ = new SordZ(ObjDataC.mbOwnerId);
    sordZ.add(ObjDataC.mbName);
    sordZ.add(SordC.mbAclItems);
    sordZ.add(ObjDataC.mbLockId);

    startSord = sol.common.RepoUtils.getSord(startId, { sordZ: sordZ });
    me.prepareSordForInstallExport(startSord);

    sords = sol.common.RepoUtils.findChildren(startId, { sordZ: sordZ, recursive: true, level: 32 });
    sords.forEach(function (sord) {
      me.prepareSordForInstallExport(sord);
    });
    me.logger.exit("prepareBranchForInstallExport");
  },

  /**
   * @private
   * Prepares a sord for installation export
   * @param {de.elo.ix.client.Sord} sord Sord
   * @param {Object} config Configuration
   */
  prepareSordForInstallExport: function (sord, config) {
    var me = this,
        newAclItems = [],
        aclChanged = false,
        writeSord = false,
        i, aclItem, sordZ, aclItemId, aclItemName, sordOwnerId, sordOwnerName;

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

    me.ownerId = me.ownerId || 0;
    me.buildConfig.preserveAclUserIds = me.buildConfig.preserveAclUserIds || ["0", "1", "9999"];
    me.buildConfig.preserveAclUserNames = me.buildConfig.preserveAclUserNames || [];

    if ((sord.lockId > -1) && (me.buildConfig.checkLocks) && !me.debug) {
      throw "Sord is locked: sord.id=" + sord.id + ", sord.name=" + sord.name + ", sord.lockName=" + sord.lockName;
    }

    if (sol.common.SordUtils.isFolder(sord) && (sord.mask == 0)) {
      sord = sol.common.SordUtils.changeMask(sord, "1");
    }

    sordOwnerId = sord.ownerId + "";
    sordOwnerName = sord.ownerName + "";

    if (sordOwnerId != me.ownerId) {
      if ((me.buildConfig.preserveAclUserIds.indexOf(sordOwnerId) < 0) && (me.buildConfig.preserveAclUserNames.indexOf(sordOwnerName) < 0)) {
        sord.ownerId = me.ownerId;
        writeSord = true;
      }
    }

    for (i = 0; i < sord.aclItems.length; i++) {
      aclItem = sord.aclItems[i];
      aclItemId = aclItem.id + "";
      aclItemName = aclItem.name + "";
      if ((me.buildConfig.preserveAclUserIds.indexOf(aclItemId) > -1) || (me.buildConfig.preserveAclUserNames.indexOf(aclItemName) > -1)) {
        newAclItems.push(aclItem);
      } else {
        aclChanged = true;
      }
    }

    if (aclChanged) {
      sord.aclItems = newAclItems;
      writeSord = true;
    }

    if (writeSord) {
      try {
        sordZ = new SordZ(ObjDataC.mbOwnerId);
        sordZ.add(SordC.mbAclItems);

        ixConnect.ix().checkinSord(sord, sordZ, LockC.NO);
      } catch (ex) {
        throw "Can't prepare sord for installation export: sord.id=" + sord.id + ", sord.name=" + sord.name + ", exception=" + ex;
      }
    }
  },

  /**
   * @private
   * Processes the export of a workflow template
   * @param {String} workflowTemplateName Name of the worklflow name
   */
  processWorkflowTemplateExport: function (workflowTemplateName) {
    var me = this,
        workflowTemplateFile, workflowTemplateFileName;

    workflowTemplateFileName = sol.common.FileUtils.sanitizeFilename(workflowTemplateName);

    workflowTemplateFile = new File(me.buildConfig.workflowTemplatesDirPath + File.separator + workflowTemplateFileName + ".json");

    sol.common.WfUtils.exportWorkflowTemplate(workflowTemplateName, workflowTemplateFile, { clearUsers: true, addSubTemplateInfo: true });
  },

  defaultMaskGuids: [
    "(E10E1000-E100-E100-E100-E10E10E10E30)",
    "(E10E1000-E100-E100-E100-E10E10E10E31)"
  ],

  /**
   * @private
   * Processes the export of a mask
   * @param {String} maskName Name of the worklflow name
   */
  processMaskExport: function (maskName) {
    var me = this,
        mask, maskGuid, json, fileName, maskFilePath, line, i, maskObj;

    maskName += "";

    mask = ixConnect.ix().checkoutDocMask(maskName, DocMaskC.mbAll, LockC.NO);

    if (!mask) {
      throw "Mask '" + maskName + "' not found";
    }

    maskGuid = mask.guid + "";
    if (me.defaultMaskGuids.indexOf(maskGuid) > -1) {
      return;
    }

    fileName = sol.common.FileUtils.sanitizeFilename(maskName + "");

    maskFilePath = new File(me.buildConfig.masksDirPath + File.separator + fileName + ".json");

    mask.acl = "";
    mask.DAcl = "";
    me.clearIds(mask.aclItems);
    me.clearIds(mask.docAclItems);
    for (i = 0; i < mask.lines.length; i++) {
      line = mask.lines[i];
      line.acl = "";
      me.clearIds(line.aclItems);
    }

    json = sol.common.JsonUtils.serialize(mask);

    maskObj = JSON.parse(json);

    me.adjustMask(maskObj);

    json = JSON.stringify(maskObj, null, 2);

    sol.common.FileUtils.writeStringToFile(maskFilePath, json);
  },

  adjustMask: function (maskObj) {
    var me = this,
        childMaskNames = [],
        i, line, mask, maskId;

    maskObj.id = -1;
    maskObj.TStamp = "2018.01.01.00.00.00";

    me.adjustAcl(maskObj.aclItems);

    for (i = 0; i < maskObj.lines.length; i++) {
      line = maskObj.lines[i];
      line.maskId = -1;
      me.adjustAcl(line.aclItems);
    }

    if (maskObj.maskIdsForChildEntries) {

      for (i = 0; i < maskObj.maskIdsForChildEntries.length; i++) {
        maskId = maskObj.maskIdsForChildEntries[i] + "";
        mask = ixConnect.ix().checkoutDocMask(maskId, DocMaskC.mbAll, LockC.NO);
        childMaskNames.push(mask.name + "");
      }

      maskObj.maskIdsForChildEntries = childMaskNames;
    }
  },

  adjustAcl: function (aclItems) {
    var me = this,
        i, aclItem, aclName;

    me.adminName = me.adminName || (me.getUserName(UserInfoC.ID_ADMINISTRATOR) + "");
    me.everyoneName = me.everyoneName || (me.getUserName(UserInfoC.ID_EVERYONE_GROUP) + "");

    for (i = 0; i < aclItems.length; i++) {
      aclItem = aclItems[i];
      aclName = aclItem.name;

      switch (aclName) {
        case (me.adminName):
          aclItem.id = 0;
          aclItem.name = "";
          break;

        case (me.everyoneName):
          aclItem.id = 9999;
          aclItem.name = "";
          break;

        default:
          break;
      }
    }
  },

  getUserName: function (id) {
    var userNames, name;

    userNames = ixConnect.ix().getUserNames([id + ""], CheckoutUsersC.BY_IDS_RAW);
    name = userNames[0].name;

    return name;
  },

  /**
   * @private
   * Copy IX plug-ins
   */
  copyIxPlugins: function () {
    var me = this,
        i, ixPluginDirPath, ixPluginDir, ixPluginDirExists, jarCollection, jarIterator, jarFile;

    if (me.buildConfig.ixPluginDirs) {
      me.buildConfig.ixPluginsDir.mkdirs();

      for (i = 0; i < me.buildConfig.ixPluginDirs.length; i++) {
        ixPluginDirPath = me.buildConfig.ixPluginDirs[i];
        ixPluginDir = new java.io.File(ixPluginDirPath);

        if (!ixPluginDir.exists()) {
          continue;
        }
        jarCollection = Packages.org.apache.commons.io.FileUtils.listFiles(ixPluginDir,
          new Packages.org.apache.commons.io.filefilter.SuffixFileFilter(["jar"], Packages.org.apache.commons.io.IOCase.INSENSITIVE),
          Packages.org.apache.commons.io.filefilter.FalseFileFilter.INSTANCE);

        jarIterator = jarCollection.iterator();
        while (jarIterator.hasNext()) {
          jarFile = jarIterator.next();
          Packages.org.apache.commons.io.FileUtils.copyFileToDirectory(jarFile, me.buildConfig.ixPluginsDir);
          if (me.gitIxPluginDir) {
			log.info("Copy IX plugin to Git directory: file=" + jarFile.absolutePath + ", gitIxPluginDir=" + me.gitIxPluginDir.absolutePath);
            Packages.org.apache.commons.io.FileUtils.copyFileToDirectory(jarFile, me.gitIxPluginDir);
          }
        }
      }
    }
  },

  /**
   * @private
   * Downloads IX plug-ins
   */
  downloadIxPlugins: function () {
    var me = this,
        pluginName, i;

    if (me.buildConfig.ixPlugins) {
      for (i = 0; i < me.buildConfig.ixPlugins.length; i++) {
        pluginName = me.buildConfig.ixPlugins[i];
        me.downloadIxPlugin(pluginName);
      }
    }
  },

  /**
   * @private
   * Download an IX plug-in
   * @param {String} pluginName
   */
  downloadIxPlugin: function (pluginName) {
    var me = this,
        jsonArgs, args, anyResult, fileData, targetFilePath;

    if (!pluginName) {
      throw "Plug-in name is empty";
    }

    jsonArgs = { name: pluginName };

    args = new Any;
    args.type = AnyC.TYPE_STRING;
    args.stringValue = JSON.stringify(jsonArgs);

    anyResult = ixConnect.ix().executeRegisteredFunction("RF_sol_dev_service_DownloadIxPlugin", args);

    fileData = AnyToObject.toObject(anyResult);

    me.buildConfig.ixPluginsDir.mkdirs();
    targetFilePath = me.buildConfig.ixPluginsDirPath + java.io.File.separator + pluginName;

    sol.common.FileUtils.saveFileData(fileData, targetFilePath);
  },

  /**
   * @private
   * Clears the `id` property of an array
   * @param {Array} arr Array
   */
  clearIds: function (arr) {
    var i, element;

    for (i = 0; i < arr.length; i++) {
      element = arr[i];
      element.id = -1;
    }
  }
});