package mx.com.amx.mx.dda.crn.bo;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.ws.WebServiceException;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.client.SoapFaultClientException;

import com.americamovil.dda._1.f.enviaactivofijo.DTActivoFijo;
import com.americamovil.dda._1.f.enviaactivofijo.DTActivoFijoRes;
import com.americamovil.dda._1.f.enviacontenido.DTContenido;
import com.americamovil.dda._1.f.enviacontenido.DTContenidoRes;
import com.americamovil.dda._1.f.enviaterminoscomerciales.DTTerminosComerciales;
import com.americamovil.dda._1.f.enviaterminoscomerciales.DTTerminosComercialesRes;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import mx.com.amx.mx.dda.crn.dao.DDAExhibicionDAO;
import mx.com.amx.mx.dda.crn.dto.ContratoDTO;
import mx.com.amx.mx.dda.crn.dto.ContratoPagoDTO;
import mx.com.amx.mx.dda.crn.dto.ContratoTituloDTO;
import mx.com.amx.mx.dda.crn.dto.DatosCntTituloExhibicionDTO;
import mx.com.amx.mx.dda.crn.dto.ItemActivoFijoDTO;
import mx.com.amx.mx.dda.crn.dto.ParamActivoFijoDTO;
import mx.com.amx.mx.dda.crn.dto.ParametroDTO;
import mx.com.amx.mx.dda.crn.dto.RespSAPActivoFijoDTO;
import mx.com.amx.mx.dda.crn.dto.RespSAPNotificaAFijoDTO;
import mx.com.amx.mx.dda.crn.dto.ResponseOrdenCompraDTO;
import mx.com.amx.mx.dda.crn.dto.ResultadoCrearActivoFijoDTO;
import mx.com.amx.mx.dda.crn.dto.ResultadoNotificacionDTO;
import mx.com.amx.mx.dda.crn.dto.StringManager;
import mx.com.amx.mx.dda.crn.dto.TransactionFaultDTO;
import mx.com.amx.mx.dda.crn.utils.DateManager;

public class DDAExhibicionBO {

    private final Logger LOG = Logger.getLogger(this.getClass().getSimpleName());
    private final String ARCHIVO_PROPIEDADES = "/general.properties";
    private final String TEN = "10";
    private final String TERMINOS = "99";
    private final String TWELVE = "12";
    private final String OK = "OK";
    Properties env = new Properties();
    DateManager dateManager = new DateManager();
    StringManager strManager = new StringManager();

    @Autowired
    @Qualifier("wsNotificaAFijoSAP")
    private WebServiceTemplate wsNotificaAFijoSAP;

    private DDAExhibicionDAO dao;

    private String AMBIENTE;
    private String SERVIDOR;
    private String PUERTO;
    private String COMPONENTE;
    private String ERROR_COMUNICACION_SAP;
    private String ERROR_INTERNO_SAP;
    private String ERROR_PROCESO;
    private String ERROR_REGISTRO_SAP;
    private String FECHA_TEST;
    private String IDENTIFICADOR;

    public DDAExhibicionBO() {
        super();
        try {
            env.load(this.getClass().getResourceAsStream(ARCHIVO_PROPIEDADES));
            AMBIENTE = env.getProperty("ambiente");
            SERVIDOR = env.getProperty(AMBIENTE + ".servidor.sap.ws");
            PUERTO = env.getProperty(AMBIENTE + ".puerto.sap.ws");
            COMPONENTE = "DDA_CRN_Exhibicion::" + this.getClass().getSimpleName();
            ERROR_COMUNICACION_SAP = env.getProperty("error.comunicacion.sap");
            ERROR_INTERNO_SAP = env.getProperty("error.interno.sap");
            ERROR_PROCESO = env.getProperty("error.proceso");
            FECHA_TEST = env.getProperty("fecha.test");
            IDENTIFICADOR = env.getProperty("identificador.sap");
        } catch (IOException e) {
            LOG.error(">Constructor[" + this.getClass().getSimpleName() + "] Ocurrio un error : " + e.getMessage());
        }
    }

