/*
* Copyright 2021 E.J.I.E., S.A.
*
* Licencia con arreglo a la EUPL, Versión 1.1 exclusivamente (la «Licencia»);
* Solo podrá usarse esta obra si se respeta la Licencia.
* Puede obtenerse una copia de la Licencia en
*
* http://ec.europa.eu/idabc/eupl.html
*
* Salvo cuando lo exija la legislación aplicable o se acuerde por escrito,
* el programa distribuido con arreglo a la Licencia se distribuye «TAL CUAL»,
* SIN GARANT�?AS NI CONDICIONES DE NINGÚN TIPO, ni expresas ni implícitas.
* Véase la Licencia en el idioma concreto que rige los permisos y limitaciones
* que establece la Licencia.
*/
package com.ejie.ad74a.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ejie.ad74a.constantes.Constantes;
import com.ejie.ad74a.dao.ExpedientesDao;
import com.ejie.ad74a.exceptions.Ad74aWebserviceException;
import com.ejie.ad74a.exceptions.ManagerErrors;
import com.ejie.ad74a.model.Expedientes;
import com.ejie.ad74a.sga.xml.Datos;
import com.ejie.ad74a.sga.xml.Datos.Archivo;
import com.ejie.ad74a.sga.xml.Datos.Archivo.Contexto;
import com.ejie.ad74a.sga.xml.Datos.Archivo.Documentoselectronicos;
import com.ejie.ad74a.sga.xml.Datos.Archivo.Documentoselectronicos.Documento;
import com.ejie.ad74a.sga.xml.Datos.Archivo.Documentoselectronicos.Documento.Versiones.Version;
import com.ejie.ad74a.sga.xml.Datos.Archivo.Identificacion;
import com.ejie.ad74a.sga.xml.Datos.Registro;
import com.ejie.ad74a.sga.xml.Inicio;
import com.ejie.ad74a.sga.xml.Inicio.Fichero;
import com.ejie.ad74a.sga.xml.ObjectFactory;
import com.ejie.ad74a.util.comun.UtilidadesFecha;
import com.ejie.ad74a.util.constantes.modelos.TipoExpedientes;
import com.ejie.ad74a.util.pif.Ad74aPIFws;
import com.ejie.ad74a.ws.client.platea.expedienteElectronico.TStoreDocument;
import com.ejie.ad74a.ws.client.platea.expedienteElectronico.TStoreDocumentInfo;
import com.ejie.ad74a.ws.client.platea.expedienteElectronico.TStoreDocumentList;
import com.ejie.ad74a.ws.client.platea.service.PlateaService;
import com.ejie.y31.vo.Y31AttachmentBean;

/**
 * ArchivoExpedientesServiceImpl generated by UDA, 18-nov-2021 11:40:42.
 * 
 * @author UDA
 */

@Service(value = "archivoExpedientesService")
public class ArchivoExpedientesServiceImpl implements ArchivoExpedientesService {

	@Autowired
	private ExpedientesDao expedientesDao;

	@Autowired
	private PlateaService plateaService;

	private static final Logger logger = LoggerFactory.getLogger(ArchivoExpedientesServiceImpl.class);

	private static final String _PATH_SGA_IDA = "/s54b/ad74a/"; // "/s54b/ad27b/"
	private static final String _PATH_SGA_RETORNO = "/ad74a/s54b/"; // "/ad27b/s54b/"
	private static final String _PATH_SGA_PROCESADOS = "/ad74a/s54b/procesados/"; // "/ad27b/s54b/procesados"

	private static final String _OK_SUFIX = "_ok";
	private static final String _ERROR_SUFIX = "_errores";

	/**
	 * Proceso que realiza el archivo de los expedientes
	 */
	public void archivarExpedientes() {
		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.archivarExpedientes - INICIO -");

		// ** Recuperamos los expedientes listos para archivar **//
		ArchivoExpedientesServiceImpl.logger
				.info("ArchivoExpedientesServiceImpl.archivarExpedientes - Buscando exptes a archivar...");
		List<Expedientes> listaExptes = this.expedientesDao.findExpedientesArchivar();
		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.archivarExpedientes - "
				+ listaExptes.size() + " expedientes encontrados.");

