/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rjconsultores.ventaboletos.entidad;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.utilerias.ApplicationProperties;
import com.rjconsultores.ventaboletos.utilerias.CustomEnum;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.web.utilerias.security.SecurityEmpresaToken;
import com.rjconsultores.ventaboletos.web.utilerias.spring.AppContext;

import br.com.rjconsultores.auditador.annotations.AuditarAtributo;
import br.com.rjconsultores.auditador.annotations.AuditarClasse;
import br.com.rjconsultores.auditador.annotations.AuditarID;
import br.com.rjconsultores.auditador.annotations.AuditarLista;
import br.com.rjconsultores.auditador.annotations.NaoAuditar;
import br.com.rjconsultores.auditador.interfaces.Auditavel;

/**
 * 
 * @author rodrigo
 */
@AuditarClasse(nome = "USUARIO", tela = "auditarClasse.Usuario")
@Entity
@SequenceGenerator(name = "USUARIO_SEQ", sequenceName = "USUARIO_SEQ", allocationSize = 1)
@Table(name = "USUARIO")
public class Usuario implements Serializable, UserDetails,  Auditavel<Usuario> {
	
	public final static int CANT_DIAS_CONTRASENA = 999;
	private static Logger log = LogManager.getLogger(Usuario.class);

	private static final long serialVersionUID = 1L;
	@AuditarID
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "USUARIO_SEQ")
	@Basic(optional = false)
	@Column(name = "USUARIO_ID")
	private Integer usuarioId;
	
	@Column(name = "NOMBUSUARIO")
	private String nombusuario;
	
	@Column(name = "NOMBPATERNO")
	private String nombpaterno;
	
	@Column(name = "NOMBMATERNO")
	private String nombmaterno;
	
	@Column(name = "ACTIVO")
	private Boolean activo;
	
	@Column(name = "FECMODIF")
	@Temporal(TemporalType.TIMESTAMP)
	private Date fecmodif;
	
	@Column(name = "USUARIOMODIF_ID")
	private Integer usuariomodifId;
	
	@Column(name = "DESCCONTRASENA")
	private String senha;
	
	@Column(name = "CVEUSUARIO")
	private String claveUsuario;
	
	@Column(name = "DESCCORREO")
	private String descCorreo;
	
	@OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@AuditarLista(auditarEntidades = true, nome = "Perfil")
	private List<UsuarioPerfil> usuarioPerfilList;
	
	@Column(name = "INDCORTEAUTOMATICO")
	private Boolean indCorteAutomatico;
	
	@OneToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "EMPLEADO_ID")
	private Empleado empleado;
	
	@OneToMany(mappedBy = "usuarioLog", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@Fetch(FetchMode.SELECT)
	@NaoAuditar
	private List<UsuarioEmpresa> usuarioEmpresaList;

	@OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@Fetch(FetchMode.SELECT)
	@OrderBy("padrao desc") 
	@NaoAuditar
	private List<UsuarioUbicacion> usuarioUbicacionList;

	@Column(name = "FECCONTRASENA")
	@Temporal(TemporalType.TIMESTAMP)
	private Date fecContrasena;
	
	@Column(name = "DESCMAC")
	private String descMac;
	
	@Column(name = "TEMPODEVOLUCAOPASSAGEM")
	private Integer tempoDevolucaoPassagem;
	
	@Column(name = "INDEXPIRASENHA")
	private Boolean indExpiraSenha;

	@Column(name = "ESTACIONINTERNET_ID")
	private Long estacionInternetId;

	@Column(name = "TIPOVENTAINTEGRACAO_ID")
	private Long tipoVentaIntegracaoId;

	/* Lista de permissoes do usuario */
	@Transient
	private List<String> listClavesPermisos;
	
	@Column(name = "INDRETORNATODASLOCALIDADES")
	private Boolean indRetornaTodasLocalidades;
	
	@Column(name = "INDTROCASENHA")
	private Boolean indTrocaSenha;
	
	@Column(name = "INDRECUPERARSENHA")
	private Boolean indRecuperarSenha;
	
	@Column(name = "NOMBPATERNORECUPERAR")
	private String nombpaternoRecuperacao;
	
	@Column(name = "MATRICULA")
	private String matricula;
	
	@Column(name = "DATANASCIMENTO")
    @Temporal(TemporalType.TIMESTAMP)
    @AuditarAtributo(pattern = "dd/MM/yyyy", nome = "Data Nascimento")
    private Date dataNascimento;
	
	@Transient
	@NaoAuditar
	private Usuario usuarioClone;

	public String getClaveUsuario() {
		return claveUsuario;
	}

	public void setClaveUsuario(String claveUsuario) {
		this.claveUsuario = claveUsuario;
	}

	public Usuario() {
		tempoDevolucaoPassagem = -1;
		indExpiraSenha = false;
	}

	public Usuario(Integer usuarioId) {
		this.usuarioId = usuarioId;
		tempoDevolucaoPassagem = -1;
		indExpiraSenha = false;
	}

	public Integer getUsuarioId() {
		return usuarioId;
	}

	public void setUsuarioId(Integer usuarioId) {
		this.usuarioId = usuarioId;
	}

	public String getNombusuario() {
		return nombusuario;
	}

	public void setNombusuario(String nombusuario) {
		this.nombusuario = nombusuario;
	}

	public String getNombpaterno() {
		return nombpaterno;
	}

	public void setNombpaterno(String nombpaterno) {
		this.nombpaterno = nombpaterno;
	}

	public String getNombmaterno() {
		return nombmaterno;
	}

	public void setNombmaterno(String nombmaterno) {
		this.nombmaterno = nombmaterno;
	}

	public Boolean getActivo() {
		return activo;
	}

	public void setActivo(Boolean activo) {
		this.activo = activo;
	}

	public Date getFecmodif() {
		return fecmodif;
	}

	public void setFecmodif(Date fecmodif) {
		this.fecmodif = fecmodif;
	}

	public Integer getUsuariomodifId() {
		return usuariomodifId;
	}

	public void setUsuariomodifId(Integer usuariomodifId) {
		this.usuariomodifId = usuariomodifId;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public List<UsuarioEmpresa> getUsuarioEmpresaList() {
		List<UsuarioEmpresa> tmp = new ArrayList<UsuarioEmpresa>();
		if (usuarioEmpresaList != null) {
			for (UsuarioEmpresa ce : this.usuarioEmpresaList) {
				if (ce.getActivo()) {
					tmp.add(ce);
				}
			}
		}

		return tmp;
	}

	public void setUsuarioEmpresaList(List<UsuarioEmpresa> usuarioEmpresaList) {
		this.usuarioEmpresaList = usuarioEmpresaList;
	}

	public List<UsuarioPerfil> getUsuarioPerfilList() {
		List<UsuarioPerfil> tmp = new ArrayList<UsuarioPerfil>();
		if (usuarioPerfilList != null) {
			for (UsuarioPerfil cp : this.usuarioPerfilList) {
				if (cp.getActivo()) {
					tmp.add(cp);
				}
			}
		}

		return tmp;
	}

	public List<Empresa> getEmpresa() {
		List<Empresa> tmp = new ArrayList<Empresa>();
		
		SecurityEmpresaToken security = new SecurityEmpresaToken();
		
		if (usuarioEmpresaList != null) {
			for (UsuarioEmpresa cp : this.usuarioEmpresaList) {
				if ((cp.getActivo())) {
					Empresa empresa = cp.getEmpresa();
					boolean licenseValidate = false;
					
					try{
						licenseValidate = security.licenseValidate(empresa.getLicenca(), empresa.getEmpresaId(), empresa.getCnpj());	
					}catch(Throwable th){
						log.error(String.format("Licença não validada para a empresaId: %s e cnpj: %s", empresa.getEmpresaId(),empresa.getCnpj()), th);
					}
					
					
					if (licenseValidate){
						tmp.add(cp.getEmpresa());
					}
				}
			}
		}

		return tmp;
	}

	public void setUsuarioPerfilList(List<UsuarioPerfil> usuarioPerfilList) {
		this.usuarioPerfilList = usuarioPerfilList;
	}

	public Empleado getEmpleado() {
		return empleado;
	}

	public void setEmpleado(Empleado empleado) {
		this.empleado = empleado;
	}
	
	public void updateUsuarioUbicacionForClonedUser(){
		for (UsuarioUbicacion ub : usuarioUbicacionList){
			ub.setUsuarioubicacionId(null);
		}
	}

	public void updateUsuarioEmpresaForClonedUser(){
		for (UsuarioEmpresa ue : usuarioEmpresaList){
			ue.setUsuarioEmpresaId(null);
		}
	}
	
	public void updateUsuarioPerfilForClonedUser(){
		for (UsuarioPerfil ub : usuarioPerfilList){
			ub.setUsuarioperfilId(null);
		}
	}
	
	@Override
	public int hashCode() {
		int hash = 0;
		hash += (usuarioId != null ? usuarioId.hashCode() : 0);
		return hash;
	}

	@Override
	public boolean equals(Object object) {
		if (!(object instanceof Usuario)) {
			return false;
		}
		Usuario other = (Usuario) object;
		if ((this.usuarioId == null && other.usuarioId != null) || (this.usuarioId != null && !this.usuarioId.equals(other.usuarioId))) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		return getNombUsuarioCompleto();
	}

	public Collection<GrantedAuthority> getAuthorities() {
		return new ArrayList<GrantedAuthority>();
	}

	public String getPassword() {
		return this.senha;
	}

	public String getUsername() {
		return this.nombusuario;
	}

	public boolean isAccountNonExpired() {
		return true;
	}

	public boolean isAccountNonLocked() {
		return true;
	}

	public boolean isCredentialsNonExpired() {
		if (ApplicationProperties.getInstance().isCustomHabilitado(CustomEnum.CONTRASENA_VALIDA_COMPLEJIDAD.getDescricao())) {
			if (getFecContrasena() != null) {
				ConstanteService constanteService = (ConstanteService) AppContext.getApplicationContext().getBean("constanteService");
				Constante contante = constanteService.buscarPorNomeConstante("CANT_DIAS_CONTRASENA");
				
				Integer maxPrazoCambioContrasena = CANT_DIAS_CONTRASENA;
				
				if ( (contante != null && (StringUtils.isNotBlank(contante.getValorconstante() )))){
					maxPrazoCambioContrasena = Integer.valueOf(contante.getValorconstante());
				}
				
				Date maxFechaContrasena = DateUtil.somarDias(getFecContrasena(), maxPrazoCambioContrasena);
				
				if (Calendar.getInstance().getTime().after(maxFechaContrasena)) {
					return false;
				}
			} else {
				return false;
			}
		}

		return true;
	}

	public boolean isEnabled() {
		return true;
	}

	public Object getCredentials() {
		return new Object();
	}

	public Object getDetails() {
		return new Object();
	}

	public Object getPrincipal() {
		return this;
	}

	public boolean isAuthenticated() {
		return Boolean.TRUE;
	}

	public void setAuthenticated(boolean bln) throws IllegalArgumentException {
	}

	public String getName() {
		return this.getNombusuario();
	}

	public String getDescCorreo() {
		return descCorreo;
	}

	public void setDescCorreo(String descCorreo) {
		this.descCorreo = descCorreo;
	}

	public Boolean getIndCorteAutomatico() {
		return indCorteAutomatico;
	}

	public void setIndCorteAutomatico(Boolean indCorteAutomatico) {
		this.indCorteAutomatico = indCorteAutomatico;
	}

	public List<UsuarioUbicacion> getUsuarioUbicacionActivoList() {
		List<UsuarioUbicacion> ubicacionActivos = new ArrayList<UsuarioUbicacion>();

		if (usuarioUbicacionList != null)
			for (UsuarioUbicacion ubicacion : usuarioUbicacionList)
				if (ubicacion.getActivo())
					ubicacionActivos.add(ubicacion);

		return ubicacionActivos;
	}

	public List<UsuarioUbicacion> getUsuarioUbicacionList() {
		return usuarioUbicacionList;
	}

	public void setUsuarioUbicacionList(List<UsuarioUbicacion> usuarioUbicacionList) {
		this.usuarioUbicacionList = usuarioUbicacionList;
	}

	public Date getFecContrasena() {
		return fecContrasena;
	}

	public void setFecContrasena(Date fecContrasena) {
		this.fecContrasena = fecContrasena;
	}
	
	public String getNombUsuarioCompleto() {
		StringBuilder sNome = new StringBuilder(getNombusuario());
		if(StringUtils.isNotBlank(getNombpaterno())) {
			sNome.append(" ")
				 .append(getNombpaterno());
		}
		if(StringUtils.isNotBlank(getNombmaterno())) {
			sNome.append(" ")
			.append(getNombmaterno());
		}
		
		return sNome.toString();
	}

	public List<String> getListClavesPermisos() {
		return listClavesPermisos;
	}

	public void setListClavesPermisos(List<String> listClavesPermisos) {
		this.listClavesPermisos = listClavesPermisos;
	}

	@Transient
	public boolean isPermisoClave(String clave) {
		return listClavesPermisos != null && listClavesPermisos.contains(clave);
	}
	
	public String getDescMac() {
		return descMac;
	}

	public void setDescMac(String descMac) {
		this.descMac = descMac;
	}

	public Integer getTempoDevolucaoPassagem() {
		return tempoDevolucaoPassagem;
	}

	public void setTempoDevolucaoPassagem(Integer tempoDevolucaoPassagem) {
		if(tempoDevolucaoPassagem == null){
			tempoDevolucaoPassagem = 0;
		}
		this.tempoDevolucaoPassagem = tempoDevolucaoPassagem;
	}

	public Boolean getIndExpiraSenha() {
		return indExpiraSenha;
	}

	public void setIndExpiraSenha(Boolean indExpiraSenha) {
		this.indExpiraSenha = indExpiraSenha;
	}

	public Long getEstacionInternetId() {
		return estacionInternetId;
	}

	public void setEstacionInternetId(Long estacionInternetId) {
		this.estacionInternetId = estacionInternetId;
	}

	public Long getTipoVentaIntegracaoId() {
		return tipoVentaIntegracaoId;
	}

	public void setTipoVentaIntegracaoId(Long tipoVentaIntegracaoId) {
		this.tipoVentaIntegracaoId = tipoVentaIntegracaoId;
	}

	public Boolean getIndRetornaTodasLocalidades() {
		return indRetornaTodasLocalidades;
	}

	public void setIndRetornaTodasLocalidades(Boolean indRetornaTodasLocalidades) {
		this.indRetornaTodasLocalidades = indRetornaTodasLocalidades;
	}
	
	public Boolean getIndTrocaSenha() {
		return indTrocaSenha;
	}
	
	public void setIndTrocaSenha(Boolean indTrocaSenha) {
		this.indTrocaSenha = indTrocaSenha;
	}
	
	
	public UsuarioUbicacion getUsuarioUbicacionPadrao() {

		if (usuarioUbicacionList != null) {
			for (UsuarioUbicacion ubicacion : usuarioUbicacionList) {
				if (ubicacion.getActivo() && ubicacion.getPadrao()) {
					return ubicacion;
				}
			}
		}

		return null;
	}
	
	
	public List<UsuarioUbicacion> getUsuarioUbicacionPadraoctivoList() {
		List<UsuarioUbicacion> ubicacionActivos = new ArrayList<UsuarioUbicacion>();

		if (usuarioUbicacionList != null)
			for (UsuarioUbicacion ubicacion : usuarioUbicacionList)
				if (ubicacion.getActivo() && ubicacion.getPadrao())
					ubicacionActivos.add(ubicacion);

		return ubicacionActivos;
	}
	


	
	
	@Override
	public void clonar() throws CloneNotSupportedException {
		
		usuarioClone = new Usuario();
		usuarioClone = (Usuario) this.clone();

		
		if(this.getUsuarioPerfilList() != null) {
			List<UsuarioPerfil> lsClones = new ArrayList<UsuarioPerfil>(); 
			for (UsuarioPerfil usuarioPerfil : this.getUsuarioPerfilList()) {
				if(BooleanUtils.isTrue(usuarioPerfil.getActivo())) {
					usuarioPerfil.clonar();
					lsClones.add(usuarioPerfil.getCloneObject());
				}
			}
			usuarioClone.setUsuarioPerfilList((lsClones));
		}
		
		if(this.getUsuarioEmpresaList() != null) {
			List<UsuarioEmpresa> lsClones = new ArrayList<UsuarioEmpresa>(); 
			for (UsuarioEmpresa usuarioEmpresa : this.getUsuarioEmpresaList()) {
				if(BooleanUtils.isTrue(usuarioEmpresa.getActivo())) {
					lsClones.add(usuarioEmpresa);
				}
			}
			usuarioClone.setUsuarioEmpresaList((lsClones));
		}
		
		if(this.getUsuarioUbicacionList() != null) {
			List<UsuarioUbicacion> lsClones = new ArrayList<UsuarioUbicacion>(); 
			for (UsuarioUbicacion usuarioUbicacion : this.getUsuarioUbicacionList()) {
				if(BooleanUtils.isTrue(usuarioUbicacion.getActivo())) {					
					lsClones.add(usuarioUbicacion);
				}
			}
			usuarioClone.setUsuarioUbicacionList((lsClones));
		}
	}

	@Override
	public Usuario getCloneObject() throws CloneNotSupportedException {
		return usuarioClone;
	}

	@Override
	public String getTextoInclusaoExclusao() {
		return String.format("ID [%s]", getUsuarioId());
	}

	public Boolean getIndRecuperarSenha() {
		return indRecuperarSenha;
	}

	public void setIndRecuperarSenha(Boolean indRecuperarSenha) {
		this.indRecuperarSenha = indRecuperarSenha;
	}

	public String getNombpaternoRecuperacao() {
		return nombpaternoRecuperacao;
	}

	public void setNombpaternoRecuperacao(String nombpaternoRecuperacao) {
		this.nombpaternoRecuperacao = nombpaternoRecuperacao;
	}

	public String getMatricula() {
		return matricula;
	}

	public void setMatricula(String matricula) {
		this.matricula = matricula;
	}

	public Date getDataNascimento() {
		return dataNascimento;
	}

	public void setDataNascimento(Date dataNascimento) {
		this.dataNascimento = dataNascimento;
	}
	
}
