//@include lib_Class.js

/**
 * Rendering PDF file from a Apache FOP template.
 *
 * @author ELO Digital Office GmbH
 *
 * @eloas
 * @requires sol.common.RepoUtils
 * @requires sol.common.Template
 */
sol.define("sol.common.as.renderer.Fop", {

  /**
   * @cfg {String} templateId
   * The objid of a template sord
   * which should be rendered
   * either templateContent or templateId has to be passed
   */

  /**
   * @cfg {String} templateContent
   * The template content which should be rendered
   * either templateContent or templateId has to be passed
   */

  /**
   * @cfg {String} targetId
   * The target folder to store the rendered document.
   * Either `targetId` or `objId` has to be defined.
   */

  /**
   * @cfg {String} objId
   * The rendered document will be saved as a version of this object
   * Either `targetId` or `objId` has to be defined.
   */

  /**
   * @cfg {String} toStream
   * If true, the renderer will return the output stream
   */

  /**
   * @cfg {String} version
   * Version of the rendered document
   */

  /**
   * @cfg {String} versionComment
   * Version comment of the rendered document
   */

  /**
   * @cfg {String} versionIncrement
   * Version increment, i.g. `1` to the saved rendered document
   */

  /**
   * @cfg {Object} objKeysObj
   * Map that contains key-value pairs to the saved rendered document
   */

  /**
   * @cfg {String} ownerId
   * Owner ID to the saved rendered document
   */

  initialize: function (config) {
    var me = this;
    me.$super("sol.Base", "initialize", [config]);
    if (!me.objId && !me.targetId && !me.toStream) {
      throw "IllegalArgumentException: either 'targetId' or 'objId' has to defined";
    }
    if (!me.templateId && !me.templateContent) {
      throw "IllegalArgumentException: either 'templateId' or 'templateContent' has to be defined";
    }
  },

  render: function (name, data) {
    var me = this,
        result = {},
        fopFontDirFiles = [],
        pdfStream, foContent, foStream, tpl, eloAsConfig,
        fopConfig, fopFontsConfig, fopFontsAutoDetect, fopFontsDirs, i, fopFontsDir, fopFontsRepoPaths, fopFontsRepoPath,
        fopFontsCacheFilePath, fopFontsCacheFile, exceptionString, osUserName, userHomeDirPath, isUserHomeDirWritable;

    me.maskId = me.maskId || "";

    try {
      tpl = sol.create("sol.common.Template", {});
      if (me.templateContent) {
        tpl.setSource(me.templateContent);
      } else {
        tpl.load(me.templateId);
      }

      foContent = tpl.apply(data);

      me.logger.debug(["fo={0}", foContent]);

      foStream = org.apache.commons.io.IOUtils.toInputStream(foContent, "UTF-8");
      pdfStream = new ByteArrayOutputStream();

      eloAsConfig = sol.create("sol.common.Config").loadEloAsConfig(me.solutionNameForAsConfig);

      me.logger.debug(["asConfig={0}", JSON.stringify(eloAsConfig)]);
      fopConfig = eloAsConfig.fop || {};
      fopFontsConfig = fopConfig.fonts || {};
      fopFontsAutoDetect = (typeof fopFontsConfig.autoDetect == "undefined") ? false : fopFontsConfig.autoDetect;
      fopFontsDirs = fopFontsConfig.dirs || [];
      fopFontsCacheFilePath = fopFontsConfig.cacheFile || null;

      fopFontsRepoPaths = [];

      for (i = 0; i < fopFontsDirs.length; i++) {
        fopFontsDir = fopFontsDirs[i];
        if (fopFontsDir.indexOf("ARCPATH") == 0) {
          fopFontsRepoPaths.push(fopFontsDir);
        } else {
          fopFontDirFiles.push(new java.io.File(fopFontsDir));
        }
      }
      if (fopFontsRepoPaths.length > 0) {
        fopFontsRepoPath = sol.common.as.Utils.downloadFonts({ fopFontsRepoPaths: fopFontsRepoPaths });
        fopFontDirFiles.push(new java.io.File(fopFontsRepoPath));
      }

      osUserName = sol.common.FileUtils.getOsUserName();
      userHomeDirPath = sol.common.FileUtils.getHomeDirPath();
      isUserHomeDirWritable = sol.common.FileUtils.isWritable(userHomeDirPath);

      me.logger.info(["FOP font cache info: osUserName={0}, userHomeDir={1}, isUserHomeDirWritable={2}", osUserName, userHomeDirPath, isUserHomeDirWritable]);

      if (fopFontsCacheFilePath && me.hasMethod("de.elo.mover.main.helper.XmlHelper", "convertToPdf3")) {
        me.logger.info(["convertToPdf3: foStreamPresent={0}, pdfStreamPresent={1}, fopFontsAutoDetect={2}, fopFontDirs={3}, fopFontsCacheFile={4}", !!foStream, !!pdfStream, fopFontsAutoDetect, fopFontDirFiles, fopFontsCacheFilePath]);
        fopFontsCacheFile = new java.io.File(fopFontsCacheFilePath);
        Packages.de.elo.mover.main.helper.XmlHelper.convertToPdf3(foStream, pdfStream, fopFontsAutoDetect, fopFontDirFiles, fopFontsCacheFile);
      } else if (me.hasMethod("de.elo.mover.main.helper.XmlHelper", "convertToPdf2")) {
        me.logger.info(["convertToPdf2: foStreamPresent={0}, pdfStreamPresent={1}, fopFontsAutoDetect={2}, fopFontDirs={3}, (fopFontsCacheFile={4})", !!foStream, !!pdfStream, fopFontsAutoDetect, fopFontDirFiles, fopFontsCacheFilePath]);
        Packages.de.elo.mover.main.helper.XmlHelper.convertToPdf2(foStream, pdfStream, fopFontsAutoDetect, fopFontDirFiles);
      } else {
        me.logger.info(["convertToPdf: foStreamPresent={0}, pdfStreamPresent={1}", !!foStream, !!pdfStream]);
        Packages.de.elo.mover.main.helper.XmlHelper.convertToPdf(foStream, pdfStream);
      }

      if (me.toStream) {
        result.outputStream = pdfStream;
      }

      if (me.objId) {
        result.objId = sol.common.RepoUtils.saveToRepo({
          objId: me.objId,
          extension: "pdf",
          outputStream: pdfStream,
          version: me.version,
          versionComment: me.versionComment,
          versionIncrement: me.versionIncrement,
          objKeysObj: me.objKeysObj,
          ownerId: me.ownerId
        });
      }

      if (me.targetId) {
        sol.common.RepoUtils.preparePath(me.targetId);
        result.objId = sol.common.RepoUtils.saveToRepo({
          name: name,
          parentId: me.targetId,
          maskId: me.maskId,
          extension: "pdf",
          outputStream: pdfStream,
          version: me.version,
          versionComment: me.versionComment,
          objKeysObj: me.objKeysObj,
          ownerId: me.ownerId
        });
      }
    } catch (ex) {
      exceptionString = sol.common.ExceptionUtils.parseException(ex);
      me.logger.error(["error rendering report '{0}' (templateId='{1}')", name, me.templateId], exceptionString);
    } finally {
      if (foStream) {
        foStream.close();
      }
      if (pdfStream) {
        pdfStream.close();
      }
    }
    return result;
  },

  /**
   * @private
   * Checks wether a method exists
   * @param clazz Class
   * @param methodName Method name
   */
  hasMethod: function (className, methodName) {
    var methods, clazz, methodExists;

    if (!className) {
      throw "Class name is missing";
    }

    if (!methodName) {
      throw "Method name is missing";
    }

    clazz = java.lang.Class.forName(className);

    methods = clazz.declaredMethods;

    methodExists = methods.some(function (method) {
      return (method.name == methodName);
    });

    return methodExists;
  }
});