package com.fp.frontend.controller;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashMap;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;

import org.primefaces.model.StreamedContent;

import com.fp.common.properties.PropertiesHandler;
import com.fp.frontend.controller.pgeneral.date.TgeneAccountingDateBranchController;
import com.fp.frontend.controller.security.LoginController;
import com.fp.persistence.pgeneral.date.TgeneAccountingDateBranch;
import com.jaspersoft.ireport.jasperserver.JServer;
import com.jaspersoft.ireport.jasperserver.ws.WSClient;
import com.jaspersoft.jasperserver.api.metadata.xml.domain.impl.ResourceDescriptor;
import java.io.File;

/**
 * Clase controladora de reportes.
 *
 * @author Jorge Vaca.
 * @version 2.1
 */
@ManagedBean
@ViewScoped
public class ReportController {

    private StreamedContent streamedContent;

    public ReportController() {
    }

    public void execute(String path, HashMap<String, Object> parameters, String format, String filename, LoginController logincontroller) throws Exception {
        this.adddefaultparameters(parameters, logincontroller);
        if (format == null) {
            format = "pdf";
        }
        if ((format.compareTo("xls") == 0) || (format.compareTo("xlsx") == 0)) {
            parameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
        }

        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
        response.addHeader("Content-disposition", "attachment; filename=" + filename + ".pdf");
        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany() + "/modules/" + path, parameters);
        OutputStream outputStream = response.getOutputStream();

        JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
        FacesContext.getCurrentInstance().responseComplete();

    }

    /**
     * M&eacute;todo que exporta el reporte a formato .xlsx
     *
     * @param path, ruta de acceso al reporte en el servidor jaspersoft
     * @param parameters, par&aacute;metros que se env&iacute;an desde el
     * controlador
     * @param format, formato de archivo, en este caso xlsx
     * @param filename, nombre que tendr&aacute; el archivo
     * @param logincontroller
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public void executeXls(String path, HashMap<String, Object> parameters, String format, String filename, LoginController logincontroller) throws Exception {
        this.adddefaultparameters(parameters, logincontroller);
        if (format == null) {
            format = "pdf";
        }
        if ((format.compareTo("xls") == 0) || (format.compareTo("xlsx") == 0)) {
            parameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
        }

        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
        response.addHeader("Content-disposition", "attachment; filename=" + filename + ".xlsx");
        System.out.println(logincontroller.getRequest().getCompany() + "/modules/" + path);
//        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany() + "/modules/" + path, parameters);
        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany()+"/modules/"+ path, parameters);

        OutputStream ouputStream = response.getOutputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        JRXlsxExporter exporter = new JRXlsxExporter();
        exporter.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
        exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.TRUE);
        exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
        exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
        exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
        exporter.exportReport();
        ouputStream.write(byteArrayOutputStream.toByteArray());
        ouputStream.flush();
        ouputStream.close();
        FacesContext.getCurrentInstance().responseComplete();

    }

    private JasperPrint executereport(String pathJasper, HashMap<String, Object> parameters) throws Exception {
        PropertiesHandler ph = new PropertiesHandler("jasper");

        JServer server = new JServer();
        //server.setUsername("jasperadmin");
        server.setUsername(ph.getStringValue("jasperserver.user"));
        //server.setPassword("jasperadmin");
        server.setPassword(ph.getStringValue("jasperserver.password"));
        //server.setUrl("http://localhost:8080/jasperserver/services/repository");
        server.setUrl(ph.getStringValue("jasperserver.repository"));
        ResourceDescriptor rd = new ResourceDescriptor();
        rd.setWsType(ResourceDescriptor.TYPE_REPORTUNIT);
        rd.setUriString("/maia/" + pathJasper);
        WSClient wsClient = server.getWSClient();
        return wsClient.runReport(rd, parameters);
    }

    /**
     * Recupera un input stream del reporte pdf
     *
     * @param path
     * @param parameters
     * @param format
     * @param filename
     * @param logincontroller
     * @return
     * @throws Exception
     */
    public InputStream jaspertoInputstream(String path, HashMap<String, Object> parameters, String format, String filename, LoginController logincontroller) throws Exception {
        this.adddefaultparameters(parameters, logincontroller);
        if (format == null) {
            format = "pdf";
        }
        if ((format.compareTo("xls") == 0) || (format.compareTo("xlsx") == 0)) {
            parameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
        }

        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
        response.addHeader("Content-disposition", "attachment; filename=" + filename + ".pdf");
        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany() + "/modules/" + path, parameters);

        OutputStream outputStream = response.getOutputStream();
        JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
        InputStream inputStream;

        byte[] byteArray = JasperExportManager.exportReportToPdf(jasperPrint);
        inputStream = new ByteArrayInputStream(byteArray);
        FacesContext.getCurrentInstance().responseComplete();

        return inputStream;

    }

    /**
     * Recupera un byte array del reporte pdf
     *
     * @param path
     * @param parameters
     * @param format
     * @param filename
     * @param logincontroller
     * @return
     * @throws Exception
     */
    public byte[] jaspertoByteArray(String path, HashMap<String, Object> parameters, String format, String filename, LoginController logincontroller) throws Exception {
        this.adddefaultparameters(parameters, logincontroller);
        if (format == null) {
            format = "pdf";
        }
        if ((format.compareTo("xls") == 0) || (format.compareTo("xlsx") == 0)) {
            parameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
        }
        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany() + "/modules/" + path, parameters);
        JasperExportManager.exportReportToPdfFile(jasperPrint, filename + "." + format);
        byte[] byteArray = JasperExportManager.exportReportToPdf(jasperPrint);
        return byteArray;

    }

    /**
     * Recupera un input stream del reporte xls
     *
     * @param path
     * @param parameters
     * @param format
     * @param filename
     * @param logincontroller
     * @return
     * @throws Exception
     */
    public InputStream jaspertoInputstreamXls(String path, HashMap<String, Object> parameters, String format, String filename, LoginController logincontroller) throws Exception {
        this.adddefaultparameters(parameters, logincontroller);
        if (format == null) {
            format = "xls";
        }
        if ((format.compareTo("xls") == 0) || (format.compareTo("xlsx") == 0)) {
            parameters.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
        }
        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
        response.addHeader("Content-disposition", "attachment; filename=" + filename + ".xls");
        JasperPrint jasperPrint = this.executereport(logincontroller.getRequest().getCompany() + "/modules/" + path, parameters);

        OutputStream ouputStream = response.getOutputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        JRXlsxExporter exporter = new JRXlsxExporter();
        exporter.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
        exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.TRUE);
        exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
        exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
        exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
        exporter.exportReport();
        ouputStream.write(byteArrayOutputStream.toByteArray());
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        ouputStream.flush();
        ouputStream.close();
        FacesContext.getCurrentInstance().responseComplete();

        InputStream inputStream;
        inputStream = new ByteArrayInputStream(byteArray);
        FacesContext.getCurrentInstance().responseComplete();
        return inputStream;
    }

    private void adddefaultparameters(HashMap<String, Object> parameters, LoginController logincontroller) throws Exception {
        if (parameters == null) {
            parameters = new HashMap<String, Object>();
        }
        parameters.put("pathimage", "repo:/maia/" + logincontroller.getRequest().getCompany() + "/image/logo");
        parameters.put("pathstyle", "repo:/maia/" + logincontroller.getRequest().getCompany() + "/style/style");

        TgeneAccountingDateBranch accodate = TgeneAccountingDateBranchController.find(logincontroller.getRequest().getCompany());
        parameters.put("workingdate", accodate.getWorkingdate());
        parameters.put("accountingdate", accodate.getAccountingdate());
        //parameters.workingtime = User.getHour();
        parameters.put("companycode", logincontroller.getRequest().getCompany());
        parameters.put("usercode", logincontroller.getRequest().getUser());
        parameters.put("languagecode", logincontroller.getRequest().getLanguage().toUpperCase());

    }

    /**
     * Formato de fechas utilizado en la ejecucion de reportes.
     */
    private static SimpleDateFormat FORMATOFECHAREPORTES = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * Entrega un string con la fecha en formato "yyyy-MM-dd"
     *
     * @param value Fecha a transformar a un string.
     * @return String
     */
    public String getFechaReporte(Date value) {
        if (value == null) {
            return null;
        }
        return FORMATOFECHAREPORTES.format(value);
    }

    public StreamedContent getStreamedContent() {
        return streamedContent;
    }

    public void setStreamedContent(StreamedContent streamedContent) {
        this.streamedContent = streamedContent;
    }
}
