package com.ejie.ab04b.service.pif;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import com.ejie.ab04b.constantes.Constantes;
import com.ejie.ab04b.exception.AB04BException;
import com.ejie.ab04b.service.util.ApplicationContextProvider;
import com.ejie.ab04b.util.PropertiesUtil;
import com.ejie.ab04b.util.seguridad.UtilSeguridad;
import com.ejie.y31.exception.Y31JanoServiceAccesDeniedException;
import com.ejie.y31.exception.Y31JanoServiceEventJmsException;
import com.ejie.y31.exception.Y31JanoServiceFileNameFormatException;
import com.ejie.y31.exception.Y31JanoServiceFileNotFoundException;
import com.ejie.y31.exception.Y31JanoServiceGenericException;
import com.ejie.y31.exception.Y31JanoServiceMongoDbGenericException;
import com.ejie.y31.exception.Y31JanoServiceOracleGenericException;
import com.ejie.y31.factory.Y31JanoServiceAbstractFactory;
import com.ejie.y31.service.Y31JanoService;
import com.ejie.y31.vo.Y31AttachmentBean;

/**
 * Utilidad para invocar al WS de Platea Integración Ficheros
 * 
 * @author olillo
 * 
 */
@Service(value = "pifService")
public class PifService {

	private static PifService instance;
	private Y31JanoService webservice;

	@Autowired()
	private Properties appConfiguration;

	/**
	 *  Y31JanoService.
	 *
	 * @return the web service
	 * @throws AB04BException             Excepcion al invocar el WS
	 */
	public Y31JanoService getWebService() throws AB04BException {
		if (this.webservice == null) {
			try {
				this.webservice = Y31JanoServiceAbstractFactory.getInstance();
			} catch (Y31JanoServiceGenericException e) {
				throw new AB04BException(
						"Error al instanciar el WS de PIF: " + e.getCause());
			}
		}
		return this.webservice;
	}

	/**
	 * Descarga el documento desde la ruta especificada y lo devuelve como
	 * Stream d entrada
	 * 
	 *  path
	 *            la ruta
	 *  el stream.
	 *
	 * @param path the path
	 * @return the input stream
	 * @throws AB04BException             excepción de invocación al servicio
	 */
	public InputStream downloadDocument(String path) throws AB04BException {
		try {
			// GET --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - pathFrom - String --> Ruta lógica de donde se va a descargar el
			// fichero. Incluirá como carpeta principal la aplicación destino
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero

			return this.getWebService().get(UtilSeguridad.getInstance()
					.getTokenDocumentXLNets(Constantes.APLICACION), path);
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error descargar el fichero (Excepción genérica): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNotFoundException e) {
			throw new AB04BException(
					"Error descargar el fichero (Archivo no encontrado): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error descargar el fichero (Formato de fichero no soportado): "
							+ e.getCause());
		} catch (Y31JanoServiceMongoDbGenericException e) {
			throw new AB04BException(
					"Error descargar el fichero (Error de BB.DD.[MongoDB]): "
							+ e.getCause());
		} catch (Y31JanoServiceOracleGenericException e) {
			throw new AB04BException(
					"Error descargar el fichero (Error de BB.DD.[Oracle]): "
							+ e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error descargar el fichero (Accedo denegado): "
							+ e.getCause());
		}
	}

