package com.fp.armas.portal.service;

import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.persistence.Query;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.SerializationUtils;

import com.fp.armas.portal.dao.registro.ActividadEconomicaDao;
import com.fp.armas.portal.dao.registro.ArchivoDao;
import com.fp.armas.portal.dao.registro.ArchivoDetalleDao;
import com.fp.armas.portal.dao.registro.CantonDao;
import com.fp.armas.portal.dao.registro.CatalogoDao;
import com.fp.armas.portal.dao.registro.CiudadDao;
import com.fp.armas.portal.dao.registro.CompaniaDao;
import com.fp.armas.portal.dao.registro.DireccionPersonaDao;
import com.fp.armas.portal.dao.registro.PaisDao;
import com.fp.armas.portal.dao.registro.ParroquiaDao;
import com.fp.armas.portal.dao.registro.PersonaDao;
import com.fp.armas.portal.dao.registro.PersonaDetalleDao;
import com.fp.armas.portal.dao.registro.PersonaNaturalDao;
import com.fp.armas.portal.dao.registro.ProvinciaDao;
import com.fp.armas.portal.dao.registro.TelefonoPersonaDao;
import com.fp.armas.portal.dao.registro.UsuarioDao;
import com.fp.armas.portal.dao.registro.UsuarioDetalleDao;
import com.fp.armas.portal.dao.registro.UsuarioPerfilDao;
import com.fp.armas.portal.model.Tcustcompany;
import com.fp.armas.portal.model.TcustcompanyPK;
import com.fp.armas.portal.model.Tcustpeople;
import com.fp.armas.portal.model.TcustpeoplePK;
import com.fp.armas.portal.model.Tcustperson;
import com.fp.armas.portal.model.Tcustpersonaddress;
import com.fp.armas.portal.model.TcustpersonaddressPK;
import com.fp.armas.portal.model.Tcustpersondetail;
import com.fp.armas.portal.model.TcustpersondetailPK;
import com.fp.armas.portal.model.Tcustpersonphone;
import com.fp.armas.portal.model.TcustpersonphonePK;
import com.fp.armas.portal.model.Tgeneactivity;
import com.fp.armas.portal.model.Tgenecanton;
import com.fp.armas.portal.model.Tgenecatalogdetail;
import com.fp.armas.portal.model.Tgenecity;
import com.fp.armas.portal.model.Tgenecountry;
import com.fp.armas.portal.model.Tgenefile;
import com.fp.armas.portal.model.Tgenefilesdetail;
import com.fp.armas.portal.model.TgenefilesdetailPK;
import com.fp.armas.portal.model.Tgeneparroquia;
import com.fp.armas.portal.model.Tgeneprovince;
import com.fp.armas.portal.model.Tsafeuser;
import com.fp.armas.portal.model.Tsafeuserdetail;
import com.fp.armas.portal.model.TsafeuserdetailPK;
import com.fp.armas.portal.model.Tsafeuserprofile;
import com.fp.armas.portal.model.TsafeuserprofilePK;
import com.fp.armas.portal.util.FechaUtil;
import com.fp.armas.portal.util.PortalMessages;
import com.fp.armas.portal.util.RegistroException;
import com.fp.general.mail.EnvioMail;
import com.fp.general.mail.dto.EnvioCorreoDTO;
import com.fp.general.mail.exception.EnvioMailException;
import com.fp.general.mail.factory.EnvioMailFactory;

/**
 * Servicio que maneja la l&oacute;gica del registro de usuarios
 * @author dcruz
 *
 */
