package com.ejie.ab04b.util.seguridad;

import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;

import com.ejie.ab04b.constantes.Constantes;
import com.ejie.ab04b.model.comun.ElementoCombo;
import com.ejie.ab04b.util.PropertiesUtil;
import com.ejie.ab04b.util.ValidadorNifCifNie;
import com.ejie.ab04b.util.XmlUtils;
import com.ejie.x38.security.UserCredentials;
import com.ejie.x38.security.XlnetGrantedAuthority;

import n38a.exe.N38APISesion;
import n38c.exe.N38API;

/**
 * Clase de utilidades utilizada para el acceso al objeto de seguridad
 * UsuarioConectado
 * 
 * @author GFI-NORTE
 * 
 */
@Component(value = "seguridadProperties")
public final class UtilSeguridad extends PropertyPlaceholderConfigurer {

	private static UtilSeguridad instance;

	private static final Logger LOGGER = LoggerFactory
			.getLogger(UtilSeguridad.class);

	/*
	 * ****************************************************************
	 * Seguridad properties
	 * ****************************************************************
	 */
	private static Map<String, String> propertiesMap;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#
	 * processProperties(org.springframework.beans.factory.config.
	 * ConfigurableListableBeanFactory, java.util.Properties)
	 */
	@Override()
	protected void processProperties(
			ConfigurableListableBeanFactory beanFactory, Properties props)
			throws BeansException {
		super.processProperties(beanFactory, props);
		UtilSeguridad.propertiesMap = new HashMap<String, String>();
		for (Object key : props.keySet()) {
			String keyStr = key.toString();
			UtilSeguridad.propertiesMap.put(keyStr, props.getProperty(keyStr));
		}
	}

	/**
	 * Obtiene el valor de una propiedad definida en el fichero
	 * 'aa73aSeguridad.properties'.
	 * 
	 * name String String
	 *
	 * @param name
	 *            the name
	 * @return the property
	 */
	public static String getProperty(String name) {
		return UtilSeguridad.propertiesMap.get(name);
	}