		// ** Si se encuentran expedientes proseguimos ** //
		if (listaExptes.size() != 0) {

			// ** Recuperamos de Platea la información de exptes y documentos ** //
			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.archivarExpedientes - Recuperando datos de Platea ...");
			ArrayList<String> listaCodExptes = new ArrayList<String>();
			for (Expedientes expte : listaExptes) {
				listaCodExptes.add(expte.getFolderId00());
			}

			TStoreDocumentList listaExptesArchivar = this.plateaService.getStoredFolderDocuments(listaCodExptes);

			// ** Generamos el XML a enviar a SGA ** //
			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.archivarExpedientes - Generando archivo XML...");
			ObjectFactory oFactory = new ObjectFactory();
			Datos archivoXML = oFactory.createDatos();

			List<Archivo> listaArchivo = archivoXML.getArchivo();

			for (TStoreDocument storeDoc : listaExptesArchivar.getStoreDocument()) {
				Archivo archivo = new Archivo();
				SimpleDateFormat formatter = new SimpleDateFormat(Constantes.FORMATO_FECHA_YYYYMMDD);

				// ** Datos de identificación del expedientes ** //
				Identificacion identificacion = new Identificacion();
				identificacion.setCuadroclasificacion(new Long(storeDoc.getCuadroClasificacionID()));
				identificacion.setTitulo(storeDoc.getFolderTitle());
				try {
					identificacion.setFechaInicio(formatter.format(UtilidadesFecha.formatearStringToDateFormato(
							storeDoc.getOpeningDate(), Constantes.PLATEA_XML_EVENTS_DATE_FORMAT)));
				} catch (ParseException e) {
					identificacion.setFechaInicio("");
				}
				try {
					identificacion.setFechaFin(formatter.format(UtilidadesFecha.formatearStringToDateFormato(
							storeDoc.getClosingDate(), Constantes.PLATEA_XML_EVENTS_DATE_FORMAT)));
				} catch (ParseException pe) {
					identificacion.setFechaFin("");
				}
				identificacion.setNumeroexpediente(this.getNumExpediente(listaExptes, storeDoc.getFolderNumber()));

				archivo.setIdentificacion(identificacion);

				// ** Contexto ** //
				Contexto contexto = new Contexto();
				contexto.setProductor(storeDoc.getManagingUnitID());
				archivo.setContexto(contexto);

				Documentoselectronicos documentosElectronicos = new Documentoselectronicos();

				for (TStoreDocumentInfo infoDocu : storeDoc.getDocumentsStoreInfo().getStoreDocumentInfo()) {
					Documento documento = new Documento();
					documento.setTitulodoc(infoDocu.getTitle());

					Version ver = new Version();
					Datos.Archivo.Documentoselectronicos.Documento.Versiones vers = new Datos.Archivo.Documentoselectronicos.Documento.Versiones();
					ver.setOid(infoDocu.getDokusiID());
					vers.getVersion().add(ver);
					documento.setVersiones(vers);

					documentosElectronicos.getDocumento().add(documento);
				}
				archivo.setDocumentoselectronicos(documentosElectronicos);

				//
				listaArchivo.add(archivo);
			}

			// ** Crear Archivo ** //
			this.crearArchivoenPIF(archivoXML);

			// ** Actualizar estado de los expedientes en BD** //
			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.archivarExpedientes - actualizando exptes en BD...");
			for (Expedientes expte : listaExptes) {
				expte.setArchivo00(TipoExpedientes.Archivo00.ENVIADO.getValue());
				this.expedientesDao.updateDatosArchivo(expte);
			}
		}
		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.archivarExpedientes - FIN -");
	}

	/**
	 * Recupera el número de expediente de la lista
	 * 
	 * @param listaExptes List<Expedientes> con la lista de expedientes
	 * @param folderId    String folderID
	 * @return El número de expediente
	 */
	private String getNumExpediente(List<Expedientes> listaExptes, String folderId) {
		boolean encontrado = false;
		String numExpediente = null;
		for (int e = 0; e < listaExptes.size() && !encontrado; e++) {
			if (listaExptes.get(e).getFolderId00().equalsIgnoreCase(folderId)) {
				numExpediente = listaExptes.get(e).getNumExpediente00();
				encontrado = true;
			}
		}
		return numExpediente;
	}

	/**
	 * Crea el nombre dle archivo con la fecha
	 * 
	 * @return nombreArchivo XML
	 */
	private String crearNombreArchivoXML() {
		StringBuffer nombre = new StringBuffer("integracionSGA");
		String extension = ".xml";

		Date date = new Date();
		DateFormat fecha = new SimpleDateFormat("yyyyMMdd");

		nombre.append(fecha.format(date));

		nombre.append(extension);
		return nombre.toString();
	}

	/**
	 * Crea el archivo en la zona PIF
	 * 
	 * @param objDatos Datos del archivo
	 */
	private void crearArchivoenPIF(Datos objDatos) {
		// ** Poner archivo en zona de intercambio ** //
		ArchivoExpedientesServiceImpl.logger
				.info("ArchivoExpedientesServiceImpl.archivarExpedientes - Creando archivo XML...");

		JAXBContext jaxbContext;
		try {

			jaxbContext = JAXBContext.newInstance(Datos.class);

			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			jaxbMarshaller.marshal(objDatos, byteArrayOutputStream);

			// quitamos namespaces
			String contenido = new String(byteArrayOutputStream.toByteArray());
			contenido = contenido.replaceAll("<datos xmlns=\"com/ejie/ad74a/sga/xml\">", "<datos>");

			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.archivarExpedientes - " + contenido);

			// ** Guardarlo en PIF ** //
			String filePath = ArchivoExpedientesServiceImpl._PATH_SGA_IDA.concat(this.crearNombreArchivoXML());
			InputStream stream = new ByteArrayInputStream(contenido.getBytes());
			Ad74aPIFws.getInstance().uploadDocument(stream, filePath, true);

		} catch (JAXBException e) {
			ManagerErrors.manageException(e);
			ArchivoExpedientesServiceImpl.logger
					.error("ArchivoExpedientesServiceImpl.archivarExpedientes - ERROR JAXB: -", e);
		} catch (Ad74aWebserviceException e) {
			ManagerErrors.manageException(e);
			ArchivoExpedientesServiceImpl.logger
					.error("ArchivoExpedientesServiceImpl.archivarExpedientes - ERROR PIF: -", e);
		}
	}

	/**
	 * Proceso que realiza el proceso de la respuesta de archivo
	 */
	public void procesarRespuesta() {
		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.procesarRespuesta - INICIO -");

		// ** Recuperar archivos de la zona PIF **//
		List<Y31AttachmentBean> listaArchivos = new ArrayList<Y31AttachmentBean>();

		try {
			listaArchivos = Ad74aPIFws.getInstance().listFile(ArchivoExpedientesServiceImpl._PATH_SGA_RETORNO);
		} catch (Ad74aWebserviceException e) {
			ManagerErrors.manageException(e);
			ArchivoExpedientesServiceImpl.logger
					.error("ArchivoExpedientesServiceImpl.archivarExpedientes - ERROR PIF: -", e);
		}
		ArchivoExpedientesServiceImpl.logger.info(
				"ArchivoExpedientesServiceImpl.procesarRespuesta - Encontrados " + listaArchivos.size() + " archivos.");

		for (Y31AttachmentBean archivo : listaArchivos) {
			// Comprobar si son OK o ERROR ** //
			if ((archivo.getFileName().toLowerCase()).indexOf(ArchivoExpedientesServiceImpl._OK_SUFIX) != -1) {
				// Archivo de exptes OK
				this.procesarArchivo(archivo.getFilePath(), true);

			} else if ((archivo.getFileName().toLowerCase())
					.indexOf(ArchivoExpedientesServiceImpl._ERROR_SUFIX) != -1) {
				// Archivo de exptes ERROR
				this.procesarArchivo(archivo.getFilePath(), false);
			}

			// ** Guardar archivo procesado ** //
			try {
				Ad74aPIFws.getInstance().moveDocument(archivo.getFilePath(),
						ArchivoExpedientesServiceImpl._PATH_SGA_PROCESADOS.concat(archivo.getFileName()));

			} catch (Ad74aWebserviceException e) {
				ManagerErrors.manageException(e);
				ArchivoExpedientesServiceImpl.logger
						.error("ArchivoExpedientesServiceImpl.archivarExpedientes - ERROR guardando archivo PIF: -", e);
			}
		}

		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.procesarRespuesta - FIN -");
	}

	/**
	 * 
	 * @param filePath
	 * @param archivados
	 */
	private void procesarArchivo(String filePath, boolean archivados) {
		ArchivoExpedientesServiceImpl.logger
				.info("ArchivoExpedientesServiceImpl.procesarRespuesta - Procesando archivo: " + filePath);

		// ** Obtener contenido del archivo ** //
		List<Expedientes> listaExpedientes = new ArrayList<Expedientes>();

		if (archivados) {
			// ********************** EXPTES ARCHIVADOS ********************* //
			// leer archivo
			Datos datosXML = (Datos) this.leerArchivo(filePath, archivados);

			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.procesarRespuesta - Procesando expedientes archivados...");

			for (Registro registro : datosXML.getRegistro()) {
				Expedientes expte = new Expedientes();
				expte.setNumExpediente00(registro.getNumeroexpediente());

				List<Expedientes> listaExptes = this.expedientesDao.findAll(expte, null);
				if (!listaExptes.isEmpty()) {
					expte.setNumExpediente00(listaExptes.get(0).getNumExpediente00());
					expte.setFolderId00(listaExptes.get(0).getFolderId00());
				}
				if (registro.getCodigoSGA() != null) {

					expte.setCodigoSga00(new BigDecimal(registro.getCodigoSGA()).longValue());
				}

				Date fecha;
				try {
					fecha = UtilidadesFecha.formatearStringToDateFormato(datosXML.getFechacarga(),
							com.ejie.ad74a.constantes.Constantes.FORMATO_FECHA_YYYYMMDD);
				} catch (ParseException pe) {
					fecha = new Date();
				}
				expte.setfArchivo00(fecha);
				expte.setArchivo00(TipoExpedientes.Archivo00.ARCHIVADO.getValue());

				ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.procesarRespuesta - "
						+ expte.getNumExpediente00() + " - " + expte.getCodigoSga00() + "- OK");

				// Añadimos el expediente
				listaExpedientes.add(expte);
			}

		} else {
			// ********************** EXPTES NO ARCHIVADOS ********************* //
			Inicio erroresXML = (Inicio) this.leerArchivo(filePath, archivados);

			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.procesarRespuesta - Procesando expedientes NO archivados...");

			for (Fichero fichero : erroresXML.getFichero()) {
				for (com.ejie.ad74a.sga.xml.Inicio.Fichero.Registro registro : fichero.getRegistro()) {
					Expedientes expte = new Expedientes();
					expte.setNumExpediente00(registro.getNumeroexpediente());

					List<Expedientes> listaExptes = this.expedientesDao.findAll(expte, null);
					if (!listaExptes.isEmpty()) {
						expte.setNumExpediente00(listaExptes.get(0).getNumExpediente00());
						expte.setFolderId00(listaExptes.get(0).getFolderId00());
					}

					expte.setArchivo00(TipoExpedientes.Archivo00.PENDIENTE_ENVIO.getValue());

					ArchivoExpedientesServiceImpl.logger
							.info("ArchivoExpedientesServiceImpl.procesarRespuesta - " + expte.getNumExpediente00()
									+ "- ERROR: " + registro.getError().get(0).getMensaje().get(0));

					// Añadimos el expediente
					listaExpedientes.add(expte);
				}
			}

		}

		// ** Actualización de datos en Platea ** //
		ArchivoExpedientesServiceImpl.logger.info(
				"ArchivoExpedientesServiceImpl.procesarRespuesta - Procesando archivo, actualizando exptes en Platea...");

		this.plateaService.setStoredFolderStatus(listaExpedientes, archivados);

		// ** Actualización de datos en BD ** //
		ArchivoExpedientesServiceImpl.logger.info(
				"ArchivoExpedientesServiceImpl.procesarRespuesta - Procesando archivo, actualizando exptes en BD...");
		for (Expedientes expte : listaExpedientes) {
			this.expedientesDao.updateDatosArchivo(expte);
		}

		ArchivoExpedientesServiceImpl.logger.info(
				"ArchivoExpedientesServiceImpl.procesarRespuesta - Archivo procesado: " + filePath + " procesado.");
	}

	/**
	 * 
	 * @param filePath
	 * @return
	 */
	private Object leerArchivo(String filePath, boolean archivados) {
		ArchivoExpedientesServiceImpl.logger
				.info("ArchivoExpedientesServiceImpl.leerArchivo - Leyendo contenido del archivo...");
		// ** Obtener contenido del archivo ** //
		byte[] contenido = null;
		try {
			ArchivoExpedientesServiceImpl.logger.info(
					"ArchivoExpedientesServiceImpl.leerArchivo - Ad74aPIFws.getInstance().downloadDocument path = {}",
					filePath);
			InputStream is = Ad74aPIFws.getInstance().downloadDocument(filePath);
			contenido = IOUtils.toByteArray(is);
			ArchivoExpedientesServiceImpl.logger
					.info("ArchivoExpedientesServiceImpl.leerArchivo - Contenido: " + contenido);
		} catch (Ad74aWebserviceException wse) {
			ManagerErrors.manageException(wse);
			ArchivoExpedientesServiceImpl.logger.error("ArchivoExpedientesServiceImpl.leerArchivo - ERROR PIF: -", wse);
		} catch (IOException ioe) {
			ManagerErrors.manageException(ioe);
			ArchivoExpedientesServiceImpl.logger.error("ArchivoExpedientesServiceImpl.leerArchivo - ERROR PIF: -", ioe);
		}

		ObjectFactory oFactory = new ObjectFactory();
		Datos datosXML = oFactory.createDatos();
		Inicio erroneosXML = oFactory.createInicio();
		String tempXML = new String(contenido);

		if (archivados) {
			datosXML = oFactory.createDatos();
			tempXML = tempXML.replaceAll("<datos>", "<datos xmlns=\"com/ejie/ad74a/sga/xml\">");
		} else {
			erroneosXML = oFactory.createInicio();
			tempXML = tempXML.replaceAll("<inicio>", "<inicio xmlns=\"com/ejie/ad74a/sga/xml\">");
		}
		contenido = tempXML.getBytes();

		try {
			JAXBContext jc;
			Unmarshaller unmarshaller;
			if (archivados) {
				jc = JAXBContext.newInstance(datosXML.getClass());
				unmarshaller = jc.createUnmarshaller();
				datosXML = (Datos) unmarshaller.unmarshal(new ByteArrayInputStream(contenido));
			} else {
				jc = JAXBContext.newInstance(erroneosXML.getClass());
				unmarshaller = jc.createUnmarshaller();
				erroneosXML = (Inicio) unmarshaller.unmarshal(new ByteArrayInputStream(contenido));
			}
		} catch (JAXBException jaxbe) {
			ManagerErrors.manageException(jaxbe);
			ArchivoExpedientesServiceImpl.logger.error("ArchivoExpedientesServiceImpl.leerArchivo - ERROR PIF: -",
					jaxbe);
		}
		ArchivoExpedientesServiceImpl.logger.info("ArchivoExpedientesServiceImpl.leerArchivo - Archivo leído OK.");

		return (archivados ? datosXML : erroneosXML);
	}
}
