package com.ffii.core.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.springframework.core.io.ClassPathResource;

import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;

public abstract class JasperUtils {

  public static JasperPrint compile(
      String templateClasspath,
      Map<String, Object> params,
      JRDataSource dataSource,
      Map<String, String> subTemplateClasspath)
      throws JRException, IOException {
    return compile(templateClasspath, params, dataSource, subTemplateClasspath, LocaleUtils.getLocale());
  }

  public static JasperPrint compile(
      String templateClasspath,
      Map<String, Object> params,
      JRDataSource dataSource,
      Map<String, String> subTemplateClasspath,
      Locale locale)
      throws JRException, IOException {
    String localeStr = LocaleUtils.toLocaleStr(locale);
    if (subTemplateClasspath != null) {
      params = new HashMap<>(params);
      for (Map.Entry<String, String> entry : subTemplateClasspath.entrySet()) {
        ClassPathResource r = new ClassPathResource(entry.getValue() + "_" + localeStr + ".jrxml");
        if (!r.exists()) r = new ClassPathResource(entry.getValue() + ".jrxml");

        try (InputStream in = r.getInputStream()) {
          params.put(entry.getKey(), JasperCompileManager.compileReport(in));
        }
      }
    }

    ClassPathResource r = new ClassPathResource(templateClasspath + "_" + localeStr + ".jrxml");
    if (!r.exists()) r = new ClassPathResource(templateClasspath + ".jrxml");

    try (InputStream in = r.getInputStream()) {
      return JasperFillManager.fillReport(
          JasperCompileManager.compileReport(in),
          params,
          dataSource);
    }
  }

  public static void responseDocx(
      HttpServletResponse response,
      JasperPrint jRerpot,
      String fileName) throws IOException, JRException {
    try (OutputStream out = response.getOutputStream()) {
      JRAbstractExporter<?, ?, OutputStreamExporterOutput, ?> exporter = new JRDocxExporter();
      exporter.setExporterInput(new SimpleExporterInput(jRerpot));
      exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
      response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
      response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"",
          response.encodeURL(fileName + ".docx")));
      exporter.exportReport();
    }
  }

  public static void responsePdf(
      HttpServletResponse response,
      JasperPrint jRerpot,
      String fileName,
      boolean download) throws IOException, JRException {
    try (OutputStream out = response.getOutputStream()) {
      JRAbstractExporter<?, ?, OutputStreamExporterOutput, ?> exporter = new JRPdfExporter();
      exporter.setExporterInput(new SimpleExporterInput(jRerpot));
      exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
      response.setContentType("application/pdf");
      response.setHeader("Content-Disposition",
          String.format("%s; filename=\"%s\"", download ? "attachment" : "inline",
              response.encodeURL(fileName + ".pdf")));
      exporter.exportReport();
    }
  }

  public static byte[] toByteArrayPdf(JasperPrint jRerpot) throws JRException, IOException {
    try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) {
      JRAbstractExporter<?, ?, OutputStreamExporterOutput, ?> exporter = new JRPdfExporter();
      exporter.setExporterInput(new SimpleExporterInput(jRerpot));
      exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteOut));
      exporter.exportReport();
      return byteOut.toByteArray();
    }
  }

  public static byte[] toByteArrayDocx(JasperPrint jRerpot) throws JRException, IOException {
    try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) {
      JRAbstractExporter<?, ?, OutputStreamExporterOutput, ?> exporter = new JRDocxExporter();
      exporter.setExporterInput(new SimpleExporterInput(jRerpot));
      exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteOut));
      exporter.exportReport();
      return byteOut.toByteArray();
    }
  }
}
