/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.qsoft.wmp.services.rest;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qsoft.util.constantes.CodigoRespuesta;
import com.qsoft.util.constantes.ErrorTipo;
import com.qsoft.util.ms.pojo.HeaderMS;
import com.qsoft.erp.constantes.DominioConstantes;
import com.qsoft.erp.constantes.EntidadEnum;
import com.qsoft.erp.dominio.MultipartService;
import com.qsoft.erp.dominio.exception.DominioExcepcion;
import com.qsoft.erp.dominio.util.AuditoriaUtil;
import com.qsoft.erp.dto.AuditoriaDTO;
import com.qsoft.erp.dto.DocumentoDTO;
import com.qsoft.erp.dto.LiquidacionDTO;
import com.qsoft.wmp.services.util.ServiceUtil;
import com.qsoft.wmp.services.xsd.EntradaLiquidacion;
import com.qsoft.wmp.services.xsd.SalidaConsulta;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;

/**
 * REST Web Service
 *
 * @author james
 */
@Path("multipart")
@MultipartConfig(
        maxFileSize = 838860800l, // 100Mb 
        fileSizeThreshold = 52428800, //512 
        maxRequestSize = 1024000 // 10Kb 
)
public class MultipartResource {

    @Inject
    private MultipartService multipart;

    @Inject
    private AuditoriaUtil auditoria;

    @Context
    private HttpServletRequest request;

    @PostConstruct
    public void postConstructor() {

    }

    /**
     *
     * @return an instance of java.lang.String
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public SalidaConsulta getJson() {
        SalidaConsulta salida = ServiceUtil.crearSalidaConsultaError(CodigoRespuesta.CODIGO_ERROR_GENERICO,
                "Acción no soportada por favor ejecute la consulta via POST");
        return salida;
    }

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public SalidaConsulta postFile(FormDataMultiPart input) {
        SalidaConsulta salida = null;
        EntradaLiquidacion entrada = null;
        Long time = System.currentTimeMillis();

        boolean estado = false;
        if (input != null) {
            List<Object> data = new ArrayList<>();
            Map<String, List<FormDataBodyPart>> parts = input.getFields();
            int i = 0;
            try {
                for (List<FormDataBodyPart> p : parts.values()) {
                    FormDataBodyPart bp = p.get(0);
                    if (i == 0) {
                        entrada = getEntrada(bp);
                        if (entrada != null && entrada.getBodyIn() != null) {
                            AuditoriaDTO dto = ServiceUtil.crearAuditoria(entrada.getHeaderIn(), entrada.getBodyIn().getEntidad(),
                                    super.getClass().getName() + ".posFile", request.getRequestURL().toString(),
                                    MultipartService.class.getName() + ".multipartGenerico", ServiceUtil.REQUEST,
                                    "" + entrada.getBodyIn().getTipoConsulta(), 0, ServiceUtil.getJson(entrada));
                            this.auditoria.AddAuditoria(dto);
                        }
                        if (entrada != null && entrada.getBodyIn().getParametros() != null
                                && entrada.getBodyIn().getParametros().get("Liquidacion") != null
                                && entrada.getBodyIn().getParametros().get("Liquidacion").getPolCodigo() != null
                                && entrada.getBodyIn().getParametros().get("Liquidacion").getPolCodigo() == -1) {
                            throw new DominioExcepcion(ErrorTipo.ERROR, CodigoRespuesta.CODIGO_VALOR_NULO,
                                    "No existe una poliza activa no puede ejecutar este proceso");
                        }
                    } else {
                        InputStream in = bp.getValueAs(InputStream.class);
                        try {
                            if (in != null && entrada != null && entrada.getBodyIn().getParametros() != null
                                    && entrada.getBodyIn().getParametros().get("Liquidacion") != null) {
                                DocumentoDTO doc = (DocumentoDTO) entrada.getBodyIn().getParametros().get("Liquidacion").getDocumentos().get(i - 1);
                                doc.setData(in.readAllBytes());
                            }
                        } catch (IOException ex) {
                            System.out.println("ERROR CARGANDO ARCHIVO " + ex);
                        }
                    }
                    i++;
                }
                if (!validarEntrada(entrada)) {
                    throw new DominioExcepcion(ErrorTipo.ERROR, CodigoRespuesta.CODIGO_VALOR_NULO,
                            "Uno o mas documentos enviados son nulos por favor verifique la informacion");
                }
                EntidadEnum entidad = Enum.valueOf(EntidadEnum.class, entrada.getBodyIn().getEntidad());
                data = this.multipart.multipartGenerico(entrada.getHeaderIn(), entidad,
                        entrada.getBodyIn().getParametros(), entrada.getBodyIn().getTipoConsulta());
                HeaderMS header = entrada.getHeaderIn();
                header.setFechaHora(DominioConstantes.getDateTime());
                salida = ServiceUtil.crearSalidaConsultaOk(header, entrada.getBodyIn().getEntidad(), data);
            } catch (DominioExcepcion ex) {
                salida = ServiceUtil.crearSalidaConsultaError(ex.getCodigo(), ex.getMensaje());
                ex.printStackTrace();
            } catch (Exception ex) {
                salida = ServiceUtil.crearSalidaConsultaError(CodigoRespuesta.CODIGO_ERROR_GENERICO, ex.toString());
                ex.printStackTrace();
            }

        } else {
            ServiceUtil.crearSalidaConsultaError(CodigoRespuesta.CODIGO_VALOR_NULO, "ERROR. La entrada no puede ser nula");
        }
        time = System.currentTimeMillis() - time;
        AuditoriaDTO dto = ServiceUtil.crearAuditoria(salida.getHeaderOut(), salida.getBodyOut().getEntidad(),
                super.getClass().getName() + ".posFile", request.getRequestURL().toString(),
                MultipartService.class.getName() + ".multipartGenerico", ServiceUtil.RESPONSE,
                "", time.intValue(), ServiceUtil.getJson(salida.getError()));
        this.auditoria.AddAuditoria(dto);

        return salida;
    }

    /**
     *
     * @param entrada
     * @return
     */
    private boolean validarEntrada(EntradaLiquidacion entrada) {
        boolean estado = true;
        if (entrada == null || entrada.getBodyIn() == null || entrada.getBodyIn().getParametros() == null) {
            return false;
        }
        if (entrada.getBodyIn() != null && entrada.getBodyIn().getParametros() != null) {
            for (LiquidacionDTO liq : entrada.getBodyIn().getParametros().values()) {
                if (liq.getDocumentos() != null) {
                    for (DocumentoDTO doc : liq.getDocumentos()) {
                        if (doc == null || doc.getData() == null) {
                            estado = false;
                            break;
                        }
                    }
                }
            }
        }
        return estado;
    }

    /**
     * Crea la entrada a partir de la consulta del servicio
     *
     * @param bp
     * @return
     */
    public EntradaLiquidacion getEntrada(FormDataBodyPart bp) throws DominioExcepcion {
        EntradaLiquidacion entrada = null;
        InputStream in = bp.getValueAs(InputStream.class);
        if (in != null) {
            try {
                String json = new String(in.readAllBytes());
                ObjectMapper maper = new ObjectMapper();
                maper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
                entrada = maper.readValue(json, EntradaLiquidacion.class);
            } catch (IOException ex) {
                throw new DominioExcepcion(ErrorTipo.ERROR, CodigoRespuesta.CODIGO_VALOR_NULO, "No es posible convertir el JSON " + ex.toString());
            }
        }
        System.out.println("CREO ENTRADA... " + entrada);
        return entrada;
    }

}