@Stateless
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class RegistroBean {
	
	/**
	 * Bean que maneja las secuencias
	 */
	@EJB
	private SequenceBean sequenceBean;

	/**
	 * Referencia al {@link CatalogoDao}
	 */
	@Inject
	private CatalogoDao catalogoDao;
	
	/**
	 * Referencia al {@link ActividadEconomicaDao}
	 */
	@Inject
	private ActividadEconomicaDao actividadEconomicaDao;
	
	/**
	 * Referencia al {@link PaisDao}
	 */
	@Inject 
	private PaisDao paisDao;
	
	/**
	 * Referencia al DAO {@link ProvinciaDao}
	 */
	@Inject
	private ProvinciaDao provinciaDao;
	
	/**
	 * Referencia al {@link CantonDao}
	 */
	@Inject
	private CantonDao cantonDao;
	
	/**
	 * Referencia al DAO {@link ParroquiaDao}
	 */
	@Inject
	private ParroquiaDao parroquiaDao;
	
	/**
	 * Referencia al DAO {@link CiudadDao}
	 */
	@Inject
	private CiudadDao ciudadDao;
	
	/**
	 * Referencia al DAO {@link PersonaDao}
	 */
	@Inject
	private PersonaDao personaDao;
	
	/**
	 * Referencia al DAO {@link PersonaDetalleDao}
	 */
	@Inject
	private PersonaDetalleDao personaDetalleDao;
	
	/**
	 * Referencia al DAO {@link DireccionPersonaDao}
	 */
	@Inject
	private DireccionPersonaDao direccionPersonaDao;
	
	/**
	 * Referencia al DAO {@link TelefonoPersonaDao}
	 */
	@Inject
	private TelefonoPersonaDao telefonoPersonaDao;
	
	/**
	 * Referencia al DAO {@link PersonaNaturalDao}
	 */
	@Inject
	private PersonaNaturalDao personaNaturalDao;
	
	/**
	 * Referencia al DAO {@link CompaniaDao}
	 */
	@Inject
	private CompaniaDao companiaDao;
	
	/**
	 * Referencia al DAO {@link UsuarioDao}
	 */
	@Inject
	private UsuarioDao usuarioDao;
	
	/**
	 * Referencia al DAO {@link UsuarioDetalleDao}
	 */
	@Inject
	private UsuarioDetalleDao usuarioDetalleDao;
	
	/**
	 * Referencia al DAO {@link UsuarioPerfilDao}
	 */
	@Inject
	private UsuarioPerfilDao usuarioPerfilDao;
	
	/**
	 * Referencia al DAO {@link ArchivoDao}
	 */
	@Inject
	private ArchivoDao archivoDao;
	
	/**
	 * Referencia al DAO {@link ArchivoDetalleDao}
	 */
	@Inject
	private ArchivoDetalleDao archivoDetalleDao;
	
	/**
	 * Retorna una colecci&oacute;n de cat&aacute;logos en base al codigo de cat&aacute;logo ingresado
	 * @param codigoTipo
	 * @return
	 * @throws RegistroException
	 */
	public Collection<Tgenecatalogdetail> obtenerCatalogo(String codigoTipo) throws RegistroException{
		try{
			return catalogoDao.buscarCatalogo(codigoTipo);
		}catch (Throwable e){
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna las actividades econ&oacute;micas disponibles
	 * @return
	 * @throws RegistroException
	 */
	public Collection<Tgeneactivity> obtenerActividades() throws RegistroException{
		try {
			return actividadEconomicaDao.buscarActividadEconomicas();
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna un cat&aacute;logo por c&oacute;digo y legalcode
	 * @param codigoTipo
	 * @param legalCode
	 * @return
	 */
	public Collection<Tgenecatalogdetail> obtenerCalogo(String codigoTipo, String legalCode) {
		try {
			return catalogoDao.buscarCatalogo(codigoTipo, legalCode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna los pa&iacute;ses disponibles en el sistema
	 * @return
	 */
	public Collection<Tgenecountry> obtenerPaises() {
		try {
			return paisDao.buscarPaises();
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna las provincias de un pa&iacute;s
	 * @param countryCode
	 * @return
	 */
	public Collection<Tgeneprovince> obtenerProvincias(String countryCode) {
		try {
			return provinciaDao.buscarProvinciasxPais(countryCode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna los cantones de una provincia 
	 * @param countryCode
	 * @param provinceCode
	 * @return
	 */
	public Collection<Tgenecanton> obtenerCantones(String countryCode, String provinceCode) {
		try {
			return cantonDao.buscarCantonesxPaisyProvincia(countryCode, provinceCode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna las parroquias de un cant&oacute;n
	 * @param countryCode
	 * @param provinceCode
	 * @param cantonCode
	 * @return
	 */
	public Collection<Tgeneparroquia> obtenerParroquias(String countryCode, String provinceCode, String cantonCode) {
		try {
			return parroquiaDao.buscarParroquias(countryCode, provinceCode, cantonCode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Retorna las ciudades de un cant&oacute;n
	 * @param countryCode
	 * @param provinceCode
	 * @param cantonCode
	 * @return
	 */
	public Collection<Tgenecity> obtenerCiudades(String countryCode, String provinceCode, String cantonCode) {
		try {
			return ciudadDao.buscarCiudad(countryCode, provinceCode, cantonCode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Genera un nuevo usuario con todas sus caracter&iacute;sticas
	 * @param persona
	 * @param direccionPersona
	 * @param correoPersona
	 * @param telefonoPersona
	 * @param telefonoCelular
	 * @param adicionalPersona
	 * @param compania
	 * @param foto
	 * @throws RegistroException
	 */
	public void guardarUsuario(Tcustpersondetail persona,
			Tcustpersonaddress direccionPersona,
			Tcustpersonaddress correoPersona, Tcustpersonphone telefonoPersona,
			Tcustpersonphone telefonoCelular, Tcustpeople adicionalPersona, Tcustcompany compania, Tgenefilesdetail foto) throws RegistroException {
		try {
			Tcustperson personaExistente = null;
			if(persona.getId() != null && persona.getId().getPersoncode() != 0){
				personaExistente = personaDao.buscarPorId(persona.getId().getPersoncode());
			}
			if(personaExistente == null){
				Future<Long> personCode = sequenceBean.retornaSecuencia("PERSONCODE"); //busco la secuencia en otro hilo de ejecucion
				Tcustperson personaRaiz = new Tcustperson();
				Long codigoPersona = personCode.get();
				personaRaiz.setPersoncode(codigoPersona);
				personaDao.create(personaRaiz);//creo persona y preparo datos para generar personadetail
				persona.setId(new TcustpersondetailPK());
				persona.getId().setPersoncode(personaRaiz.getPersoncode());
			}
			switch(persona.getIdentificationcatalog()){
				case "CED": case "PAS":{//firstname
						StringBuilder nombre = new StringBuilder(adicionalPersona.getFirstname() != null ? adicionalPersona.getFirstname():"");
//						nombre.append(" ");
//						nombre.append(adicionalPersona.getMiddlename() != null ? adicionalPersona.getMiddlename():"");
//						nombre.append(" ");
//						nombre.append(adicionalPersona.getLastname() != null ? adicionalPersona.getLastname():"");
//						nombre.append(" ");
//						nombre.append(adicionalPersona.getSurename() != null ? adicionalPersona.getSurename():"");
						persona.setName(nombre.toString());
						persona.setPersontypecatalog("1");
						persona.setPersontypecatalogcode("PERSONTYPE");
				}
				break;
				default: {
					persona.setPersontypecatalog("2");
					persona.setPersontypecatalogcode("PERSONTYPE");
				}
				break;
			}
			this.guardaPersonaDetalle(persona);
			this.guardarDireccionesPersona(persona, direccionPersona, correoPersona);
			this.guardarTelefonosPersona(persona, direccionPersona, telefonoPersona, telefonoCelular);
			this.guardaDetallesPersonaNatural(persona, adicionalPersona);
			this.guardaCompania(persona, compania, foto);
			this.guardarUsuario(persona, correoPersona);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Obtiene persona por identificaci&oacute;n
	 * @param codigoIdentificacion
	 * @return
	 * @throws RegistroException
	 */
	public Tcustpersondetail obtenerPersonaPorIdentificacion(String codigoIdentificacion) throws RegistroException{
		try{
			return personaDetalleDao.buscarPorIdentificacion(codigoIdentificacion);
		}catch(Throwable e){
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Obtener compan&iacute;a en base al id
	 * @param personcode
	 * @return
	 * @throws RegistroException
	 */
	public Tcustcompany obtenerCompania(Integer personcode) throws RegistroException{
		try {
			TcustcompanyPK pk = new TcustcompanyPK();
			pk.setPersoncode(personcode);
			pk.setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
			return companiaDao.buscarPorId(pk);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Obtener informaci&oacute;n de la persona natural en base al id
	 * @param personcode
	 * @return
	 */
	public Tcustpeople obtenerPersonaNaturalId(Integer personcode) {
		try {
			TcustpeoplePK pk = new TcustpeoplePK();
			pk.setPersoncode(personcode);
			pk.setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
			return personaNaturalDao.buscarPorId(pk);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Busca y devuelve la direcci&oacute;n principal de la persona
	 * @param personcode
	 * @return
	 */
	public Tcustpersonaddress obtenerDireccionPrincipal(Integer personcode) {
		try {
			return direccionPersonaDao.buscaDireccionPrincipal(personcode);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Busca y devuelve la direcci&oacute;n de correo de la persona
	 * @param personcode
	 * @return
	 */
	public Tcustpersonaddress obtenerDireccionCorreo(Integer personcode) {
		try {
			return direccionPersonaDao.buscaDireccionPorTipo(personcode, PortalMessages.getInstancia().getString("catalogo.valor.direccion.correo"));
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Busca y devuelve el tel&eacute;fono fijo de la persona
	 * @param personcode
	 * @return
	 */
	public Tcustpersonphone obtenerTelefonoFijo(Integer personcode) {
		try {
			return telefonoPersonaDao.obtenerTelefonoTipo(personcode, PortalMessages.getInstancia().getString("catalogo.valor.telefono.fijo"));
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Busca y devuelve el tel&eacute;fono celular de la persona
	 * @param personcode
	 * @return
	 */
	public Tcustpersonphone obtenerTelefonoCelular(Integer personcode) {
		try {
			return telefonoPersonaDao.obtenerTelefonoTipo(personcode, PortalMessages.getInstancia().getString("catalogo.valor.telefono.celular"));
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	/**
	 * M&eacute;todo en donde almaceno los detalles del usuario, datos adicionales
	 * @param persona
	 * @param direccionPersona
	 * @param correoPersona
	 * @param telefonoPersona
	 * @param telefonoCelular
	 * @param adicionalPersona
	 */
	private void guardaPersonaDetalle(Tcustpersondetail persona){
		try {
			Tcustpersondetail personaAnterior = personaDetalleDao.buscarPorId(new TcustpersondetailPK(persona.getId().getPersoncode(), persona.getId().getDateto()));
			if(personaAnterior == null){
				persona.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
				persona.setDatefrom(new Timestamp(System.currentTimeMillis()));
				persona.setRecordversion(0L);
				persona.setIngressuser(PortalMessages.getInstancia().getString("usuario.registro"));
				persona.setLanguagecode(PortalMessages.getInstancia().getString("codigo.general.lenguaje"));
				persona.setCompanycode(1L);
				persona.setBranchcode(1L);
				persona.setOfficecode(1L);
				persona.setIdentificationcatalogcode("IDENTIFICATION");
				persona.setRegisterdate(Calendar.getInstance().getTime());
				personaDetalleDao.create(persona);
			} else{//actualizacion
				personaDetalleDao.detach(personaAnterior);
				personaAnterior.getId().setDateto(new Date());
				personaAnterior.setIdentificationcatalogcode("IDENTIFICATION");				
				personaDetalleDao.create(personaAnterior);
				persona.setIdentificationcatalogcode("IDENTIFICATION");
				personaDetalleDao.update(persona);
			}
			
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Almaceno la informaci&oacute;n de las direcciones de las personas
	 * @param persona
	 * @param direccionPersona
	 * @param correoPersona
	 */
	private void guardarDireccionesPersona(Tcustpersondetail persona, Tcustpersonaddress direccionPersona,
			Tcustpersonaddress correoPersona){
		try {
			// Limpiar las direcciones domicilio previas existentes en caso de existir
			List<Tcustpersonaddress>direccionesDomPreviasLst = direccionPersonaDao.buscaDireccionesPorTipo(persona.getId().getPersoncode(), "2");
			if(direccionesDomPreviasLst!=null){
				for(Tcustpersonaddress direccionTmp:direccionesDomPreviasLst){
					direccionTmp.getId().setDateto(new Date());
					direccionPersonaDao.update(direccionTmp);
					direccionPersonaDao.getEntityManager().flush();
				}
			}
			// Limpiar las direcciones correo previas existentes en caso de existir
			List<Tcustpersonaddress>direccionesCorreoPreviasLst = direccionPersonaDao.buscaDireccionesPorTipo(persona.getId().getPersoncode(), "3");
			if(direccionesCorreoPreviasLst!=null){
				for(Tcustpersonaddress direccionTmp:direccionesCorreoPreviasLst){
					direccionTmp.getId().setDateto(new Date());
					direccionPersonaDao.update(direccionTmp);
					direccionPersonaDao.getEntityManager().flush();
				}
			}
			if(direccionPersona.getId() == null || direccionPersona.getId().getPersoncode() == 0){
				//Ingreso la direccion de residencia de la persona
				direccionPersona.setId(new TcustpersonaddressPK());
				direccionPersona.getId().setPersoncode(persona.getId().getPersoncode());
				direccionPersona.getId().setAddressnumber(1L);
				direccionPersona.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
				direccionPersona.setDatefrom(new Timestamp(System.currentTimeMillis()));
				direccionPersona.setPrincipal(PortalMessages.getInstancia().getString("valor.general.si"));
				direccionPersona.setRecordversion(0L);
				direccionPersona.setIngressusercode(PortalMessages.getInstancia().getString("usuario.registro"));
				Tcustpersonaddress direccionAnterior = direccionPersonaDao.buscarPorId(new TcustpersonaddressPK(direccionPersona.getId().getPersoncode(), direccionPersona.getId().getAddressnumber(), direccionPersona.getId().getDateto()));
				if(direccionAnterior==null){
					direccionPersonaDao.create(direccionPersona);
				}
				else{
					direccionAnterior.setPrincipal(PortalMessages.getInstancia().getString("valor.general.si"));
					direccionAnterior.setAddress(direccionPersona.getAddress());
					direccionAnterior.setDatefrom(new Timestamp(System.currentTimeMillis()));
					direccionAnterior.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
					direccionPersonaDao.update(direccionAnterior);
				}
			} 
			else{
//				Tcustpersonaddress direccionAnterior = direccionPersonaDao.buscarPorId(new TcustpersonaddressPK(direccionPersona.getId().getPersoncode(), direccionPersona.getId().getAddressnumber(), direccionPersona.getId().getDateto()));
//				if(direccionAnterior != null){
//					direccionPersonaDao.detach(direccionAnterior);
//					direccionAnterior.getId().setDateto(new Date());
//					direccionPersonaDao.create(direccionAnterior);
//				}
				direccionPersona.setDatefrom(new Timestamp(System.currentTimeMillis()));
				direccionPersona.setPrincipal(PortalMessages.getInstancia().getString("valor.general.si"));
				direccionPersonaDao.update(direccionPersona);
			}
			if(correoPersona.getId() == null || correoPersona.getId().getPersoncode() == 0){
				//Ingreso la direccion de correo de la persona
				correoPersona.setId(new TcustpersonaddressPK());
				correoPersona.getId().setPersoncode(persona.getId().getPersoncode());
				correoPersona.getId().setAddressnumber(2L);
				correoPersona.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
				correoPersona.setDatefrom(new Timestamp(System.currentTimeMillis()));
				correoPersona.setRecordversion(0L);
				correoPersona.setIngressusercode(PortalMessages.getInstancia().getString("usuario.registro"));
				Tcustpersonaddress correoAnterior = direccionPersonaDao.buscarPorId(new TcustpersonaddressPK(correoPersona.getId().getPersoncode(), correoPersona.getId().getAddressnumber(), correoPersona.getId().getDateto()));
				if(correoAnterior==null){
					direccionPersonaDao.create(correoPersona);
				}
				else{	
					correoAnterior.getId().setAddressnumber(2L);
					correoAnterior.setAddress(correoPersona.getAddress());
					correoAnterior.setAddresstypecatalog("3");
					correoAnterior.setCountryCode(null);
					correoAnterior.setProvinceCode(null);
					correoAnterior.setCantonCode(null);
					correoAnterior.setCityCode(null);
					correoAnterior.setParroquiaCode(null);
					correoAnterior.setPrincipal(null);
					correoAnterior.setDatefrom(new Timestamp(System.currentTimeMillis()));
					correoAnterior.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
					direccionPersonaDao.update(correoAnterior);
				}
			} 
			else{
//				Tcustpersonaddress correoAnterior = direccionPersonaDao.buscarPorId(new TcustpersonaddressPK(correoPersona.getId().getPersoncode(), correoPersona.getId().getAddressnumber(), correoPersona.getId().getDateto()));
//				if(correoAnterior != null){
//					direccionPersonaDao.detach(correoAnterior);
//					correoAnterior.getId().setDateto(new Date());
//					direccionPersonaDao.create(correoAnterior);
//				}
				direccionPersonaDao.update(correoPersona);
			}
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	} 
	
	/**
	 * Almaceno la informaci&oacute;n correspondientes a los tel&eacute;fonos de la persona
	 * @param persona
	 * @param telefonoPersona
	 * @param telefonoCelular
	 */
	private void guardarTelefonosPersona(Tcustpersondetail persona, Tcustpersonaddress direccionPersona, Tcustpersonphone telefonoPersona,
			Tcustpersonphone telefonoCelular){
		try {
			// Limpiar los telefonos previos convencionales existentes en caso de existir
			List<Tcustpersonphone>telefonoConvPreviosLst = telefonoPersonaDao.obtenerTelefonosPorTipo(persona.getId().getPersoncode(), "1");
			if(telefonoConvPreviosLst!=null){
				for(Tcustpersonphone telefonoTmp:telefonoConvPreviosLst){
					telefonoTmp.getId().setDateto(new Date());
					telefonoPersonaDao.update(telefonoTmp);
				}
			}
			// Limpiar los telefonos previos celulares existentes en caso de existir
			List<Tcustpersonphone>telefonoCelularPreviosLst = telefonoPersonaDao.obtenerTelefonosPorTipo(persona.getId().getPersoncode(), "2");
			if(telefonoCelularPreviosLst!=null){
				for(Tcustpersonphone telefonoTmp:telefonoCelularPreviosLst){
					telefonoTmp.getId().setDateto(new Date());
					telefonoPersonaDao.update(telefonoTmp);
				}
			}		
			
			if(telefonoPersona.getId() == null || telefonoPersona.getId().getPersoncode() == 0){
				Long sec=telefonoPersonaDao.maxSecuencia(persona.getId().getPersoncode());
				//El telefono corresponde a la direccion de la persona
				telefonoPersona.setId(new TcustpersonphonePK());
				telefonoPersona.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
				if(sec==null || sec==0){
					telefonoPersona.getId().setPhonesequence(1L);
				}else{
					telefonoPersona.getId().setPhonesequence(sec+1L);
				}
				telefonoPersona.getId().setPersoncode(persona.getId().getPersoncode());
				telefonoPersona.setDatefrom(new Timestamp(System.currentTimeMillis()));
				telefonoPersona.setAddressnumber(direccionPersona.getId().getAddressnumber());
				telefonoPersona.setIngressusercode(PortalMessages.getInstancia().getString("usuario.registro"));
				telefonoPersonaDao.create(telefonoPersona);
			} 
			else{
//				Tcustpersonphone telefonoPersonaAnterior = telefonoPersonaDao.buscarPorId(new TcustpersonphonePK(telefonoPersona.getId().getPersoncode(), telefonoPersona.getId().getDateto(),telefonoPersona.getId().getPhonesequence()));
//				if(telefonoPersonaAnterior != null){
//					telefonoPersonaDao.detach(telefonoPersonaAnterior);
//					telefonoPersonaAnterior.getId().setDateto(new Date());
//					telefonoPersonaDao.update(telefonoPersonaAnterior);
//				}
				telefonoPersonaDao.update(telefonoPersona);
			}
			if(telefonoCelular.getId() == null || telefonoCelular.getId().getPersoncode() == 0){
				//Almaceno el telefono celular
				telefonoCelular.setId(new TcustpersonphonePK());
				telefonoCelular.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
				Long sec=telefonoPersonaDao.maxSecuencia(persona.getId().getPersoncode());
				if(sec==null || sec==0){
					telefonoCelular.getId().setPhonesequence(1L);
				}else{
					telefonoCelular.getId().setPhonesequence(sec+1L);
				}
				//telefonoCelular.getId().setPhonesequence(2L);
				telefonoCelular.getId().setPersoncode(persona.getId().getPersoncode());
				telefonoCelular.setDatefrom(new Timestamp(System.currentTimeMillis()));
				telefonoCelular.setAddressnumber(direccionPersona.getId().getAddressnumber());
				telefonoCelular.setIngressusercode(PortalMessages.getInstancia().getString("usuario.registro"));
				telefonoPersonaDao.create(telefonoCelular);
			} 
			else{
//				Tcustpersonphone telefonoCelularAnterior = telefonoPersonaDao.buscarPorId(new TcustpersonphonePK(telefonoCelular.getId().getPersoncode(), telefonoCelular.getId().getDateto(), telefonoCelular.getId().getPhonesequence()));
//				if(telefonoCelularAnterior != null){
//					telefonoPersonaDao.detach(telefonoCelularAnterior);
//					telefonoCelularAnterior.getId().setDateto(new Date());
//					telefonoPersonaDao.update(telefonoCelularAnterior);
//				}
				telefonoPersonaDao.update(telefonoCelular);
			}
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	/**
	 * Almaceno informaci&oacute;n adicional siempre y cuando la persona sea de tipo natural
	 * @param persona
	 */
	private void guardaDetallesPersonaNatural(Tcustpersondetail persona, Tcustpeople adicionalPersona){
		// Actualizar dateto de registros previos vigentes
		List<Tcustpeople>personasNaturalesPreviasLst = personaNaturalDao.buscaPersonaNatural(persona.getId().getPersoncode());
		if(personasNaturalesPreviasLst!=null){
			for(Tcustpeople peopleTmp:personasNaturalesPreviasLst){
				peopleTmp.getId().setDateto(new Date());
				personaNaturalDao.update(peopleTmp);
			}
		}
		
		//Si no es natural no se debe anadir detalles
		if(!persona.getIdentificationcatalog().equals(PortalMessages.getInstancia().getString("catalogo.codigo.detalle.id.cedula")) && !persona.getIdentificationcatalog().equals(PortalMessages.getInstancia().getString("catalogo.codigo.detalle.id.pas"))){
			return;
		}
		if(adicionalPersona.getId() == null || adicionalPersona.getId().getPersoncode() == 0){
			adicionalPersona.setId(new TcustpeoplePK());
			adicionalPersona.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
			adicionalPersona.getId().setPersoncode(persona.getId().getPersoncode());
			adicionalPersona.setDatefrom(new Timestamp(System.currentTimeMillis()));
			adicionalPersona.setRecordversion(0L);
			adicionalPersona.setIngressusercode(PortalMessages.getInstancia().getString("usuario.registro"));
			personaNaturalDao.create(adicionalPersona);
		} 
		else{
//			Tcustpeople adicionalAnterior = personaNaturalDao.buscarPorId(new TcustpeoplePK(adicionalPersona.getId().getPersoncode(), adicionalPersona.getId().getDateto()));
//			if(adicionalAnterior != null){
//				personaNaturalDao.detach(adicionalAnterior);
//				adicionalAnterior.getId().setDateto(new Date());
//				personaNaturalDao.update(adicionalAnterior);
//			}			
			personaNaturalDao.update(adicionalPersona);
		}
	}
	
	/**
	 * Guarda la compan&iacute;a si es que es persona jur&iacute;dica
	 * @param persona
	 * @param compania
	 * @param foto
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	private void guardaCompania(Tcustpersondetail persona, Tcustcompany compania, Tgenefilesdetail foto) throws InterruptedException, ExecutionException {
		if(!persona.getIdentificationcatalog().equals(PortalMessages.getInstancia().getString("catalogo.codigo.detalle.id.ruc"))){
			return;
		}
		if(compania.getId() == null || compania.getId().getPersoncode() == 0){
			compania.setId(new TcustcompanyPK());
			compania.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
			compania.getId().setPersoncode(persona.getId().getPersoncode());
			compania.setDatefrom(new Timestamp(System.currentTimeMillis()));
			compania.setLogo(guardaFoto(foto));
			compania.setRecordversion(0L);
			compania.setIngressuser(PortalMessages.getInstancia().getString("usuario.registro"));
			companiaDao.create(compania);
		} else{
			Tcustcompany companiaAnterior = companiaDao.buscarPorId(new TcustcompanyPK(compania.getId().getPersoncode(), compania.getId().getDateto()));
			if(companiaAnterior != null){
				companiaDao.detach(companiaAnterior);
				companiaAnterior.getId().setDateto(new Date());
				companiaDao.create(companiaAnterior);
			}
			Tgenefilesdetail fotoBase = archivoDetalleDao.buscarPorId(new TgenefilesdetailPK(compania.getLogo() != null ? compania.getLogo() : -1, FechaUtil.obtenerFecha(2999, 11, 31)));
			if(fotoBase != null){
				fotoBase.setImage(foto.getImage());
				archivoDetalleDao.update(fotoBase);
			} else{
				compania.setLogo(guardaFoto(foto));
			}
			companiaDao.update(compania);
		}
	}
	
	/**
	 * Almacena la foto o logo de la persona natural o jur&iacute;dica
	 * @param fotoDetalle
	 * @return
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	private Integer guardaFoto(Tgenefilesdetail fotoDetalle) throws InterruptedException, ExecutionException{
		Long idFoto = null;
		if(fotoDetalle != null && fotoDetalle.getImage() != null){
			Future<Long> code = sequenceBean.retornaSecuencia("CODE");
			Tgenefile foto = new Tgenefile();
			fotoDetalle.setId(new TgenefilesdetailPK());
			fotoDetalle.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
			fotoDetalle.setDatefrom(new Timestamp(System.currentTimeMillis()));
			fotoDetalle.setIngressuser(PortalMessages.getInstancia().getString("usuario.registro"));
			idFoto = code.get();
			foto.setCode(idFoto);
			fotoDetalle.getId().setCode(foto.getCode());
			archivoDao.create(foto);
			archivoDetalleDao.create(fotoDetalle);
		}
		return idFoto != null ? idFoto.intValue() : null;
	}
	
	/**
	 * Guardo el usuario y el detalles de dicho usuario asociado a una persona y perfil default
	 * @throws ExecutionException 
	 * @throws InterruptedException 
	 */
	@SuppressWarnings("unchecked")
	private void guardarUsuario(Tcustpersondetail persona, Tcustpersonaddress correoPersona) throws InterruptedException, ExecutionException{
		String claveAleatoria = generarClaveAleatoria();
		Tsafeuserdetail usuarioDetalle = new Tsafeuserdetail();
		List<Tsafeuserdetail> userDetailList = usuarioDetalleDao.buscaUserDetail(persona.getId().getPersoncode()); 
//		if(persona.getId() == null || persona.getId().getPersoncode() == 0){
		if(userDetailList==null){
			crearUsuario(usuarioDetalle, persona, claveAleatoria);
			crearUsuarioPerfil(usuarioDetalle);
		} else{
			Query query = usuarioDetalleDao.getEntityManager().createQuery("SELECT o FROM Tsafeuserdetail o WHERE o.id.personcode=:personcode and o.id.dateto=:dateto");
			query.setParameter("personcode", persona.getId().getPersoncode());
			query.setParameter("dateto", FechaUtil.obtenerFecha(2999, 11, 31));
			List<Tsafeuserdetail> lusers = query.getResultList();
			if(lusers != null && !lusers.isEmpty()){//existe actualizamos
				usuarioDetalle = lusers.iterator().next();
				Tsafeuserdetail usuarioAnterior = SerializationUtils.clone(usuarioDetalle);
				usuarioDetalleDao.detach(usuarioAnterior);
				usuarioAnterior.getId().setDateto(new Date());
				usuarioDetalleDao.create(usuarioAnterior);
				usuarioDetalle.setPassword(SerializationUtils.clone(DigestUtils.sha1Hex(claveAleatoria)));
				usuarioDetalleDao.update(usuarioDetalle);
			} else{//no existe creamos con todo y perfil
				crearUsuario(usuarioDetalle, persona, claveAleatoria);
				crearUsuarioPerfil(usuarioDetalle);
			}
		}
               
                this.enviarMailAcceso(persona, usuarioDetalle, correoPersona, claveAleatoria);
	}
	
	private void crearUsuario(Tsafeuserdetail usuarioDetalle, Tcustpersondetail persona, String claveAleatoria) throws InterruptedException, ExecutionException{
		Tsafeuser usuario = new Tsafeuser();
		Future<Long> internalCode = sequenceBean.retornaSecuencia("INTERNALCODE");
		usuario.setCompanycode(Long.parseLong(PortalMessages.getInstancia().getString("compania.general")));
		usuario.setTcustperson(persona.getTcustperson());
		usuario.setUsercode(persona.getIdentification());
		usuario.setPersonCode(persona.getId().getPersoncode());
		usuario.setInternalcode(internalCode.get());
		List<Tsafeuser> usuariosList= usuarioDao.buscaUsers(persona.getIdentification());
		if(usuariosList==null){
			usuarioDao.create(usuario);
		}		
		usuarioDetalle.setId(new TsafeuserdetailPK());
		usuarioDetalle.getId().setUsercode(usuario.getUsercode());
		usuarioDetalle.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
		usuarioDetalle.getId().setPersoncode(persona.getId().getPersoncode());
		usuarioDetalle.setDatefrom(new Timestamp(System.currentTimeMillis()));
		usuarioDetalle.setLanguagecode(PortalMessages.getInstancia().getString("codigo.general.lenguaje"));
		usuarioDetalle.setCompanycode(Long.parseLong(PortalMessages.getInstancia().getString("compania.general")));
		usuarioDetalle.setChannelcode(PortalMessages.getInstancia().getString("codigo.canal.validacion.usuario"));
		usuarioDetalle.setAreacode(Long.parseLong(PortalMessages.getInstancia().getString("area.general")));
		usuarioDetalle.setBranchcode(Long.parseLong(PortalMessages.getInstancia().getString("codigo.sucursal.usuario")));
		usuarioDetalle.setOfficecode(Long.parseLong(PortalMessages.getInstancia().getString("codigo.oficina.usuario")));
		usuarioDetalle.setUserstatuscatalogcode(PortalMessages.getInstancia().getString("catalogo.codigo.estado.usuario"));
		usuarioDetalle.setUserstatuscatalog(PortalMessages.getInstancia().getString("valor.general.activo"));
		usuarioDetalle.setIngressuser(PortalMessages.getInstancia().getString("usuario.registro"));
		usuarioDetalle.setIsuserbpm(PortalMessages.getInstancia().getString("valor.general.si"));
		usuarioDetalle.setChangepassword(PortalMessages.getInstancia().getString("valor.general.si"));
		usuarioDetalle.setActivateuser(PortalMessages.getInstancia().getString("usuario.registro"));
		usuarioDetalle.setPassword(DigestUtils.sha1Hex(SerializationUtils.clone(claveAleatoria)));
		usuarioDetalle.setNickname(persona.getIdentification());
		usuarioDetalle.setRecordversion(0L);
		usuarioDetalleDao.create(usuarioDetalle);
	}
	
	private void crearUsuarioPerfil(Tsafeuserdetail usuarioDetalle){
		Tsafeuserprofile perfilUsuario = new Tsafeuserprofile();
		perfilUsuario.setId(new TsafeuserprofilePK());
		perfilUsuario.getId().setProfilecode(PortalMessages.getInstancia().getString("codigo.perfil.usuario.registro"));
		perfilUsuario.getId().setUsercode(usuarioDetalle.getId().getUsercode());
		perfilUsuario.getId().setDateto(FechaUtil.obtenerFecha(2999, 11, 31));
		perfilUsuario.setDatefrom(new Timestamp(System.currentTimeMillis()));
		perfilUsuario.setIngressuser(PortalMessages.getInstancia().getString("usuario.registro"));
		usuarioPerfilDao.create(perfilUsuario);
	}
	
	/**
	 * M&eacute;todo que genera el cuerpo del mensaje a enviar a los nuevos usuarios registrados y activaci&oacute;n del mismos
	 */
	private void enviarMailAcceso(Tcustpersondetail detallePersona, Tsafeuserdetail detalleUsuario, Tcustpersonaddress correoPersona, String digest){
		try {
			String asunto = PortalMessages.getInstancia().getString("asunto.mensaje.envio.correo");
			String cuerpo = MessageFormat.format(PortalMessages.getInstancia().getString("cuerpo.mensaje.envio.correo"), detallePersona.getName(), detalleUsuario.getId().getUsercode(), digest);
			EnvioCorreoDTO envioCorreo = new EnvioCorreoDTO();
			envioCorreo.setCorreoDesde(PortalMessages.getInstancia().getString("correo.envio.default.notificiacion"));
			envioCorreo.setCorreoPara(new String[]{correoPersona.getAddress()});
			envioCorreo.setAsunto(asunto);
			envioCorreo.setMensajeHTML(cuerpo);
			EnvioMail envioMail = EnvioMailFactory.getInstancia();
			envioMail.envioMail(envioCorreo);
		} catch(EnvioMailException e){
			throw new RegistroException("Se produjo un error al enviar el correo ".concat(e.getMessage()));
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
	
	private String generarClaveAleatoria(){
		return UUID.randomUUID().toString().substring(0, 8);
	}
	
	/**
	 * Obtener informaci&oacute;n de las imagenes
	 * @param personcode
	 * @return
	 */
	public Tgenefilesdetail obtenerImagen(long code) {
		try {
			
			TgenefilesdetailPK pk = new TgenefilesdetailPK();
			pk.setCode(code);
			pk.setDateto(FechaUtil.obtenerFecha(2999, Calendar.DECEMBER, 31));
			return archivoDetalleDao.buscarPorId(pk);
		} catch (Throwable e) {
			throw new RegistroException(e);
		}
	}
}