	/**
	 * Verifica si el usuario conectado tiene alguno de los roles recibidos por
	 * parametros
	 * 
	 * roles String... boolean
	 *
	 * @param roles
	 *            the roles
	 * @return true, if successful
	 */
	public static boolean userContentRol(String... roles) {

		Collection<? extends GrantedAuthority> authorities = SecurityContextHolder
				.getContext().getAuthentication().getAuthorities();
		for (String rol : roles) {
			if (authorities.contains(new XlnetGrantedAuthority(rol))) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Constructor de Utilidades.
	 */
	private UtilSeguridad() {
	}

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

	/**
	 * Devuelve un String con el token de sesion
	 * 
	 * String.
	 *
	 * @return the token XL nets
	 */
	public String getTokenXLNets() {

		try {
			String simulacion = PropertiesUtil
					.getProperty(PropertiesUtil.SIMULA_TOKEN);
			if (simulacion != null && Boolean.valueOf(simulacion)) {
				return PropertiesUtil.getProperty(PropertiesUtil.TOKEN_PRUEBA);
			} else {
				N38APISesion miAPISesion = new N38APISesion();
				Document miSesion;
				miSesion = miAPISesion
						.n38APISesionCrearApp(Constantes.APLICACION);
				return this.dom2String(miSesion);
			}
		} catch (Exception e) {
			UtilSeguridad.LOGGER.error("Error al obtener el TOKEN", e);
			return null;
		}
	}

	/**
	 * Devuelve un String con el token de sesion
	 * 
	 * String.
	 *
	 * @param migrado
	 *            the migrado
	 * @return the token XL nets
	 */
	public String getTokenXLNets(boolean migrado) {

		try {
			String simulacion = PropertiesUtil
					.getProperty(PropertiesUtil.SIMULA_TOKEN);
			if (simulacion != null && Boolean.valueOf(simulacion)) {
				if (!migrado) {
					return PropertiesUtil
							.getProperty(PropertiesUtil.TOKEN_PRUEBA);
				} else {
					return PropertiesUtil
							.getProperty(PropertiesUtil.TOKEN_PRUEBA_OLD);
				}
			} else {
				N38APISesion miAPISesion = new N38APISesion();
				Document miSesion;
				if (!migrado) {
					miSesion = miAPISesion
							.n38APISesionCrearApp(Constantes.APLICACION);
				} else {
					miSesion = miAPISesion
							.n38APISesionCrearApp(Constantes.APLICACION_OLD);
				}
				return this.dom2String(miSesion);
			}
		} catch (Exception e) {
			UtilSeguridad.LOGGER.error("Error al obtener el TOKEN", e);
			return null;
		}
	}

	/**
	 * Devuelve un String con el token de aplicación
	 * 
	 * idAplic String String.
	 *
	 * @param idAplic
	 *            the id aplic
	 * @return the token document XL nets
	 */
	public Document getTokenDocumentXLNets(String idAplic) {

		Document token = null;

		try {
			String simulacion = PropertiesUtil
					.getProperty(PropertiesUtil.SIMULA_TOKEN);
			if (simulacion != null && Boolean.valueOf(simulacion)) {

				if (Constantes.APLICACION.equals(idAplic)) {
					return XmlUtils.string2Document(PropertiesUtil
							.getProperty(PropertiesUtil.TOKEN_PRUEBA));
				}
			} else {
				N38APISesion miAPISesion = new N38APISesion();
				return miAPISesion.n38APISesionCrearApp(idAplic);
			}

		} catch (Exception e) {
			UtilSeguridad.LOGGER.error("Error al obtener el TOKEN", e);
			return null;
		}

		return token;
	}

	/**
	 * Convierte en String un documento org.w3c.dom.Document
	 * 
	 * doc Document (Documento de tipo org.w3c.dom.Document) String (en el que
	 * se ha convertido el Document)
	 *
	 * @param doc
	 *            the doc
	 * @return the string
	 */
	public String dom2String(Document doc) {

		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		Transformer transformer = null;

		try {
			transformer = transformerFactory.newTransformer();
		} catch (javax.xml.transform.TransformerConfigurationException error) {
			UtilSeguridad.LOGGER
					.error("Error al crear la instancia de Transformer");
		}

		Source source = new DOMSource(doc);
		StringWriter writer = new StringWriter();
		Result result = new StreamResult(writer);

		try {
			transformer.transform(source, result);
		} catch (javax.xml.transform.TransformerException error) {
			UtilSeguridad.LOGGER.error("Error al transformar el Document",
					error);
		}

		return writer.toString();
	}

	/**
	 * Devuelve el objeto UserCredentials guardado en el contexto.
	 * 
	 * UserCredentials
	 *
	 * @return the user credentials
	 */
	public UserCredentials getUserCredentials() {
		// Cuando se llama a este método desde un EJB no existe usuario
		// conectado y falla, por lo que se añade la comprobación de

		return SecurityContextHolder.getContext().getAuthentication() == null
				? null
				: (UserCredentials) SecurityContextHolder.getContext()
						.getAuthentication().getCredentials();
	}

	/**
	 * Devuelve el usuario conectado.
	 * 
	 * String
	 *
	 * @return the audit user
	 */
	public String getAuditUser() {

		UserCredentials userCredentials = this.getUserCredentials();

		StringBuilder auditUser = new StringBuilder();
		auditUser.append(userCredentials.getNif()).append("#")
				.append(userCredentials.getFullName()).append("#")
				.append(Constantes.APLICACION);

		return auditUser.toString();
		// }
	}

	/**
	 * Devuelve el usuario conectado (corto)
	 * 
	 * String.
	 *
	 * @return the audit user short
	 */
	public String getAuditUserShort() {
		return this.getAuditUser().toLowerCase().split("#")[0];
	}

	/**
	 * Devuelve el NIF del usuario conectado
	 * 
	 * String.
	 *
	 * @return the nif
	 */
	public String getNif() {
		UserCredentials credentials = this.getUserCredentials();
		if (credentials != null) {
			return credentials.getNif();
		}
		return "";
	}

	/**
	 * Devuelve el Nombre del usuario conectado
	 * 
	 * String.
	 *
	 * @return the nombre
	 */
	public String getNombre() {
		UserCredentials credentials = this.getUserCredentials();
		if (credentials != null) {
			return credentials.getFullName();
		}
		return "";
	}

	/**
	 * String.
	 *
	 * @return the audit user auto
	 */
	public String getAuditUserAuto() {
		return PropertiesUtil.getProperty(PropertiesUtil.AUDIT_USER_AUTO);
	}

	/**
	 * Obtiene el territorio / delegación del usuario
	 * 
	 * String.
	 *
	 * @return the string
	 */
	public String obtenerDelegacionUsuario() {

		UserCredentials userCredentials = null;
		userCredentials = (UserCredentials) SecurityContextHolder.getContext()
				.getAuthentication().getCredentials();

		List<String> perfiles = userCredentials.getUserProfiles();

		if (perfiles != null) {
			if (perfiles.contains(Constantes.ROL_TRAMITADOR_ALAVA)
					|| perfiles.contains(Constantes.ROL_TRAMITADOR_OSALAN_ALAVA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_ALAVA)
					|| perfiles
							.contains(Constantes.ROL_CONSULTA_OSALAN_ALAVA)) {
				return Constantes.TH_ALAVA;
			} else if (perfiles.contains(Constantes.ROL_TRAMITADOR_GIPUZKOA)
					|| perfiles
							.contains(Constantes.ROL_TRAMITADOR_OSALAN_GIPUZKOA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_GIPUZKOA)
					|| perfiles.contains(
							Constantes.ROL_CONSULTA_OSALAN_GIPUZKOA)) {
				return Constantes.TH_GIPUZKOA;
			} else if (perfiles.contains(Constantes.ROL_TRAMITADOR_BIZKAIA)
					|| perfiles
							.contains(Constantes.ROL_TRAMITADOR_OSALAN_BIZKAIA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_BIZKAIA)
					|| perfiles
							.contains(Constantes.ROL_CONSULTA_OSALAN_BIZKAIA)) {
				return Constantes.TH_BIZKAIA;
			} else if (perfiles.contains(Constantes.ROL_ADMIN)
					|| perfiles.contains(Constantes.ROL_INSPECCION)) {
				return Constantes.TH_BIZKAIA;
			}
		}
		return "-1";
	}

	/**
	 * request HttpServletRequest String.
	 *
	 * @param request
	 *            the request
	 * @return the string
	 */
	public String obtenerTelefonoUsuario(HttpServletRequest request) {
		N38API n38api = new N38API(request);
		StringBuilder filterLdap = new StringBuilder();
		filterLdap.append("dni=");
		String nif = UtilSeguridad.getInstance().getNif();
		filterLdap.append(nif);
		// Si es un NIF (DNIs reales), eliminamos la letra
		if (ValidadorNifCifNie.checkNif(nif)) {
			filterLdap.deleteCharAt(filterLdap.length() - 1);
		}
		UtilSeguridad.LOGGER.info("filterLdap {}", filterLdap);

		Document infoLdap = n38api
				.n38ItemObtenerPersonas(filterLdap.toString());

		String telefonoDestinatario = "";
		try {
			String[] telefono = XmlUtils.obtenerValorNodosXPath(infoLdap,
					"//elemento[@subtipo='n38persona']/parametro[@id='telephonenumber']/valor/text()");
			if (telefono != null && telefono.length > 0) {
				telefonoDestinatario = telefono[0];
				UtilSeguridad.LOGGER.info("telefono usuario {}",
						telefonoDestinatario);
			}
		} catch (Exception e) {
			telefonoDestinatario = "";
		}

		return telefonoDestinatario;
	}

	/**
	 * Obtiene el territorio / delegación del usuario
	 * 
	 * String.
	 *
	 * @return the list
	 */
	public List<ElementoCombo> obtenerDelegacionesUsuario() {

		UserCredentials userCredentials = null;
		userCredentials = (UserCredentials) SecurityContextHolder.getContext()
				.getAuthentication().getCredentials();

		List<String> perfiles = userCredentials.getUserProfiles();

		if (perfiles != null) {
			if (perfiles.contains(Constantes.ROL_TRAMITADOR_ALAVA)
					|| perfiles.contains(Constantes.ROL_TRAMITADOR_OSALAN_ALAVA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_ALAVA)
					|| perfiles
							.contains(Constantes.ROL_CONSULTA_OSALAN_ALAVA)) {
				return Constantes.COMBO_DELEGACIONES_ARABA;
			} else if (perfiles.contains(Constantes.ROL_TRAMITADOR_GIPUZKOA)
					|| perfiles
							.contains(Constantes.ROL_TRAMITADOR_OSALAN_GIPUZKOA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_GIPUZKOA)
					|| perfiles.contains(
							Constantes.ROL_CONSULTA_OSALAN_GIPUZKOA)) {
				return Constantes.COMBO_DELEGACIONES_GIPUZKOA;
			} else if (perfiles.contains(Constantes.ROL_TRAMITADOR_BIZKAIA)
					|| perfiles
							.contains(Constantes.ROL_TRAMITADOR_OSALAN_BIZKAIA)
					|| perfiles.contains(Constantes.ROL_CONSULTA_BIZKAIA)
					|| perfiles
							.contains(Constantes.ROL_CONSULTA_OSALAN_BIZKAIA)) {
				return Constantes.COMBO_DELEGACIONES_BIZKAIA;
			} else if (perfiles.contains(Constantes.ROL_ADMIN)
					|| perfiles.contains(Constantes.ROL_INSPECCION)) {
				return Constantes.COMBO_DELEGACIONES;
			}
		}

		return null;

	}

	/**
	 * Obtiene el territorio / delegación del usuario
	 * 
	 * String.
	 *
	 * @return the list
	 */
	public List<ElementoCombo> obtenerTodasDelegaciones() {

		return Constantes.COMBO_DELEGACIONES;

	}

	public boolean soyAdmin() {
		UserCredentials userCredentials = null;
		userCredentials = (UserCredentials) SecurityContextHolder.getContext()
				.getAuthentication().getCredentials();

		List<String> perfiles = userCredentials.getUserProfiles();
		if (perfiles.contains(Constantes.ROL_ADMIN)) {
			return true;
		} else {
			return false;
		}
	}
}