    public boolean existeProcesoNotificacionEjecutandose() throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::existeProcesoNotificacionEjecutandose]");
        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.verificaEjecutandoseProcesoNotificacion();
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::existeProcesoNotificacionEjecutandose]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return resultado;
    }

    public boolean verificaPuedeIniciar() throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::verificaPuedeIniciar]");

        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.puedeIniciarProcesoNotificacion();

        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::verificaPuedeIniciar]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return resultado;
    }

    public boolean actualizarEjecutandoProcesoNotificacion(String pstValor) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::actualizarEjecutandoProcesoNotificacion]");
        LOG.debug("    - Parametros: _" + pstValor + "_");

        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.updateEjecutandoseProcesoNotificacion(pstValor);
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::actualizarEjecutandoProcesoNotificacion]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return resultado;
    }

    public String getValorDiaNotificacion() throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::getValorDiaNotificacion]");

        String lstResultado = "-1";
        List<ParametroDTO> lobValores = dao.getValorDiaNotificacion();

        if (Objects.nonNull(lobValores) && !lobValores.isEmpty()) {
            lstResultado = lobValores.get(0).getVALOR();
        }

        return lstResultado;
    }

    public String obtenerFechaReferencia(String pstValorReferencia) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::obtenerFechaReferencia]");
        LOG.debug("    - Parametros: _" + pstValorReferencia + "_");

        String lstResultado = "";

        //-- Se adquiere la ideologia de que la fecha de referencia ya no sera calculada y sera tomada la fecha actual.
        //-- Se implementa la funcionalidad para tomar una fecha proporcionada manualmente con motivo de pruebas.
        try {

            if (FECHA_TEST.equalsIgnoreCase("VACIO")) {
                lstResultado = dateManager.getFechaActual("dd/mm/yyyy");
            } else {
                lstResultado = FECHA_TEST;
            }

        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::obtenerFechaReferencia]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return lstResultado;

    }

    public ResponseOrdenCompraDTO creacionTitulosSAP(String pstFechaReferencia, String contratosId) throws Exception {
        LOG.debug("        - [" + this.getClass().getSimpleName() + "::creacionTitulosSAP]");
        ResponseOrdenCompraDTO resultado = new ResponseOrdenCompraDTO();
        int lnuTotalRegOCSAP_OK = 0;
        int lnuTotalRegOCSAP_NOOK = 0;
        int lnuTotalUpdIdSAP_OK = 0;
        int lnuTotalUpdIdSAP_NOOK = 0;

        try {
            //-- Consulta de titulos sin ID de SAP que esten en estatus de Recien Exhibido (Fecha inicio <= hoy)
            LOG.info("        [INI]. Consulta de Titulos sin ID SAP Recien Exhibidos.");
            List<ItemActivoFijoDTO> lobTitulosCnt = dao.obtenerTitulosSinIdSAP_RecienExhibidos(pstFechaReferencia, contratosId);
            List<ItemActivoFijoDTO> lobContratosCnt = dao.obtenerContratosConTitulosSinIdSAP_RecienExhibidos(pstFechaReferencia, contratosId);
            LOG.info("        [FIN]. Consulta de Titulos sin ID SAP Recien Exhibidos. Titulos:_" + lobTitulosCnt.size() + "_");

            if (Objects.nonNull(lobTitulosCnt) && !lobTitulosCnt.isEmpty()) {
                ParamActivoFijoDTO afDTO = new ParamActivoFijoDTO();
                afDTO.setTitulos(lobTitulosCnt);
                afDTO.setContratos(lobContratosCnt);

                //--Llamado al WS SAP para registrar los Activos Fijos (Titulos)
                LOG.info("        [INI]. Llamado a WS SAP. Interfaz 10.");
                ResultadoCrearActivoFijoDTO rWS_AFijo = this.crearActivoFijoWS(afDTO);
                LOG.info("        [FIN]. Llamado a WS SAP. Interfaz 10. Resultado: _" + rWS_AFijo.getResultado() + "_");

                //--Verifica si se genero alguna excepcion en el llamado a Activos Fijos
                if (Objects.nonNull(rWS_AFijo.getActivosFijos()) && rWS_AFijo.getResultado()){
                    //-- Verifica que los enviados sean igual a los registrados por parte de SAP
                    //-- Si se enviaron 3, mismos 3 que debería regresar
                    if (rWS_AFijo.getActivosFijos().size() == afDTO.getTitulos().size()) {
                        //-- Recorrer la respuesta en busqueda de los titulos registrados en SAP correctamente
                        for (RespSAPActivoFijoDTO activoFijo : rWS_AFijo.getActivosFijos()) {
                            if (activoFijo.getExcepcion().equalsIgnoreCase(OK)) {
                                lnuTotalRegOCSAP_OK++;
                                
                                //-- Actualiza el titulo con el ID SAP
                                LOG.info("        [INI]. Actualiza titulo [" + activoFijo.getID_DDA() + "] con ID de SAP [" + activoFijo.getID_SAP() + "].");
                                boolean lboActTituloIDSAP = dao.actualizaIdSAPCntTitulo(activoFijo);
                                LOG.info("        [FIN]. Actualiza titulo [" + activoFijo.getID_DDA() + "] con ID de SAP [" + activoFijo.getID_SAP() + "]. Resultado: _" + lboActTituloIDSAP + "_");

                                if (lboActTituloIDSAP) {
                                    lnuTotalUpdIdSAP_OK++;
                                } else {
                                    lnuTotalUpdIdSAP_NOOK++;
                                }
                            } else {
                                lnuTotalRegOCSAP_NOOK++;
                            }
                        }

                        //--Construye respuesta
                        resultado.setResultado(Boolean.TRUE);
                        resultado.setMensaje(OK);
                        resultado.setLnuTotalRegOCSAP_Envio(lobTitulosCnt.size());
                        resultado.setLnuTotalRegOCSAP_Regreso(rWS_AFijo.getActivosFijos().size());
                        resultado.setLnuTotalRegOCSAP_OK(lnuTotalRegOCSAP_OK);
                        resultado.setLnuTotalRegOCSAP_NOOK(lnuTotalRegOCSAP_NOOK);
                        resultado.setLnuTotalUpdIdSAP_OK(lnuTotalUpdIdSAP_OK);
                        resultado.setLnuTotalUpdIdSAP_NOOK(lnuTotalUpdIdSAP_NOOK);
                        resultado.setTitulos(lobTitulosCnt);
                    } else {
                        //--Construye Respuesta
                        resultado.setResultado(Boolean.FALSE);
                        resultado.setMensaje("DDA-AF-005: " + ERROR_REGISTRO_SAP);
                    }
                } else if (Objects.nonNull(rWS_AFijo.getTransFault())) {
                    //-- Tracking
                    LOG.error("        Error al llamar el WS Envia Activo Fijo:: creacionTitulosSAP: " + rWS_AFijo.getTransFault().toString());

                    //--Construccion de respuesta
                    resultado.setResultado(Boolean.FALSE);
                    resultado.setMensaje(rWS_AFijo.getTransFault().getInternalCode() + ": " + rWS_AFijo.getTransFault().getFaultDescription());
                }//Ends if(rWS_AFijo.getActivosFijos() != null && rWS_AFijo.getResultado())

            }//Ends if(lobTitulosCnt != null && lobTitulosCnt.size() > 0)
            else {
                //--Envia resultado
                resultado.setMensaje("No se encontraron titulos sin Id SAP recien exhibidos.");
                resultado.setResultado(Boolean.FALSE);
                LOG.info("[" + this.getClass().getSimpleName() + "::creacionTitulosSAP] ");
            }
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::creacionTitulosSAP]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return resultado;
    }

    private ResultadoCrearActivoFijoDTO crearActivoFijoWS(ParamActivoFijoDTO dto) {
        ResultadoCrearActivoFijoDTO resultado = new ResultadoCrearActivoFijoDTO();
        TransactionFaultDTO tf = resultado.getTransFault();
        List<RespSAPActivoFijoDTO> afs = resultado.getActivosFijos();
        String method = "crearActivoFijoWS";
        Map<String,String> contratosIdSap = new HashMap<>();
        try {
            DTActivoFijo params = new DTActivoFijo();

            for (ItemActivoFijoDTO titulo : dto.getContratos()) {
                String idSap = dao.validarIdSap(titulo.getContratoDDA());
                if(idSap.isEmpty()){
                    DTActivoFijo.Registro tituloAF = new DTActivoFijo.Registro();
                    tituloAF.setCentroCoste((Objects.nonNull(titulo.getCentroCosto()) && !titulo.getCentroCosto().isEmpty()) ? titulo.getCentroCosto() : "");
                    tituloAF.setCodigoDDA((Objects.nonNull(titulo.getCodigoDDA()) && !titulo.getCodigoDDA().isEmpty()) ? titulo.getCodigoDDA() : "");
                    tituloAF.setDescripcion(strManager.extraerPrimerosCaracteres(
                            (Objects.nonNull(titulo.getDescripcion())&& !titulo.getDescripcion().isEmpty()) ? titulo.getDescripcion() : "", 45));
                    tituloAF.setOrdenCompra((Objects.nonNull(titulo.getOrdenCompra()) && !titulo.getOrdenCompra().isEmpty()) ? titulo.getOrdenCompra() : "");
                    tituloAF.setProveedor((Objects.nonNull(titulo.getProveedor()) && !titulo.getProveedor().isEmpty()) ? titulo.getProveedor() : "");
                    tituloAF.setProgramID((Objects.nonNull(titulo.getProgramID()) && !titulo.getProgramID().isEmpty()) ? titulo.getProgramID() : "");
                    tituloAF.setContratoDDA((Objects.nonNull(titulo.getContratoDDA()) && !titulo.getContratoDDA().isEmpty()) ? titulo.getContratoDDA() : "" );
                    tituloAF.setInicioAmortizacion((Objects.nonNull(titulo.getInicioAmortizacion()) && !titulo.getInicioAmortizacion().isEmpty()) ? titulo.getInicioAmortizacion() : "" );
                    params.getRegistro().add(tituloAF);
                } else{
                    contratosIdSap.put(titulo.getContratoDDA(), idSap);
                }
            }

            //--Llamado al WS de SAP. Interfaz 10.
            LOG.debug("        Url Srv. Activo Fijo primer llamado: " + this.getUrlServicio(TEN));
            DTActivoFijoRes responseActivoFijo = null;
            if(params.getRegistro().size() > 0){
                responseActivoFijo = (DTActivoFijoRes) wsNotificaAFijoSAP.marshalSendAndReceive(this.getUrlServicio(TEN), params);
            }

            if (!contratosIdSap.isEmpty() || (Objects.nonNull(responseActivoFijo) && Objects.nonNull(responseActivoFijo.getRespuesta()) && !responseActivoFijo.getRespuesta().isEmpty())) {
                int lnuTitulosActualizados = responseActivoFijo.getRespuesta().size();
                LOG.info("    Total titulos procesados SAP primer llamado: " + lnuTitulosActualizados);
                
                LOG.info(" ");
                LOG.info("        [INI] Detalle respuesta devuelta por SAP [CrearActivoFijo] primer llamado:");
                for (DTActivoFijoRes.Respuesta respuesta : responseActivoFijo.getRespuesta()) {
                    LOG.info("IDDDA devuelto por sap: " + respuesta.getIDDDA());
                   for (DTActivoFijo.Registro registro : params.getRegistro()){
                       if (respuesta.getIDDDA().equals(registro.getCodigoDDA())){
                           LOG.info("IDDDA devuelto por sap: " + respuesta.getIDDDA() + " codigo DDA en parametros: " + registro.getCodigoDDA());
                           registro.setCodigoSAP((Objects.nonNull(respuesta.getIDSAP()) && !respuesta.getIDSAP().isEmpty()) ? respuesta.getIDSAP() : "");
                       }
                       actualizarEstatusSapTitulosContrato("PRIMER LLAMADO: " + respuesta.getExcepcion(), registro.getContratoDDA());
                   }
                }
                DTActivoFijo paramsSeg = new DTActivoFijo();
                for (ItemActivoFijoDTO titulo : dto.getTitulos()) {
                    DTActivoFijo.Registro tituloAF = new DTActivoFijo.Registro();
                    tituloAF.setCentroCoste((Objects.nonNull(titulo.getCentroCosto()) && !titulo.getCentroCosto().isEmpty()) ? titulo.getCentroCosto() : "");
                    tituloAF.setCodigoDDA((Objects.nonNull(titulo.getCodigoDDA()) && !titulo.getCodigoDDA().isEmpty()) ? titulo.getCodigoDDA() : "");
                    tituloAF.setDescripcion(strManager.extraerPrimerosCaracteres(
                            (Objects.nonNull(titulo.getDescripcion())&& !titulo.getDescripcion().isEmpty()) ? titulo.getDescripcion() : "", 45));
                    tituloAF.setOrdenCompra((Objects.nonNull(titulo.getOrdenCompra()) && !titulo.getOrdenCompra().isEmpty()) ? titulo.getOrdenCompra() : "");
                    tituloAF.setProveedor((Objects.nonNull(titulo.getProveedor()) && !titulo.getProveedor().isEmpty()) ? titulo.getProveedor() : "");
                    tituloAF.setProgramID((Objects.nonNull(titulo.getProgramID()) && !titulo.getProgramID().isEmpty()) ? titulo.getProgramID() : "");
                    tituloAF.setContratoDDA((Objects.nonNull(titulo.getContratoDDA()) && !titulo.getContratoDDA().isEmpty()) ? titulo.getContratoDDA() : "" );
                    tituloAF.setInicioAmortizacion((Objects.nonNull(titulo.getInicioAmortizacion()) && !titulo.getInicioAmortizacion().isEmpty()) ? titulo.getInicioAmortizacion() : "" );
                    if(Objects.nonNull(contratosIdSap.get(tituloAF.getContratoDDA()))){
                        tituloAF.setCodigoSAP((contratosIdSap.get(tituloAF.getContratoDDA())));
                    } else {
                        for (DTActivoFijo.Registro registro : params.getRegistro()){
                            if (tituloAF.getContratoDDA().equals(registro.getContratoDDA())){
                               tituloAF.setCodigoSAP((Objects.nonNull(registro.getCodigoSAP()) && !registro.getCodigoSAP().isEmpty()) ? registro.getCodigoSAP() : "");
                           }
                        }
                    }
                    paramsSeg.getRegistro().add(tituloAF);
                }
                
                LOG.info("        [FIN] Detalle respuesta devuelta por SAP [CrearActivoFijo]primer llamado:");
                LOG.info(" ");
                
                LOG.debug("        Url Srv. Activo Fijo primer llamado segundo llamado: " + this.getUrlServicio(TEN));
                responseActivoFijo = (DTActivoFijoRes) wsNotificaAFijoSAP.marshalSendAndReceive(this.getUrlServicio(TEN), paramsSeg);
                
                LOG.info(" ");
                LOG.info("        [INI] Detalle respuesta devuelta por SAP [CrearActivoFijo] segundo llamado:");
                for (DTActivoFijoRes.Respuesta respuesta : responseActivoFijo.getRespuesta()) {
                    RespSAPActivoFijoDTO respActivoFijo = new RespSAPActivoFijoDTO();
                    respActivoFijo.setID_DDA(respuesta.getIDDDA());
                    respActivoFijo.setID_SAP(respuesta.getIDSAP());
                    respActivoFijo.setSUBNUMERO(respuesta.getSubNumero());
                    respActivoFijo.setExcepcion(respuesta.getExcepcion());
                    LOG.info("        <IDDDA:[" + respuesta.getIDDDA() + "], IDSAP:[" + respuesta.getIDSAP() + "], Excepcion:["
                            + respuesta.getExcepcion() + "]>");
                    afs.add(respActivoFijo);
                    dao.actualizarEstatusSapTitulosByTitulo("SEGUNDO LLAMADO: " + respuesta.getExcepcion(), respuesta.getIDDDA());
                }
                LOG.info("        [FIN] Detalle respuesta devuelta por SAP [CrearActivoFijo] segundo llamado:");
                LOG.info(" ");

                resultado.setResultado(Boolean.TRUE);
            } else {
                for (ItemActivoFijoDTO titulo : dto.getContratos()) {
                    writeResponse(tf, "DDA-AF-004", ERROR_COMUNICACION_SAP, "El servicio web se ejecuto, pero la respuesta es NULL", method, titulo.getContratoDDA());
                }
                resultado.setResultado(Boolean.FALSE);
            }

            return resultado;

        } catch (WebServiceException c) {
            for (ItemActivoFijoDTO titulo : dto.getContratos()) {
                writeResponse(tf, "DDA-AF-001", ERROR_COMUNICACION_SAP, c.getMessage(), method, titulo.getContratoDDA());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        } catch (SoapFaultClientException se) {
            for (ItemActivoFijoDTO titulo : dto.getContratos()) {
                writeResponse(tf, "DDA-AF-002", ERROR_INTERNO_SAP, se.getMessage(), method, titulo.getContratoDDA());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        } catch (Exception e) {
            for (ItemActivoFijoDTO titulo : dto.getContratos()) {
                writeResponse(tf, "DDA-AF-002", ERROR_PROCESO, e.getMessage(), method, titulo.getContratoDDA());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        }
    }
    
    private void writeResponse(TransactionFaultDTO tf, String intCode, String faultDesc, String message, String method, String idtituloCnt){
        tf.setInternalCode(intCode);
        tf.setComponent(COMPONENTE);
        tf.setFaultDescription(faultDesc);
        tf.setFaultMessage(message);
        tf.setMethod(method);
        dao.actualizarEstatusSapTitulosByTitulo(faultDesc, idtituloCnt);
    }
    
    public Map<String,String> ejecutarTerminosComerciales( List<DatosCntTituloExhibicionDTO> titulos, String contratosId ){
        //--Llamado al WS de SAP. Interfaz 99. Terminos Comerciales
            LOG.info("        Url Srv. Activo Fijo primer llamado: " + this.getUrlServicio(TERMINOS));
            Map<String,String> validaciones = new HashMap<>();
        try {
            Map<String,DatosCntTituloExhibicionDTO> map = new HashMap<>();
            LOG.info("        Entrando try: "  );
            for(DatosCntTituloExhibicionDTO titulo : titulos){
                if (Objects.isNull(map.get(titulo.getNUMERO_CONTRATO()))){
                    map.put(titulo.getNUMERO_CONTRATO(), new DatosCntTituloExhibicionDTO());
                    map.get(titulo.getNUMERO_CONTRATO()).setCOSTO(titulo.getCOSTO());
                } else {
                    Long suma = Long.parseLong(map.get(titulo.getNUMERO_CONTRATO()).getCOSTO()) + Long.parseLong(titulo.getCOSTO());
                    map.get(titulo.getNUMERO_CONTRATO()).setCOSTO(suma.toString());
                }
            }
            List<ContratoDTO> contratos = dao.obtenerContratos(contratosId);
            LOG.info("        Contratos encontrado: " + contratos.size() );
            for(ContratoDTO contrato : contratos){
                if (Objects.nonNull(map.get(contrato.getContratoDDA()))){
                    DTTerminosComerciales params = new DTTerminosComerciales();
                    params.setContratoDDA(contrato.getContratoDDA());
                    params.setOrdenCompra(contrato.getOrdenCompra());
                    params.setIdentificadorInt(IDENTIFICADOR);
                    LOG.info("        Se envia contrato: " + contrato.getContratoDDA() + " con orden de compra: " + contrato.getOrdenCompra() + " e identificador: " + IDENTIFICADOR);
                    List<ContratoPagoDTO> pagos = dao.obtenerCondicionesComerciales(contrato.getIdcontratoDDA());
                    List<ContratoPagoDTO> anticipo = dao.obtenerAnticipo(contrato.getIdcontratoDDA());
                    if(Objects.isNull(pagos) || pagos.isEmpty()){
                        if(Objects.nonNull(anticipo) && Objects.nonNull(anticipo.get(0).getMonto()) && !anticipo.get(0).getMonto().isEmpty()){
                            DTTerminosComerciales.Condicionescomerciales condicion = new DTTerminosComerciales.Condicionescomerciales();
                            condicion.setValorcondicion(anticipo.get(0).getMonto());
                            condicion.setFechavencimiento(anticipo.get(0).getFecha());
                            params.getCondicionescomerciales().add(condicion);
                            Double total = Double.parseDouble(map.get(contrato.getContratoDDA()).getCOSTO()) - (Double.parseDouble(anticipo.get(0).getMonto()));
                            if(total > 0){
                                DTTerminosComerciales.Condicionescomerciales ant = new DTTerminosComerciales.Condicionescomerciales();
                                ant.setValorcondicion(total.toString());
                                ant.setFechavencimiento(contrato.getFechavencimiento());
                                params.getCondicionescomerciales().add(ant);
                            }
                        } else {
                            DTTerminosComerciales.Condicionescomerciales condicion = new DTTerminosComerciales.Condicionescomerciales();
                            condicion.setValorcondicion(map.get(contrato.getContratoDDA()).getCOSTO());
                            condicion.setFechavencimiento(contrato.getFechavencimiento());
                            params.getCondicionescomerciales().add(condicion);
                        }
                        
                    } else {
                        if(Objects.nonNull(anticipo) && Objects.nonNull(anticipo.get(0).getMonto()) && !anticipo.get(0).getMonto().isEmpty()){
                            DTTerminosComerciales.Condicionescomerciales ant = new DTTerminosComerciales.Condicionescomerciales();
                            ant.setValorcondicion(anticipo.get(0).getMonto());
                            ant.setFechavencimiento(anticipo.get(0).getFecha());
                            params.getCondicionescomerciales().add(ant);
                        }
                        for(ContratoPagoDTO pago : pagos){
                            DTTerminosComerciales.Condicionescomerciales condicion = new DTTerminosComerciales.Condicionescomerciales();
                            condicion.setValorcondicion(pago.getMonto());
                            condicion.setFechavencimiento(pago.getFecha());
                            params.getCondicionescomerciales().add(condicion);
                        }
                    }
                    DTTerminosComercialesRes response = (DTTerminosComercialesRes) wsNotificaAFijoSAP.marshalSendAndReceive(this.getUrlServicio(TERMINOS), params);
                    if(!response.getESTPROC().equals("OK")){
                        LOG.info("        Fallo el contrato " + contrato.getContratoDDA() + " al enviarlo a " + this.getUrlServicio(TERMINOS) + " se daran de baja los titulos en la BD.");
                        //respuesta = response.getEstatus();
                        validaciones.put(contrato.getContratoDDA(), response.getEstatus());
                    } else {
                        LOG.info("        Respuesta OK del servicio ESTPROC: " + response.getESTPROC() + " con Estatus: " + response.getEstatus());
                        validaciones.put(contrato.getContratoDDA(), response.getESTPROC());
                    }
                }
            }
        } catch (Exception ex) {
            LOG.info("        Prueba SAP erronea: " + ex.getMessage());
            LOG.info(ex);
            ex.printStackTrace();
            java.util.logging.Logger.getLogger(DDAExhibicionBO.class.getName()).log(Level.SEVERE, null, ex);
            //respuesta = "ERROR DE PROCESO";
        }
        return validaciones;
    }

    public List<DatosCntTituloExhibicionDTO> obtenerContratosRecienExhibidos(String pstFechaReferencia, String contratosId) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::obtenerContratosRecienExhibidos]");
        LOG.debug("    - Parametros: _" + pstFechaReferencia + "_");

        List<DatosCntTituloExhibicionDTO> lobResultado = new ArrayList<>();

        try {
            lobResultado = dao.obtenerTitulosRecienExhibidos(pstFechaReferencia, contratosId);
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::obtenerFechaReferencia]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return lobResultado;
    }
    
    public List<DatosCntTituloExhibicionDTO> obtenerTitulosRecienExhibidos(String pstFechaReferencia, String contratosId) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::obtenerTitulosRecienExhibidos]");
        LOG.debug("    - Parametros: _" + pstFechaReferencia + "_");

        List<DatosCntTituloExhibicionDTO> lobResultado = new ArrayList<>();

        try {
            lobResultado = dao.obtenerTitulosRecienExhibidos(pstFechaReferencia, contratosId);
            Collections.sort(lobResultado,  new Comparator<DatosCntTituloExhibicionDTO> (){
                @Override
                public int compare(DatosCntTituloExhibicionDTO d1, DatosCntTituloExhibicionDTO d2){
                    return d1.getID_SAP().compareTo(d2.getID_SAP());
                }
            });
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::obtenerFechaReferencia]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return lobResultado;
    }

    public ResultadoNotificacionDTO notificarAFijoWS(List<DatosCntTituloExhibicionDTO> dto, Map<String,String> respuestaTC) {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::notificarAFijoWS]");
        LOG.debug("    - Parametros: _" + dto.size() + " Titulos._");

        ResultadoNotificacionDTO resultado = new ResultadoNotificacionDTO();
        TransactionFaultDTO tf = resultado.getTransFault();
        List<RespSAPNotificaAFijoDTO> not = resultado.getNotificaciones();
        Map<String, List<RespSAPNotificaAFijoDTO>> mapNot = new HashMap<>();
        String method = "notificarAFijoWS";
        try {
            DTContenido params = new DTContenido();
            int xNotifica = 1;
            for (DatosCntTituloExhibicionDTO dtoEx : dto) {
                if(respuestaTC.get(dtoEx.getNUMERO_CONTRATO()).equals("OK")){
                    String lstCodigoSAP = (Objects.nonNull(dtoEx.getID_SAP()) && !dtoEx.getID_SAP().trim().isEmpty()) ? dtoEx.getID_SAP() : "";
                    String lstFechaContabilizacionBD = (Objects.nonNull(dtoEx.getFECHA_CONTABILIZACION()) && !dtoEx.getFECHA_CONTABILIZACION().trim().isEmpty()) ? dtoEx.getFECHA_CONTABILIZACION() : "";
                    String lstFechaInicio = (Objects.nonNull(dtoEx.getFECHA_INICIO()) && !dtoEx.getFECHA_INICIO().trim().isEmpty()) ? dtoEx.getFECHA_INICIO() : "";
                    String lstValor = (Objects.nonNull(dtoEx.getCOSTO()) && !dtoEx.getCOSTO().trim().isEmpty()) ? dtoEx.getCOSTO() : "";
                    String lstVidaUtil = (Objects.nonNull(dtoEx.getVIDA_UTIL()) && !dtoEx.getVIDA_UTIL().trim().isEmpty()) ? dtoEx.getVIDA_UTIL() : "";
                    String lstIdTituloCntOrig = (Objects.nonNull(dtoEx.getID_TITULO_CNTORIG()) && !dtoEx.getID_TITULO_CNTORIG().trim().isEmpty()) ? dtoEx.getID_TITULO_CNTORIG() : "";
                    String lstSubNumero = (Objects.nonNull(dtoEx.getSUBNUMERO()) && !dtoEx.getSUBNUMERO().trim().isEmpty()) ? dtoEx.getSUBNUMERO() : "";
                    String lstVUAA = "";
                    String lstVUMM = "";

                    if (lstVidaUtil.length() == 4) {
                        lstVUAA = lstVidaUtil.substring(0, 2);
                        lstVUMM = lstVidaUtil.substring(2);
                    }

                    LOG.info("            <Registro: [" + xNotifica++ + "], IdTituloCnt:[" + lstIdTituloCntOrig + "],CodigoSAP:[" + lstCodigoSAP + "],FechaContabilizacion:[" + lstFechaContabilizacionBD + "], FechaInicio:[" + lstFechaInicio + "], Valor:[" + lstValor + "], VU:[" + lstVidaUtil + "]>, vuAA:[" + lstVUAA + "], vuMM[" + lstVUMM + "]");

                    //--Determinacion de la fecha de contabilizacion con referencia a la fecha actual
                    String lstFechaContabilizacion = dateManager.obtenerFechaMayorVsActual(lstFechaContabilizacionBD, "yyyyMMdd");
                    LOG.debug("Fecha contabilización: [" + lstFechaContabilizacion + "]");

                    DTContenido.Registro titulo = new DTContenido.Registro();
                    titulo.setCodigoSAP(lstCodigoSAP);
                    titulo.setFechaContabilizacion(lstFechaContabilizacion);
                    titulo.setFechaInicio(lstFechaInicio);
                    if (Integer.parseInt(lstSubNumero) == 0){
                        titulo.setValor("1");
                    } else {
                        titulo.setValor(lstValor);
                    }
                    titulo.setVUAA(lstVUAA);
                    titulo.setVUMM(lstVUMM);
                    titulo.setSubNumero(lstSubNumero);
                    params.getRegistro().add(titulo);
                }
                else {
                    LOG.error("DDA-NOT-012: Falla en terminos comerciales.");
                    dao.actualizarEstatusSapTitulosByTitulo(respuestaTC.get(dtoEx.getNUMERO_CONTRATO()), dtoEx.getID_TITULO_CNTORIG());
                }
            }

            //--Llamado a WS de SAP. Interfaz 12
            LOG.debug("    Url Srv. Notifica Activo Fijo: " + this.getUrlServicio(TWELVE));

            //-- REAL CODE
            DTContenidoRes responseNotifica = null;
            resultado.setTitulosEnviados(params.getRegistro().size());
            if(!params.getRegistro().isEmpty()){
                responseNotifica = (DTContenidoRes) wsNotificaAFijoSAP.marshalSendAndReceive(this.getUrlServicio(TWELVE), params);
            }
            
            if (Objects.nonNull(responseNotifica) && Objects.nonNull(responseNotifica.getRespuesta()) && !responseNotifica.getRespuesta().isEmpty()) {
                int lnuTitulosNotificados = responseNotifica.getRespuesta().size();
                LOG.info("Total titulos devueltos por SAP [Notificados]: " + lnuTitulosNotificados);

                LOG.info(" ");
                LOG.info("    [INI] Detalle respuesta devuelta por SAP [Notificados]:");
                for (DTContenidoRes.Respuesta respuesta : responseNotifica.getRespuesta()) {
                    RespSAPNotificaAFijoDTO respNotificaAFijo = new RespSAPNotificaAFijoDTO();
                    respNotificaAFijo.setCodigoDDA(respuesta.getCodigoDDA());
                    respNotificaAFijo.setStatus(respuesta.getStatus());
                    respNotificaAFijo.setMensaje(respuesta.getMensaje());
                    LOG.info("        <CodigoDDA:[" + respuesta.getCodigoDDA() + "], Status:[" + respuesta.getStatus() + "], Mensaje:[" + respuesta.getMensaje() + "]>");
                    if(Objects.isNull(mapNot.get(respuesta.getCodigoDDA()))){
                        not.add(respNotificaAFijo);
                        mapNot.put(respuesta.getCodigoDDA(), new ArrayList());
                    }
                    if(respuesta.getStatus().equals("OK")){
                        dao.actualizarEstatusSapTitulosByTitulo(respuesta.getStatus(), respuesta.getCodigoDDA());
                    }
                    else{
                        dao.actualizarEstatusSapTitulosByTitulo(respuesta.getMensaje(), respuesta.getCodigoDDA());
                    }
                }
                LOG.info("    [FIN] Detalle respuesta devuelta por SAP [Notificados]:");
                LOG.info(" ");

                resultado.setResultado(Boolean.TRUE);
            } else {
                for (DatosCntTituloExhibicionDTO dtoEx : dto) {
                    writeResponse(tf, "DDA-AF-010", ERROR_COMUNICACION_SAP, "El servicio web se ejecuto, pero la respuesta es NULL", method, dtoEx.getID_TITULO_CNTORIG());
                }
                resultado.setResultado(Boolean.FALSE);
            }

            return resultado;

        } catch (WebServiceException c) {
            for (DatosCntTituloExhibicionDTO dtoEx : dto) {
                writeResponse(tf, "DDA-AF-007", ERROR_COMUNICACION_SAP, c.getMessage(), method, dtoEx.getID_TITULO_CNTORIG());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        } catch (SoapFaultClientException se) {
            for (DatosCntTituloExhibicionDTO dtoEx : dto) {
                writeResponse(tf, "DDA-AF-008", ERROR_INTERNO_SAP, se.getMessage(), method, dtoEx.getID_TITULO_CNTORIG());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        } catch (Exception e) {
            for (DatosCntTituloExhibicionDTO dtoEx : dto) {
                writeResponse(tf, "DDA-AF-009", ERROR_PROCESO, e.getMessage(), method, dtoEx.getID_TITULO_CNTORIG());
            }
            resultado.setResultado(Boolean.FALSE);
            return resultado;
        }

    }

    public boolean actualizaFechaNotificacion(ContratoTituloDTO dto) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::actualizaFechaNotificacion]");
        //LOG.debug("    - Parametros: _" + dto.toString()+"_");

        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.actualizaFechaNotificacion(dto);
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::actualizaFechaNotificacion]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }

        return resultado;
    }

    public boolean insertarRegistroSubNumero(String pstIdTituloCntOrig) throws Exception {
        LOG.debug("    - [" + this.getClass().getSimpleName() + "::insertarRegistroSubNumero]");
        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.insertarRegistroSubnum(pstIdTituloCntOrig);
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::insertarRegistroSubNumero]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }
        return resultado;
    }

    private String getUrlServicio(String pNumInterfaz) {
        String urlServicio = env.getProperty(AMBIENTE + ".clientws.interface.i" + pNumInterfaz).replaceAll("%servidor%", SERVIDOR).replaceAll("%puerto%", PUERTO);
        return urlServicio;
    }

    public DDAExhibicionDAO getDao() {
        return dao;
    }

    public void setDao(DDAExhibicionDAO dao) {
        this.dao = dao;
    }

    public boolean ejecutarSPAmortizacionReal() throws Exception {

        LOG.debug("    - [" + this.getClass().getSimpleName() + "::ejecutarSPAmortizacionReal]");

        boolean resultado = Boolean.FALSE;
        try {
            resultado = dao.ejecutarSPAmortizacionReal();
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::ejecutarSPAmortizacionReal]: " + e.getMessage());
            throw new Exception(e.getMessage());
        }
        return resultado;
    }
    
    public List<ContratoDTO> contratosCandidatos(String contratosId){
         LOG.debug("    - [" + this.getClass().getSimpleName() + "::contratosCandidatos]");
        List<ContratoDTO> resultado = null;
        try {
            resultado = dao.obtenerContratosCandidatos(contratosId);
        } catch (Exception e) {
            LOG.error("Exception[" + this.getClass().getSimpleName() + "::contratosCandidatos]: " + e.getMessage());
        }
        return resultado;
    }
    
    public void actualizarEstatusSapTitulosContrato(String mensaje, String idContrato){
            LOG.debug("    - ["+this.getClass().getSimpleName()+"::actualizarEstatusSapTitulo]");
            try
		{
                    dao.actualizarEstatusSapTitulosByContrato(mensaje,idContrato); 
		}
		catch(Exception e)
		{
                    LOG.error("Exception["+this.getClass().getSimpleName()+"::ejecutarSPAmortizacionAjustada]: "+e.getMessage() );
		}
        }
}