	/**
	 * Sube a la ruta de la zona pif que se pasa como parámetro el documento
	 * accedido por el inpuStream
	 * 
	 *  stream
	 *            Stream del documento
	 *  path
	 *            ruta en la que se va a dejar el documento (incluyendo el
	 *            nombre de archivo y extensión)
	 *  preserveName
	 *            Indica si se desea preservar el nombre del fichero en la ruta
	 *            seleccionada sobrescribiendo el fichero si existiera. Si se
	 *            decide no preservar los nombres lo que se hace es concatenarle
	 *            una serie de dígitos que lo hace único en el repositorio
	 *  la ruta en la que se deja el documento
	 *
	 * @param stream the stream
	 * @param path the path
	 * @param preserveName the preserve name
	 * @return the string
	 * @throws AB04BException             Excepción de invocación al servicio
	 */
	public String uploadDocument(InputStream stream, String path,
			boolean preserveName) throws AB04BException {
		try {
			// PUT --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - File - InputStream --> Stream de datos para acceder al
			// contenido a copiar en el repositorio
			// - pathTo - String --> Ruta lógica donde alojar el fichero.
			// Incluirá como carpeta principal la aplicación destino
			// - preserveName - boolean --> Indica si se desea preservar el
			// nombre del fichero en la ruta seleccionada sobrescribiendo el
			// fichero si existiera. Si se decide no preservar los nombres lo
			// que se hace es concatenarle una serie de dígitos que lo hace
			// único en el repositorio
			// - Ttl - Long --> Número de segundos que se desea mantener el
			// fichero en el repositorio. Como máximo se podrá fijar el número
			// de segundos de 15 días naturales
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero

			UtilSeguridad.getInstance().getTokenXLNets();

			if (this.appConfiguration == null) {
				ApplicationContext ctx = ApplicationContextProvider
						.getApplicationContext();
				this.appConfiguration = (Properties) ctx
						.getBean("appConfiguration");
			}
			Y31AttachmentBean resul = this.getWebService()
					.put(UtilSeguridad.getInstance().getTokenDocumentXLNets(
							Constantes.APLICACION), stream, path, preserveName,
							Long.parseLong(this.appConfiguration
									.getProperty(PropertiesUtil.PIF_TTL)));
			return resul.getFilePath();
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Excepción genérica): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error al subir el fichero (Formato de fichero no soportado) : "
							+ e.getCause());
		} catch (Y31JanoServiceMongoDbGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error de BB.DD.): "
							+ e.getCause());
		} catch (Y31JanoServiceEventJmsException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error JMS): " + e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error al subir el fichero (Acceso denegado): "
							+ e.getCause());
		} catch (Exception e) {
			throw new AB04BException("Error: " + e.getCause());
		}
	}

	/**
	 * Mueve el documento en la ruta origen a la ruta destino
	 * 
	 *  pathOrigen
	 *            ruta en la que está el documento
	 *  pathDestino
	 *            ruta en la que se va a dejar el documento
	 *  la ruta en la que se deja el documento.
	 *
	 * @param pathOrigen the path origen
	 * @param pathDestino the path destino
	 * @return the string
	 * @throws AB04BException             Excepción de invocación al servicio
	 */
	public String moveDocument(String pathOrigen, String pathDestino)
			throws AB04BException {
		try {
			// MOVE --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - pathFrom - String --> Ruta lógica desde donde se va a mover el
			// fichero. Incluirá como carpeta principal la aplicación origen
			// - pathTo - String --> Ruta lógica donde se va a mover el fichero.
			// Incluirá como carpeta principal la aplicación destino
			// - preserveName - boolean --> Indica si se desea preservar el
			// nombre del fichero en la ruta seleccionada sobrescribiendo el
			// fichero si existiera. Si se decide no preservar los nombres lo
			// que se hace es concatenarle una serie de dígitos que lo hace
			// único en el repositorio
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero
			Y31AttachmentBean resul = this.getWebService()
					.move(UtilSeguridad.getInstance()
							.getTokenDocumentXLNets(Constantes.APLICACION),
							pathOrigen, pathDestino, true);
			return resul.getFilePath();
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Excepción genérica): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error al subir el fichero (Formato de fichero no soportado) : "
							+ e.getCause());
		} catch (Y31JanoServiceMongoDbGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error de BB.DD.): "
							+ e.getCause());
		} catch (Y31JanoServiceEventJmsException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error JMS): " + e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error al subir el fichero (Acceso denegado): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNotFoundException e) {
			throw new AB04BException(
					"Error al subir el fichero (Archivo no encontrado): "
							+ e.getCause());
		}
	}

	/**
	 * Copia el documento en la ruta origen a la ruta destino
	 * 
	 *  pathOrigen
	 *            ruta en la que está el documento
	 *  pathDestino
	 *            ruta en la que se va a dejar el documento
	 *  preserveName
	 *            indica si sobreescribe (true) o crea un nuevo documento
	 *            (false)
	 *  la ruta en la que se deja el documento.
	 *
	 * @param pathOrigen the path origen
	 * @param pathDestino the path destino
	 * @param preserveName the preserve name
	 * @return the string
	 * @throws AB04BException             Excepción de invocación al servicio
	 */
	public String copyDocument(String pathOrigen, String pathDestino,
			boolean preserveName) throws AB04BException {
		try {
			// COPY --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - pathFrom - String --> Ruta lógica desde donde se va a mover el
			// fichero. Incluirá como carpeta principal la aplicación origen
			// - pathTo - String --> Ruta lógica donde se va a mover el fichero.
			// Incluirá como carpeta principal la aplicación destino
			// - preserveName - boolean --> Indica si se desea preservar el
			// nombre del fichero en la ruta seleccionada sobrescribiendo el
			// fichero si existiera. Si se decide no preservar los nombres lo
			// que se hace es concatenarle una serie de dígitos que lo hace
			// único en el repositorio
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero
			Y31AttachmentBean resul = this.getWebService()
					.copy(UtilSeguridad.getInstance()
							.getTokenDocumentXLNets(Constantes.APLICACION),
							pathOrigen, pathDestino, preserveName);
			// TODO mirar resultado del servicio web. Si "success" es false
			// notificarlo (lanzar excepcion)
			return resul.getFilePath();
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Excepción genérica): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error al subir el fichero (Formato de fichero no soportado) : "
							+ e.getCause());
		} catch (Y31JanoServiceMongoDbGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error de BB.DD.): "
							+ e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error al subir el fichero (Acceso denegado): "
							+ e.getCause());
		} catch (Y31JanoServiceEventJmsException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error JMS): " + e.getCause());
		} catch (Y31JanoServiceFileNotFoundException e) {
			throw new AB04BException(
					"Error al subir el fichero (Archivo no encontrado): "
							+ e.getCause());
		}
	}

	/**
	 * Consulta el documento en la ruta
	 * 
	 *  path
	 *            ruta en la que está el documento
	 *  la ruta en la que se deja el documento.
	 *
	 * @param path the path
	 * @return the hash map
	 * @throws AB04BException             Excepción de invocación al servicio
	 */
	public HashMap<String, String> infoDocument(String path)
			throws AB04BException {

		HashMap<String, String> resultado = new HashMap<String, String>();
		try {
			// INFO --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - pathFrom - String --> Ruta lógica desde donde se va a consultar
			// el
			// fichero. Incluirá como carpeta principal la aplicación origen
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero
			Y31AttachmentBean resul = this.getWebService()
					.info(UtilSeguridad.getInstance().getTokenDocumentXLNets(
							Constantes.APLICACION), path);
			resultado.put("contentType", resul.getContentType());
			resultado.put("fileName", resul.getFileName());
			resultado.put("filePath", resul.getFilePath());
			resultado.put("size", resul.getSize().toString());

			return resultado;
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error al subir el fichero (Formato de fichero no soportado) : "
							+ e.getCause());
		} catch (Y31JanoServiceMongoDbGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Error de BB.DD.): "
							+ e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error al subir el fichero (Acceso denegado): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNotFoundException e) {
			throw new AB04BException(
					"Error al subir el fichero (Archivo no encontrado): "
							+ e.getCause());
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Excepción genérica): "
							+ e.getCause());
		}
	}

	/**
	 * Elimina el documento en la ruta
	 * 
	 *  path
	 *            ruta en la que está el documento.
	 *
	 * @param path the path
	 * @throws AB04BException             Excepción de invocación al servicio
	 */
	public void deleteDocument(String path) throws AB04BException {
		try {
			// DELETE --> PARAMETROS
			// - Xlnets - Document --> Sesión de aplicación que está escribiendo
			// en el repositorio
			// - pathFrom - String --> Ruta lógica desde donde se va a eliminar
			// el
			// fichero. Incluirá como carpeta principal la aplicación origen
			//
			// * return: File - InputStream --> Stream de datos para acceder al
			// contenido existente en el repositorio
			// ************** contentType - String --> content type del fichero
			// ************** fileName - String --> nombre del fichero
			// ************** filePath - String --> ruta completa al fichero
			// ************** size - Long --> número de bytes del fichero
			this.getWebService().delete(UtilSeguridad.getInstance()
					.getTokenDocumentXLNets(Constantes.APLICACION), path);
		} catch (Y31JanoServiceGenericException e) {
			throw new AB04BException(
					"Error al subir el fichero (Excepción genérica): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNameFormatException e) {
			throw new AB04BException(
					"Error al subir el fichero (Formato de fichero no soportado) : "
							+ e.getCause());
		} catch (Y31JanoServiceAccesDeniedException e) {
			throw new AB04BException(
					"Error al subir el fichero (Acceso denegado): "
							+ e.getCause());
		} catch (Y31JanoServiceFileNotFoundException e) {
			throw new AB04BException(
					"Error al subir el fichero (Archivo no encontrado): "
							+ e.getCause());
		}
	}

	/**
	 * Devuelve la instancia de tipo PifService
	 * 
	 *  Devuelve la instancia de tipo PifService.
	 *
	 * @return single instance of PifService
	 */
	public static final PifService getInstance() {
		if (PifService.instance == null) {
			PifService.instance = new PifService();
		}
		return PifService.instance;
	}

}
