package com.fp.frontend.controller.pentaho;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import com.fp.common.properties.PropertiesHandler;
import com.fp.frontend.controller.security.LoginController;
import com.fp.frontend.utility.Content;

/**
 * Clase controladora de Pentaho
 *
 * @author WPA
 *
 */
@ManagedBean
@ViewScoped
public class PentahoController {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * Constuctor
     */
    public PentahoController() {
        // TODO Auto-generated constructor stub
    }
    /**
     * Inject LoginController
     */
    @ManagedProperty(value = "#{loginController}")
    private LoginController logincontroler;
    /**
     * Atributo para la lista tipos de formato
     */
    protected List<Content> lcontent;
    /**
     * Atributo para el tipo de formato
     */
    private String type;
    /**
     * Atributo para activar un componente
     */
    private boolean active;
    /**
     * Atributo para el reporte a descargar
     */
    private StreamedContent streamedContent;

    /**
     * Post construct
     */
    @PostConstruct
    public void postConstruct() {
        this.loadContent();
    }

    /**
     * Carga la lista del content type
     */
    public void loadContent() {
        this.lcontent = new ArrayList<Content>();
        this.lcontent.add(new Content("PDF", "application/pdf", "pdf"));
        this.lcontent.add(new Content("EXCEL", "application/vnd.ms-excel", "xls"));
    }

    /**
     * Obtiene la url del BI-Server
     *
     * @param reporte nombre del reporte.xaction
     * @param parameters Mapa de parametros
     * @param type Tipo de archivo
     * @return url
     * @throws Exception
     */
    private String getUrlPentaho(String reporte, Map<String, String> parameters, String type) throws Exception {
        PropertiesHandler ph = new PropertiesHandler("pentaho");

        String url = ph.getStringValue("url_pentaho");
        String auth = ph.getStringValue("pentaho_authenticate");

        StringBuilder urlPentaho = new StringBuilder(url);
        if (auth.equals("N")) {
            urlPentaho.append(reporte).append(".xaction").append("&userid=").append("&password=");
        } else {
            urlPentaho.append(reporte).append(".xaction").append("&userid=").append(ph.getStringValue("usr_pentaho")).append("&password=").append(ph.getStringValue("pass_pentaho"));
        }
        Set<String> keys = parameters.keySet();
        for (String key : keys) {
            urlPentaho.append("&").append(key).append("=").append(parameters.get(key));
        }
        return urlPentaho.append("&outputType=").append(type).toString();
    }

    /**
     * Crea el reporte.
     *
     * @param reporte Nombre del reporte
     * @param parameters Mapa de par&aacute;metros
     * @param type Tipo de reporte
     * @throws Exception
     */
    private StreamedContent generateReport(String reporte, Map<String, String> parameters, String type) throws Exception {
        String content = "";

        // se ejecuta la llamada al recurso xaction de pentaho
        InputStream inputStream = this.generateTemporalReport(reporte, parameters, type);

        for (Content con : this.lcontent) {
            if (type.equals(con.getExtension())) {
                content = con.getContentType();
            }
        }
        return new DefaultStreamedContent(inputStream, content, reporte + "." + type);
    }

    /**
     * Crea el reporte.
     *
     * @param reporte Nombre del reporte
     * @param parameters Mapa de par&aacute;metros
     * @param type Tipo de reporte
     * @throws Exception
     */
    //@SuppressWarnings("deprecation")
    public InputStream generateTemporalReport(String reporte, Map<String, String> parameters, String type) throws Exception {

        // Cliente java
        DefaultHttpClient cliente = new DefaultHttpClient();
        //HttpClient cliente = HttpClientBuilder.create().build();

        String url = this.getUrlPentaho(reporte, parameters, type).replace(" ", "%20");

        // ACTION HTTP POST
        HttpPost httpPost = new HttpPost(url);
        HttpResponse httpResponse = cliente.execute(httpPost);
        InputStream inputStream = httpResponse.getEntity().getContent();
        //cliente.close();
        return inputStream;
    }

    /**
     * Llamada al reporte pentaho
     *
     * @throws Exception
     */
    public void getReport(String nomReporte, Map<String, String> parameters) throws Exception {
        this.streamedContent = this.generateReport(nomReporte, parameters, this.type == null ? "pdf" : this.type);
    }

    /**
     * Evento al cambiar el tipo de reporte
     *
     * @throws Exception
     */
    public void changeType() throws Exception {
        if (this.type.equals("PDF")) {
            this.active = true;
            //this.generarReporte();
        } else {
            this.active = true;
        }
    }

    /**
     * Entrega la instancia de LoginController
     *
     * @return loginController
     */
    public LoginController getLogincontroler() {
        return logincontroler;
    }

    /**
     * Fija la instancia de LoginController
     *
     * @param loginController
     */
    public void setLogincontroler(LoginController logincontroler) {
        this.logincontroler = logincontroler;
    }

    /**
     * Entrega la lista de contentType
     *
     * @return lcontent
     */
    public List<Content> getLcontent() {
        return this.lcontent;
    }

    /**
     * Fija una lista de contentType
     *
     * @param lcontent
     */
    public void setLcontent(List<Content> lcontent) {
        this.lcontent = lcontent;
    }

    /**
     * Entrega ek tipo de formato
     *
     * @return type
     */
    public String getType() {
        return type;
    }

    /**
     * Fija ek tipo de formato
     *
     * @param type
     */
    public void setType(String type) {
        this.type = type;
    }

    /**
     * Entrega V/F si es activo
     *
     * @return active
     */
    public boolean isActive() {
        return active;
    }

    /**
     * False V/F si es activo
     *
     * @param active
     */
    public void setActive(boolean active) {
        this.active = active;
    }

    /**
     * Entrega el objeto StreamedContent
     *
     * @return streamedContent
     */
    public StreamedContent getStreamedContent() {
        if (FacesContext.getCurrentInstance().getRenderResponse()) {
            return new DefaultStreamedContent();
        } else {
            return streamedContent;
        }
    }

    /**
     * Fija el objeto StreamedContent
     *
     * @param streamedContent
     */
    public void setStreamedContent(StreamedContent streamedContent) {
        this.streamedContent = streamedContent;
    }
}
