    /**
     * Converts office documents into other formats like PDF or HTML
     *
     * ## Usage:
     *
     *     var officeConverter = sol.create("sol.common.as.functions.OfficeConverter", {
     *       openFromRepo: {
     *         objId: "3630"
     *       },
     *       saveToRepo: {
     *         format: "pdf",
     *         parentId: "ARCPATH:/Test",
     *         name: "Excel1" }
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     * @requires sol.common.RepoUtils
     * @requires sol.common.XmlUtils
     */
    sol.define("sol.common.as.functions.OfficeConverter", {
      extend: "sol.common.as.FunctionBase",

      /**
       * @private
       * @property {Array} docClassNames
       * Supported extensions and the appropriate class name
       */

      docClassNames: {
        doc: "sol.common.as.WordDocument",
        docx: "sol.common.as.WordDocument",
        rtf: "sol.common.as.WordDocument",
        odt: "sol.common.as.WordDocument",

        xls: "sol.common.as.ExcelDocument",
        xlsx: "sol.common.as.ExcelDocument",
        xlsm: "sol.common.as.ExcelDocument",
        xltx: "sol.common.as.ExcelDocument",
        xltm: "sol.common.as.ExcelDocument",
        csv: "sol.common.as.ExcelDocument",
        ods: "sol.common.as.ExcelDocument",

        ppt: "sol.common.as.PowerPointDocument",
        pot: "sol.common.as.PowerPointDocument",
        pps: "sol.common.as.PowerPointDocument",
        pptx: "sol.common.as.PowerPointDocument",
        potx: "sol.common.as.PowerPointDocument",
        pptm: "sol.common.as.PowerPointDocument",
        odp: "sol.common.as.PowerPointDocument",

        msg: "sol.common.as.MapiMessage",

        vsd: "sol.common.as.VisioDocument",
        vss: "sol.common.as.VisioDocument",
        vst: "sol.common.as.VisioDocument",
        vsx: "sol.common.as.VisioDocument",
        vdw: "sol.common.as.VisioDocument",
        vdx: "sol.common.as.VisioDocument",
        vsdx: "sol.common.as.VisioDocument"
      },

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

      process: function () {
        var me = this,
            extension, sord, docClassName, document, objId;

        if (me.objId) {
          me.openFromRepo = {
            objId: me.objId
          };
        }

        if (!me.objId && !me.openFile && !me.openFromRepo) {
          throw "'objId', openFile' or 'openFromRepo' must be set.";
        }
        extension = "";
        if (me.openFromRepo) {
          if (!me.openFromRepo.objId) {
            throw "'openFromRepo.objId' must be set.";
          }
          sord = ixConnect.ix().checkoutSord(me.openFromRepo.objId, EditInfoC.mbSord, LockC.NO).sord;
          extension = sord.docVersion.ext.toLowerCase();
          me.openFromRepo.extension = extension;
        }

        if (me.openFile) {
          if (me.openFile.filePath) {
            me.openFile.file = new java.io.File(me.openFile.filePath);
          }
          extension = Packages.org.apache.commons.io.FilenameUtils.getExtension(me.openFile.filePath);
        }

        docClassName = me.docClassNames[extension];
        if (!docClassName) {
          me.logger.warn(["Extension '{0}' is unsupported.", extension]);
          return;
        }

        document = sol.create(docClassName);
        if (me.openFromRepo) {
          if (me.language && !me.openFromRepo.language) {
            me.openFromRepo.language = me.language;
          }
          document.openFromRepo(me.openFromRepo);
        } else {
          document.openFile(me.openFile);
        }

        if (me.hyphDicts) {
          document.hyphDicts = me.hyphDicts;
        }

        if (me.objId && !me.saveToRepo && !me.saveToFile && !me.saveToStream) {
          me.saveToRepo = {
            objId: me.objId,
            tryUpdate: true
          };
        }

        if (me.saveToRepo) {
          if (!me.saveToRepo.format) {
            me.saveToRepo.format = "pdf";
          }
          objId = document.saveToRepo(me.saveToRepo);
        } else if (me.saveToFile) {
          if (!me.saveToFile.format) {
            me.saveToFile.format = Packages.org.apache.commons.io.FilenameUtils.getExtension(me.saveToFile.filePath);
          }
          document.saveFile(me.saveToFile);
        } else if (me.saveToStream) {
          return document.saveToStream(me.saveToStream);
        }
        return {
          passOn: true,
          objId: objId
        };
      },

      /**
       * @private
       * Checks whether the extension is supported by the converter.
       * @param {String} extension Extension of the source document.
       * @return {Boolean} True if the extension is supported
       */
      isSupported: function (extension) {
        var me = this,
            docClassName;

        if (!extension) {
          return false;
        }
        docClassName = me.docClassNames[extension];
        return !!docClassName;
      }
    });

    /*
     * Represents an Microsoft Office document.
     *
     * This is a base class that provides core functionality of handling office documents. Please refer to child class
     * implementations for more details.
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     */
    sol.define("sol.common.as.OfficeDocument", {

      /**
       * @private
       * Opens a source file.
       *
       *     officeDocument.openFile({ "file": "d:/temp/file1.docx" });
       *
       * @param {Object} openFileConfig
       */
      openFile: function (openFileConfig) {
        var me = this,
            inputStream;

        inputStream = java.io.FileInputStream(openFileConfig.file);
        me.open(inputStream);
        inputStream.close();
      },

      /**
       * @private
       * Opens a document from the repository.
       *
       *     officeDocument.openFromRepo({ objId: "ARCPATH:/Folder1/Document1" });
       *
       * @param {Object} openFromRepoConfig
       */
      openFromRepo: function (openFromRepoConfig) {
        var me = this,
            inputStream;

        inputStream = sol.common.RepoUtils.downloadToStream(openFromRepoConfig.objId);
        me.objId = openFromRepoConfig.objId;
        me.language = openFromRepoConfig.language;
        me.openExtension = openFromRepoConfig.extension;
        me.openSeparator = openFromRepoConfig.separator;
        me.open(inputStream);
        inputStream.close();

        if (openFromRepoConfig.withSord) {
          me.sord = ixConnect.ix().checkoutSord(openFromRepoConfig.objId, SordC.mbMin, LockC.NO);
        }
      },

      /**
       * @private
       * Checks whether the destination format is supported.
       *
       *     var result = officeDocument.checkFormat({ "format": "pdf" });
       *
       * @param {Object} saveConfig
       * @throws {UnsupportedException}
       */
      checkFormat: function (saveConfig) {
        var me = this,
            format;

        format = saveConfig.format;
        if (!me.saveFormats[format]) {
          throw "Save format '" + format + "' is unsupported";
        }
      },

      /**
       * @private
       * @param {Object} saveConfig
       * @returns {Function}
       */
      getSaveParams: function (saveConfig) {
        var me = this,
            format, func;

        format = saveConfig.format.toUpperCase();
        func = me["getSaveParams" + format];
        if (func) {
          return func.call(me, saveConfig);
        }
        return null;
      },

      /**
       * @private
       * Saves the converted document to a file.
       *
       *     officeDocument.saveFile({ format: "pdf", filePath: "c:\\Temp\\Document1.pdf" });
       *
       * @param {Object} saveFileConfig
       */
      saveFile: function (saveFileConfig) {
        var me = this,
            saveParams, outputStream;
        me.checkFormat(saveFileConfig);

        saveParams = me.getSaveParams(saveFileConfig);
        outputStream = new FileOutputStream(saveFileConfig.filePath);
        me.save(outputStream, saveParams);
        outputStream.close();
      },

      /**
       * @private
       * Saves the converted document into the repository.
       *
       *     officeDocument.getSaveParams({ format: "pdf", parentId: "ARCPATH:/Folder1" });
       *
       * @param {Object} saveToRepoConfig
       * @return {String} Object ID
       */
      saveToRepo: function (saveToRepoConfig) {
        var me = this,
            saveParams, outputStream;

        me.checkFormat(saveToRepoConfig);

        saveParams = me.getSaveParams(saveToRepoConfig);
        outputStream = new ByteArrayOutputStream();
        me.save(outputStream, saveParams);

        saveToRepoConfig.outputStream = outputStream;
        saveToRepoConfig.extension = saveToRepoConfig.format;

        return sol.common.RepoUtils.saveToRepo(saveToRepoConfig) + "";
      },

      /**
       * @private
       * Writes the converted document into a string. e.g. a CSV content.
       *
       *     officeDocument.saveAsString({ format: "pdf" });
       *
       * @param {Object} saveConfig
       * @return {String} Content
       */
      saveAsString: function (saveConfig) {
        var me = this,
            saveParams, outputStream, content;

        me.checkFormat(saveConfig);

        saveParams = me.getSaveParams(saveConfig);
        outputStream = new ByteArrayOutputStream();
        me.save(outputStream, saveParams);
        content = String(new java.lang.String(outputStream.toByteArray(), "UTF-8"));
        outputStream.close();
        return content;
      },

      /**
       * @private
       * Writes the converted document into a stream.
       *
       *     officeDocument.saveToStream({ format: "pdf" });
       *
       * @param {Object} saveConfig
       * @return {java.io.InputStream} Input stream
       *
       */
      saveToStream: function (saveConfig) {
        var me = this,
            saveParams, outputStream, inputStream;

        me.checkFormat(saveConfig);

        saveParams = me.getSaveParams(saveConfig);
        outputStream = new ByteArrayOutputStream();
        me.save(outputStream, saveParams);
        inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        return inputStream;
      }
    });

    /*
     * Represents a Word document.
     *
     * ## Usage
     *
     * Following example shows how to open a document from the ELO Repository and converts it to a pdf document.
     *
     *     var wordDocument = sol.create("sol.common.as.WordDocument", {});
     *
     *     wordDocument.openFromRepo({
     *       objId: "123"
     *     });
     *
     *     wordDocument.mailMerge(report.getData(), report.getDataDefinition());
     *
     *     wordDocument.hyphDicts =  { "de-DE": "C:/ELOprofessional/data/as-Demo/dict/hyph_de_DE.dic" };
     *
     *     var newObjId = wordDocument.saveToRepo({
     *       format: "pdf",
     *       parentId: "ARCPATH:/Test",
     *       name: "Report1"
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     */
    sol.define("sol.common.as.WordDocument", {
      extend: "sol.common.as.OfficeDocument",

      /**
       * @private
       * @cfg {Object}
       * Supported destination formats
       */
      saveFormats: {
        pdf: {},
        html: {},
        docx: {}
      },

      initialize: function (config) {
        var me = this;
        me.$super("sol.Base", "initialize", [config]);
        me.logger.debug(["Aspose.Words: product={0}, version={1}", Packages.com.aspose.words.BuildVersionInfo.product, Packages.com.aspose.words.BuildVersionInfo.version]);
      },

      /**
       * @private
       * @param {java.io.InputStream} inputStream
       */
      open: function (inputStream) {
        var me = this;
        me.document = new Packages.com.aspose.words.Document(inputStream);
      },

      /**
       * @private
       * Renders a template word document with placeholders.
       * The placeholders must be defined in 'mustache' syntax.
       * @param {Object} data JavaScript object that contains the data to fill-in
       * @param {Object} dataDefinition Data definition to resolve JavaScript arrays to XML tags
       */
      mailMerge: function (data, dataDefinition) {
        var me = this,
            mailMerge, xmlDoc;

        xmlDoc = sol.common.XmlUtils.convertObjectToXml(data, dataDefinition);

        mailMerge = me.document.mailMerge;
        mailMerge.useNonMergeFields = true;
        mailMerge.cleanupOptions = Packages.com.aspose.words.MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS;

        me.logger.debug("xml=" + sol.common.XmlUtils.toString(xmlDoc));
        mailMerge.executeWithRegions(new Packages.de.elo.mover.main.aspose.XmlMailMergeDataSet(xmlDoc));
      },

      /**
       * @private
       * Renders a template word document with content controls.
       * The placeholders must be defined in 'mustache' syntax.
       * @param {Object} data JavaScript object that contains the data to fill-in
       *
       * The tag of the content control must contain a Handlesbars string which determinates what should be filled in.
       * e.g. {{{CONTRACT.objKeys.PARTNER_NAME}}}
       */
      fillContentControls: function (data) {
        var me = this,
            value = "",
            controlIterator, control, tag, paragraph, run, srcFont;

        controlIterator = me.document.getChildNodes(Packages.com.aspose.words.NodeType.STRUCTURED_DOCUMENT_TAG, true).iterator();

        me.logger.debug("Fill content controls: objId=" + me.objId);
        me.logger.debug("Library: " + Packages.com.aspose.words.BuildVersionInfo.product + ": " + Packages.com.aspose.words.BuildVersionInfo.version);

        while (controlIterator.hasNext()) {
          control = controlIterator.next();
          if ((control.sdtType != Packages.com.aspose.words.SdtType.PLAIN_TEXT) && (control.sdtType != Packages.com.aspose.words.SdtType.RICH_TEXT)) {
            me.logger.debug("Word content control not supported: title=" + control.title + ", sdtType=" + control.sdtType + ", tag=" + control.tag + ", value=" + value);
            continue;
          }

          tag = String(control.tag);
          if (tag.indexOf("{{") < 0) {
            continue;
          }

          value = sol.create("sol.common.Template", {
            source: tag
          }).apply(data);
          me.logger.debug("Fill word content control: title=" + control.title + ", sdtType=" + control.sdtType + ", level=" + control.level + ", tag=" + control.tag + ", value=" + value);

          value = value.replace(/\n/g, Packages.com.aspose.words.ControlChar.LINE_BREAK);
          run = new Packages.com.aspose.words.Run(me.document, value);

          if (control.style.styleIdentifier == Packages.com.aspose.words.StyleIdentifier.DEFAULT_PARAGRAPH_FONT) {
            if (control.parentNode.paragraphBreakFont) {
              srcFont = control.parentNode.paragraphBreakFont;
            } else if (control && control.firstChild && control.firstChild.runs && (control.firstChild.runs.count > 0)) {
              srcFont = control.firstChild.runs.get(0).font;
            }
          } else {
            me.logger.debug("Use font of style '" + control.styleName + "'");
            srcFont = control.style.font;
          }

          me.copyFontProperties(srcFont, run.font);

          switch (control.level) {
            case Packages.com.aspose.words.MarkupLevel.INLINE:
              control.removeAllChildren();
              control.color = run.font.color;
              control.appendChild(run);
              break;
            case Packages.com.aspose.words.MarkupLevel.BLOCK:
              paragraph = control.childNodes.get(0);
              paragraph = new Packages.com.aspose.words.Paragraph(me.document);
              control.removeAllChildren();
              paragraph.appendChild(run);
              control.appendChild(paragraph);
              break;
            default:
              throw "Unsupported markup level";
          }
        }
      },

      /**
       * Edits Word document parts
       * @param {Array} partIds Part IDs
       * @param {Object} params Parameters
       * @param {String} [params.searchPartIdFieldName=DOCUMENT_PART_ID] Part ID search field name
       * @param {String} [params.partIdentifierPrefix=sol.common.DocumentPart] Part identifier prefix
       */
      editParts: function (partIds, params) {
        var me = this,
            partIdsAlreadyIncluded = [],
            firstInsert = true,
            i, partId, partSord, partName, partIdentifierPrefix, partIdentifier, bodyNode, currentParagraph, insertAfterNode, controlIterator, control, tag;

        if (!partIds) {
          throw "Part IDs are missing";
        }

        partIds = partIds || [];

        params = params || {};
        params.searchPartIdFieldName = params.searchPartIdFieldName || "DOCUMENT_PART_ID";
        partIdentifierPrefix = params.partIdentifierPrefix || "sol.common.DocumentPart";

        me.logger.info(["Edit word document parts: partIds={0}, params={1}", partIds, JSON.stringify(params)]);

        partIdentifier = partIdentifierPrefix + "." + params.searchPartIdFieldName;

        me.documentBuilder = new Packages.com.aspose.words.DocumentBuilder(me.document);

        controlIterator = me.document.getChildNodes(Packages.com.aspose.words.NodeType.STRUCTURED_DOCUMENT_TAG, true).iterator();

        while (controlIterator.hasNext()) {
          control = controlIterator.next();
          if (control.sdtType != Packages.com.aspose.words.SdtType.RICH_TEXT) {
            continue;
          }

          tag = String(control.tag);

          // Is the part a new part that has not yet been included?
          if (tag.indexOf(partIdentifier) < 0) {
            continue;
          }

          partId = tag.substr(partIdentifier.length + 1);
          try {
            partSord = me.getPartSord(params.searchPartIdFieldName, partId);
            partName = partSord.name;
          } catch (ex) {
            me.logger.warn("Can't load part Sord: partId={0}", partId);
            partName = "";
          }

          if (partIds.indexOf(partId) === -1) {
            me.logger.debug(["Remove word document part: partId={0}, partName={1}", partId, partName]);
            control.remove();
          } else {
            me.logger.debug(["Word part is already included: partId={0}, partName={1}", partId, partName]);
            partIdsAlreadyIncluded.push(partId);
          }
        }

        // Appends new parts
        for (i = 0; i < partIds.length; i++) {
          partId = partIds[i];
          if (partIdsAlreadyIncluded.indexOf(partId) === -1) {
            if (firstInsert) {
              me.documentBuilder.moveToDocumentEnd();
              me.logger.debug(["Insert page break before first part"]);
              me.documentBuilder.insertBreak(Packages.com.aspose.words.BreakType.PAGE_BREAK);
              me.documentBuilder.insertBreak(Packages.com.aspose.words.BreakType.PARAGRAPH_BREAK);

              currentParagraph = me.documentBuilder.currentParagraph;
              bodyNode = currentParagraph.getAncestor(Packages.com.aspose.words.NodeType.BODY);
              insertAfterNode = bodyNode.lastChild;
            }

            insertAfterNode = me.addPart(params.searchPartIdFieldName, bodyNode, insertAfterNode, partId, partIdentifier);
            firstInsert = false;
          }
        }
      },

      /**
       * @private
       * Adds a single Word part
       * @param {String} searchPartIdFieldName Part ID search field name
       * @param {com.aspose.words.Node} bodyNode
       * @param {com.aspose.words.Node} insertAfterNode
       * @param {String} partId Part ID
       * @param {String} partIdentifier Part identifier
       */
      addPart: function (searchPartIdFieldName, bodyNode, insertAfterNode, partId, partIdentifier) {
        var me = this,
            partSord, partDocument, sdtRichText, dummyPara, partName, sdtNode, spacingPara, spacingNode;

        if (!partId) {
          throw "Part ID is empty";
        }

        partSord = me.getPartSord(searchPartIdFieldName, partId);

        if (!partSord) {
          return;
        }

        partName = partSord.name;

        me.logger.debug(["Add part: partId={0}, partName={1}", partId, partName]);

        partDocument = me.loadPartDocument(partSord.id);

        sdtRichText = new Packages.com.aspose.words.StructuredDocumentTag(me.document, Packages.com.aspose.words.SdtType.RICH_TEXT, Packages.com.aspose.words.MarkupLevel.BLOCK);
        sdtRichText.tag = partIdentifier + "=" + partId;
        sdtRichText.title = partName;
        sdtRichText.isShowingPlaceholderText(false);

        dummyPara = new Packages.com.aspose.words.Paragraph(me.document);
        sdtRichText.removeAllChildren();
        sdtRichText.appendChild(dummyPara);

        sdtNode = bodyNode.insertAfter(sdtRichText, insertAfterNode);

        me.documentBuilder.moveTo(dummyPara);
        me.documentBuilder.insertDocument(partDocument.document, Packages.com.aspose.words.ImportFormatMode.KEEP_DIFFERENT_STYLES);

        dummyPara.remove();

        spacingPara = new Packages.com.aspose.words.Paragraph(me.document);
        spacingNode = bodyNode.insertAfter(spacingPara, sdtNode);

        return spacingNode;
      },

      /**
       * @private
       * Get part sord
       * @param {Object} searchPartIdFieldName Part ID search field name
       * @param {String} partId Part ID
       * @returns
       */
      getPartSord: function (searchPartIdFieldName, partId) {
        var findSordsParams, partSords, partSord;

        findSordsParams = { objKeysObj: {} };
        findSordsParams.objKeysObj[searchPartIdFieldName] = partId;

        partSords = sol.common.RepoUtils.findSords(findSordsParams, { sordZ: SordC.mbMin });

        if (!partSords && (partSords.length != 1)) {
          return;
        }

        partSord = partSords[0];

        return partSord;
      },

      /**
       * @private
       * Loads a part document
       * @param {String} partObjId Part object ID
       * @returns {sol.common.as.WordDocument}
       */
      loadPartDocument: function (partObjId) {
        var me = this,
            partDocument;

        if (!partObjId) {
          throw "Part object ID is empty";
        }

        me.logger.info(["Load part document: partObjId={0}", partObjId]);

        partDocument = sol.create("sol.common.as.WordDocument", {});
        partDocument.openFromRepo({
          objId: partObjId,
          withSord: true
        });

        return partDocument;
      },

      /**
       * Update document parts
       * @param {Object} params Parameters
       * @param {String} params.partIdentifierPrefix Part identifier prefix, e.g. `sol.common.DocumentPart`
       */
      updateParts: function (params) {
        var me = this,
            controlIterator, control, tag, partIdentifierPrefix, keyValueString, keyValueParts,
            partIdFieldName, partId;

        params = params || {};

        partIdentifierPrefix = params.partIdentifierPrefix || "sol.common.DocumentPart";

        me.documentBuilder = new Packages.com.aspose.words.DocumentBuilder(me.document);

        controlIterator = me.document.getChildNodes(Packages.com.aspose.words.NodeType.STRUCTURED_DOCUMENT_TAG, true).iterator();

        while (controlIterator.hasNext()) {
          control = controlIterator.next();
          if (control.sdtType != Packages.com.aspose.words.SdtType.RICH_TEXT) {
            continue;
          }

          tag = String(control.tag);
          if (tag.indexOf(partIdentifierPrefix) < 0) {
            continue;
          }

          keyValueString = tag.substr(partIdentifierPrefix.length + 1);

          keyValueParts = keyValueString.split("=");

          if (keyValueParts.length != 2) {
            return;
          }

          partIdFieldName = keyValueParts[0];
          partId = keyValueParts[1];

          me.updatePart(control, partIdFieldName, partId);
        }
      },

      /**
       * @private
       * Update document part
       * @param {com.aspose.words.StructuredDocumentTag} control
       * @param {String} partIdFieldName Part ID field name
       * @param {String} partObjId Part object ID
       */
      updatePart: function (control, partIdFieldName, partId) {
        var me = this,
            partSord, partDocument, dummyPara;

        partSord = me.getPartSord(partIdFieldName, partId);

        if (!partSord) {
          return;
        }

        partDocument = me.loadPartDocument(partSord.id);

        me.logger.info(["Update part: partIdFieldName={0}, partId={1}, partName={2}", partIdFieldName, partId, partSord.name + ""]);

        control.removeAllChildren();
        dummyPara = new Packages.com.aspose.words.Paragraph(me.document);
        control.appendChild(dummyPara);

        me.documentBuilder.moveTo(dummyPara);
        me.documentBuilder.insertDocument(partDocument.document, Packages.com.aspose.words.ImportFormatMode.KEEP_DIFFERENT_STYLES);

        dummyPara.remove();
      },

      /**
       * @private
       * Copies font properties
       * @param {com.aspose.words.Font} srcFont Source font
       * @param {com.aspose.words.Font} dstFont Source font
       */
      copyFontProperties: function (srcFont, dstFont) {
        if (!srcFont || !dstFont) {
          return;
        }

        dstFont.name = srcFont.name;
        dstFont.size = srcFont.size;
        dstFont.color = srcFont.color;
      },

      /**
       * @private
       * @return {com.aspose.words.SaveOptions}
       */
      getSaveParamsPDF: function () {
        return Packages.com.aspose.words.SaveOptions.createSaveOptions(Packages.com.aspose.words.SaveFormat.PDF);
      },

      /**
       * @private
       * @return {com.aspose.words.SaveOptions}
       */
      getSaveParamsDOCX: function () {
        return Packages.com.aspose.words.SaveOptions.createSaveOptions(Packages.com.aspose.words.SaveFormat.DOCX);
      },

      /**
       * @private
       * @return {com.aspose.words.SaveOptions}
       */
      getSaveParamsHTML: function () {
        return Packages.com.aspose.words.SaveOptions.createSaveOptions(Packages.com.aspose.words.SaveFormat.HTML);
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       * @param {com.aspose.words.SaveOptions} saveParams
       */
      save: function (outputStream, saveParams) {
        var me = this,
            languageString, dictFilePath, fontsDirPath;

        if (me.hyphDicts) {
          for (languageString in me.hyphDicts) {
            dictFilePath = me.hyphDicts[languageString];
            me.logger.debug(["Set hypen dictionary: lang={0}, dictFilePath={1}", languageString, dictFilePath]);
            Packages.com.aspose.words.Hyphenation.registerDictionary(languageString, dictFilePath);
          }
        }

        if (saveParams.saveFormat == Packages.com.aspose.words.SaveFormat.PDF) {
          fontsDirPath = sol.common.as.Utils.downloadFonts();
          if (fontsDirPath) {
            me.logger.info(["Set font directory for PDF export: fontDir={0}", fontsDirPath]);
            Packages.com.aspose.words.FontSettings.defaultInstance.setFontsFolder(fontsDirPath, true);
          }
        }

        me.document.save(outputStream, saveParams);
      }
    });

    /*
     * Represents an Excel document.
     *
     * ## Usage
     *
     * Following example shows how to open a document from the ELO repository and converts it to a pdf document.
     *
     *     var excelDocument = sol.create("sol.common.as.ExcelDocument", {});
     *
     *     excelDocument.openFromRepo({
     *       objId: "123"
     *       separator: "#"
     *     });
     *
     *     var newObjId = excelDocument.saveToRepo({
     *       format: "pdf",
     *       parentId: "ARCPATH:/Test",
     *       name: "ExcelDocument1"
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     */
    sol.define("sol.common.as.ExcelDocument", {
      extend: "sol.common.as.OfficeDocument",

      /**
       * @private
       * @cfg {Array}
       * Supported destination formats
       */
      saveFormats: {
        csv: {},
        pdf: {},
        html: {},
        xlsx: {}
      },

      /**
       * @private
       */
      regions: {
        at: Packages.com.aspose.cells.CountryCode.AUSTRIA,
        be: Packages.com.aspose.cells.CountryCode.BELGIUM,
        ch: Packages.com.aspose.cells.CountryCode.SWITZERLAND,
        cz: Packages.com.aspose.cells.CountryCode.CZECH,
        de: Packages.com.aspose.cells.CountryCode.GERMANY,
        dk: Packages.com.aspose.cells.CountryCode.DENMARK,
        en: Packages.com.aspose.cells.CountryCode.USA,
        fi: Packages.com.aspose.cells.CountryCode.FINLAND,
        fr: Packages.com.aspose.cells.CountryCode.FRANCE,
        hu: Packages.com.aspose.cells.CountryCode.HUNGARY,
        it: Packages.com.aspose.cells.CountryCode.ITALY,
        nl: Packages.com.aspose.cells.CountryCode.NETHERLANDS,
        pl: Packages.com.aspose.cells.CountryCode.POLAND,
        pt: Packages.com.aspose.cells.CountryCode.PORTUGAL,
        sp: Packages.com.aspose.cells.CountryCode.SPAIN,
        tr: Packages.com.aspose.cells.CountryCode.TURKEY
      },

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

      /**
       * @private
       * @param {java.io.InputStream} inputStream
       */
      open: function (inputStream) {
        var me = this,
            loadOptions, region;

        loadOptions = new Packages.com.aspose.cells.LoadOptions();

        if (me.openExtension && (me.openExtension.toLowerCase() == "csv")) {
          loadOptions = new Packages.com.aspose.cells.TxtLoadOptions(Packages.com.aspose.cells.FileFormatType.CSV);
          loadOptions.separatorString = me.openSeparator || ";";
        }

        me.workbook = new Packages.com.aspose.cells.Workbook(inputStream, loadOptions);

        if (me.language) {
          me.logger.debug(["Open workbook: language={0}, aspose.region={1}", me.language, region]);
          region = me.regions[me.language];
          me.workbook.settings.region = region;
        }
      },

      /**
       * @private
       * @return {Packages.com.aspose.cells.TxtSaveOptions}
       */
      getSaveParamsCSV: function () {
        var txtSaveOptions = new Packages.com.aspose.cells.TxtSaveOptions();
        txtSaveOptions.separator = ";";
        return txtSaveOptions;
      },

      /**
       * @private
       * @return {com.aspose.cells.PdfSaveOptions}
       */
      getSaveParamsPDF: function () {
        return new Packages.com.aspose.cells.PdfSaveOptions();
      },

      /**
       * @private
       * @return {com.aspose.cells.HtmlSaveOptions}
       */
      getSaveParamsHTML: function () {
        return new Packages.com.aspose.cells.HtmlSaveOptions();
      },

      /**
       * @private
       * @return {Number}
       */
      getSaveParamsXLSX: function () {
        return Packages.com.aspose.cells.SaveFormat.XLSX;
      },

      /**
       * Returns the excel cells
       * @param {} sheetIndex
       * @return {com.aspose.cells.Cells} Cells
       */
      getCells: function (sheetIndex) {
        var me = this,
            workSheet, cells;

        sheetIndex = sheetIndex || 0;

        workSheet = me.workbook.worksheets.get(sheetIndex);
        cells = workSheet.cells;

        return cells;
      },

      /**
       * Returns table data
       * @param {Object} params Parameters
       * @param {Number} [params.sheetIndex=0]
       * @param {String} [params.startRowIndex=0] Start row index
       * @param {String} [params.startColumnIndex=0] Start row index
       * @param {Object} columns Column names
       * @param {Objekt} columns.key Column key
       * @param {Object} columns.type Colum type, e.g. 'String', 'Date'
       * @param {Object} Table data
       */
      getTableData: function (params) {
        var me = this,
            column, cells, rowIndex, stringValue, value, rowData, rowEmpty, cell, result, i,
            dateTime;

        params = params || {};
        params.sheetIndex = params.sheetIndex || 0;
        params.startColumnIndex = params.startColumnIndex || 0;
        params.columnNames = params.columnNames || [];

        rowIndex = params.startRowIndex || 0;

        result = {
          data: []
        };

        cells = me.getCells(params.sheetIndex);

        do {
          rowData = {};
          rowEmpty = true;
          for (i = 0; i < params.columns.length; i++) {
            column = params.columns[i];
            cell = cells.getCell(rowIndex, params.startColumnIndex + i);
            stringValue = cell.stringValueWithoutFormat + "";
            value = "";

            column.type = column.type || "String";

            if (stringValue) {
              switch (column.type.toUpperCase()) {
                case "DATE": {
                  dateTime = cell.dateTimeValue;
                  value = Packages.org.apache.commons.lang3.time.DateFormatUtils.format(dateTime.toDate(), "yyyyMMdd") + "";
                  break;
                }
                default: {
                  value = cell.stringValueWithoutFormat + "";
                  break;
                }
              }

              rowData[column.key] = value;
              rowEmpty = false;
            } else {
              rowData[column.key] = "";
            }
          }

          if (!rowEmpty) {
            result.data.push(rowData);
          }
          rowIndex++;
        } while (!rowEmpty);

        return result;
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       * @param {com.aspose.cells.SaveOptions|Number} saveParams
       */
      save: function (outputStream, saveParams) {
        var me = this;
        me.workbook.calculateFormula();
        me.workbook.save(outputStream, saveParams);
      }
    });

    /*
     * Represents a PowerPoint document.
     *
     * ## Usage
     *
     * Following example shows how to open a document from the ELO Repository and converts it to a pdf document.
     *
     *     var powerPointDocument = sol.create("sol.common.as.PowerPointDocument", {});
     *     powerPointDocument.openFromRepo({
     *       objId: "123"
     *     });
     *
     *     var newObjId = powerPointDocument.saveToRepo({
     *       format: "pdf",
     *       parentId: "ARCPATH:/Test",
     *       name: "PowerPointDocument1"
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     */
    sol.define("sol.common.as.PowerPointDocument", {
      extend: "sol.common.as.OfficeDocument",

      /**
       * @cfg {Object}
       * Supported destination formats
       */
      saveFormats: {
        pdf: {},
        html: {}
      },

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

      /**
       * @private
       * @param {java.io.InputStream} inputStream
       */
      open: function (inputStream) {
        var me = this;
        me.presentation = new Packages.com.aspose.slides.Presentation(inputStream);
      },

      /**
       * @private
       * @return {Number}
       */
      getSaveParamsPDF: function () {
        return Packages.com.aspose.slides.SaveFormat.Pdf;
      },

      /**
       * @private
       * @return {Number}
       */
      getSaveParamsHTML: function () {
        return Packages.com.aspose.slides.SaveFormat.Html;
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       * @param {Number} saveParams
       */
      save: function (outputStream, saveParams) {
        var me = this;
        me.presentation.save(outputStream, saveParams);
      }
    });

    /*
     * Represents an Outlook message (MSG).
     *
     * ## Usage
     *
     * Following example shows how to open an email from the ELO Repository and converts it to a pdf document.
     *
     *     var mapiMessage = sol.create("sol.common.as.MapiMessage", {});
     *
     *     mapiMessage.openFromRepo({
     *       objId: "123"
     *     });
     *
     *     var newObjId = mapiMessage.saveToRepo({
     *       format: "pdf",
     *       parentId: "ARCPATH:/Test",
     *       name: "MapiMessage1"
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     */
    sol.define("sol.common.as.MapiMessage", {
      extend: "sol.common.as.OfficeDocument",

      /**
       * @private
       * @cfg {Object}
       * Supported destination formats
       */
      saveFormats: {
        pdf: {}
      },

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

      /**
       * @private
       * @param {java.io.InputStream} inputStream
       */
      open: function (inputStream) {
        var me = this;
        me.mailMessage = new Packages.com.aspose.email.MailMessage.load(inputStream);
      },

      /**
       * @private
       * @return {String}
       */
      getSaveParamsPDF: function () {
        return "PDF";
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       * @param {String} saveParams
       */
      save: function (outputStream, saveParams) {
        var me = this;
        if (saveParams == "PDF") {
          me.savePDF(outputStream);
        }
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       */
      savePDF: function (outputStream) {
        var me = this,
            mhtmlOutputStream, loadOptions, mhtmlInputStream, wordDocument, saveOptions;

        mhtmlOutputStream = new ByteArrayOutputStream();
        saveOptions = Packages.com.aspose.email.SaveOptions.createSaveOptions(Packages.com.aspose.email.MailMessageSaveType.getMHtmlFormat());
        me.mailMessage.save(mhtmlOutputStream, saveOptions);
        mhtmlOutputStream.close();
        loadOptions = new Packages.com.aspose.words.LoadOptions();
        loadOptions.loadFormat = Packages.com.aspose.words.LoadFormat.MHTML;
        mhtmlInputStream = new ByteArrayInputStream(mhtmlOutputStream.toByteArray());
        wordDocument = new Packages.com.aspose.words.Document(mhtmlInputStream, loadOptions);
        mhtmlInputStream.close();
        wordDocument.save(outputStream, Packages.com.aspose.words.SaveFormat.PDF);
      }
    });

    /*
     * Represents a Visio document.
     *
     * ## Usage
     *
     * Following example shows how to open a document from the ELO repository and converts it to a pdf document.
     *
     *     var visioDocument = sol.create("sol.common.as.VisioDocument", {});
     *
     *     visioDocument.openFromRepo({
     *       objId: "123"
     *     });
     *
     *     var newObjId = visioDocument.saveToRepo({
     *       format: "pdf",
     *       parentId: "ARCPATH:/Test",
     *       name: "VisioDocument1"
     *     });
     *
     * @author MV, ELO Digital Office GmbH
     * @version 1.0
     *
     * @eloas
     *
     */
    sol.define("sol.common.as.VisioDocument", {

      extend: "sol.common.as.OfficeDocument",

      /**
       * @private
       * @cfg {Object}
       * Supported destination formats
       */
      saveFormats: {
        pdf: {}
      },

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

      /**
       * @private
       * @param {java.io.InputStream} inputStream
       */
      open: function (inputStream) {
        var me = this;
        me.diagram = new Packages.com.aspose.diagram.Diagram(inputStream);
      },

      /**
       * @private
       * @return {com.aspose.diagram.DiagramSaveOptions}
       */
      getSaveParamsPDF: function () {
        return Packages.com.aspose.diagram.SaveFileFormat.PDF;
      },

      /**
       * @private
       * @param {java.io.OutputStream} outputStream
       * @param {com.aspose.diagram.DiagramSaveOptions} saveParams
       */
      save: function (outputStream, saveParams) {
        var me = this;
        me.diagram.save(outputStream, saveParams);
      }
    });