/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.fw.model;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;

import gov.va.med.fw.security.RolePrincipal;
import gov.va.med.fw.security.UserCredentials;
import gov.va.med.fw.security.UserPrincipal;

/**
 * UserPrincipal implementation.
 * 
 * @author Ghazenfer Mansoor
 * @version 1.0
 */
public class UserPrincipalImpl extends AbstractKeyedEntity implements
		UserPrincipal {

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = -7044136313562745972L;

	private UserCredentials userCredentials = new UserCredentials();

	private String givenName = null;

	private String middleName = null;

	private String familyName = null;

	private Set internalRoles = null;

	/**
	 * Default Constructor.
	 */
	public UserPrincipalImpl() {
		super();
	}

	/**
	 * Construct using name
	 * 
	 * @param name
	 */
	public UserPrincipalImpl(String name) {
		super();
		userCredentials.setUserID(name);
	}

	/**
	 * Construct using name and password.
	 * 
	 * @param name
	 * @param password
	 */
	public UserPrincipalImpl(String name, String password) {
		this(name);
		userCredentials.setPassword(password);
	}

	public UserCredentials getUserCredentials() {
		return userCredentials;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.security.Principal#getName()
	 */
	public String getName() {
		return userCredentials.getUserID();
	}

	/**
	 * Set the Principal name
	 * 
	 * @param name
	 */
	public void setName(String name) {
		userCredentials.setUserID(name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.security.UserPrincipal#getPassword()
	 */
	public String getPassword() {
		return userCredentials.getPassword();
	}

	/**
	 * @param password
	 */
	public void setPassword(String password) {
		userCredentials.setPassword(password);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.security.UserPrincipal#getGivenName()
	 */
	public String getGivenName() {
		return this.givenName;
	}

	/**
	 * @param givenName
	 */
	public void setGivenName(String givenName) {
		this.givenName = givenName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.vha.fw.security.UserPrincipal#getMiddleName()
	 */
	public String getMiddleName() {
		return this.middleName;
	}

	/**
	 * @param middleName
	 */
	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	/**
	 * 
	 * @see gov.vha.fw.security.UserPrincipal#getFamilyName()
	 */
	public String getFamilyName() {
		return this.familyName;
	}

	/**
	 * @param familyName
	 */
	public void setFamilyName(String familyName) {
		this.familyName = familyName;
	}

	/**
	 * @see gov.va.med.fw.security.UserPrincipal#isAnonymous()
	 */
	public boolean isAnonymous() {
		return userCredentials.isAnonymous();
	}

	/**
	 * @see gov.va.med.fw.model.AbstractKeyedEntity#finalize()
	 */
	protected void finalize() throws Throwable {
		super.finalize();
		this.setInternalRoles(null);
	}

	/**
	 * Set the anonymous property
	 * 
	 * @param anonymous
	 */
	public void setAnonymous(boolean anonymous) {
		userCredentials.setAnonymous(anonymous);
	}

	private Set getInternalRoles() {
		if (internalRoles == null) {
			internalRoles = new HashSet();
		}
		return internalRoles;
	}

	private void setInternalRoles(Set internalRoles) {
		this.internalRoles = internalRoles;
	}

	/**
	 * @see gov.va.med.fw.security.UserPrincipal#getUserRoles()
	 */
	public Set getUserRoles() {
		return Collections.unmodifiableSet(getInternalRoles());
	}

	/**
	 * Helper method to add the RolePrincipal to a this user.
	 * 
	 * @param usersRole
	 */
	public void addUserRole(RolePrincipal rolePrincipal) {
		Validate.notNull(rolePrincipal, "Can not add null RolePrincipal");
		getInternalRoles().add(rolePrincipal);
	}

	/**
	 * Helper method to remove RolePrincipal.
	 * 
	 * @param rolePrincipal
	 */
	public void removeUserRole(RolePrincipal rolePrincipal) {
		Validate.notNull(rolePrincipal, "Can not remove null RolePrincipal");
		getInternalRoles().remove(rolePrincipal);
	}

	/**
	 * default implementation
	 */
	public Set getAuthorities() {
		Set authorities = new HashSet();
		for (Iterator i = getInternalRoles().iterator(); i.hasNext();) {
			String roleName = ((RolePrincipal) i.next()).getName();
			authorities.add(new GrantedAuthorityImpl(roleName));
		}
		return authorities;
	}

	public boolean isPermissionGranted(String permission) {
		Set authorities = getAuthorities();
		GrantedAuthority target = new GrantedAuthorityImpl(permission);

		return authorities.contains(target);
	}

	/**
	 * @see com.VHA.fw.model.AbstractEntity#buildToString()
	 */
	protected void buildToString(ToStringBuilder builder) {
		super.buildToString(builder);
		builder.append("name", getName());
		builder.append("anonymous", isAnonymous());
		builder.append("givenName", this.givenName);
		builder.append("middleName", this.middleName);
		builder.append("familyName", this.familyName);
	}

	/**
	 * @return Returns the logicalName.
	 */
	public String getLogicalName() {
		return userCredentials.getLogicalID();
	}

	/**
	 * @param logicalName
	 *           The logicalName to set.
	 */
	public void setLogicalName(String logicalName) {
		userCredentials.setLogicalID(logicalName);
	}

	public boolean equals(Object o) {
		return ((this == o) || (o instanceof UserPrincipal && this
				.equals((UserPrincipal) o)));
	}

	protected boolean equals(UserPrincipal userPrincipal) {
		return (userPrincipal != null && this.getName() != null
				&& userPrincipal.getName() != null && this.getName().equals(
				userPrincipal.getName()));
	}
}