/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/

// Package
package gov.va.med.fw.security;

// Java classes
import java.util.ArrayList;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextImpl;


/**
 * Provides a security context class containing information such as a
 * UserPrincipal, roles and authentication Details. If the user is
 * authentication normally by providing valid username and password,
 * UserPrincipal should be used to extract the user details. In case of web
 * authentication, getWebAuthenticationDetails() method return the Object that
 * contains the web authentication details such as Remote IP, session id etc.
 * 
 * 
 * @author Vu Le, Ghazenfer Mansoor
 * @version 1.0, 3.0
 */
public class SecurityContext extends SecurityContextImpl {
	/** Known max size (could equate to database column length) */
	public static final int AUDIT_ID_MAX_LENGTH = 30;

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = -1823587167685741329L;
	// private static final RolePrincipal[] EMPTY_ARRAY_ROLE_PRINCIPAL = new
	// RolePrincipal[0];
	private UserPrincipal userPrincipal;
	private Object details = null;
	private List roles = new ArrayList();

	/**
	 * Construct a security context using UserPrincipal
	 * 
	 * @param userPrincipal
	 */
	public SecurityContext(UserPrincipal userPrincipal) {
		if (userPrincipal == null) {
			throw new IllegalArgumentException("UserPrincipal can not be NULL.");
		}
		this.userPrincipal = userPrincipal;
	}

	/**
	 * Construct a security context using UserPrincipal, details and
	 * GrantedAuthority array.
	 * 
	 * @param userPrincipal
	 *            - userPrincipal Object
	 * @param authorities
	 *            - array of GrantedAuthority
	 * @param details
	 *            - authentication details Object
	 */
	public SecurityContext(UserPrincipal userPrincipal, GrantedAuthority[] authorities,
			Object details) {
		this.userPrincipal = userPrincipal;
		this.details = details;
		if (authorities != null) {
			for (int i = 0; i < authorities.length; i++) {
				GrantedAuthority authority = authorities[i];
				roles.add(authority.getAuthority());
			}
		}
	}

	/**
	 * Return a UserPrincipal
	 */
	public UserPrincipal getUserPrincipal() {
		return userPrincipal;
	}

	public String getUserName(boolean standardizeName) {
		// logic here is to give logical name a higher priority
		UserCredentials cred = getUserPrincipal().getUserCredentials();
		String id = cred.getLogicalID() != null ? cred.getLogicalID() : cred.getUserID();
		return standardizeName ? standardizeAuditId(id) : id;
	}

	public String getUserName() {
		return getUserName(true);
	}

	public static String standardizeAuditId(String id) {
		// ensure capped to known max
		if (id != null && id.length() > AUDIT_ID_MAX_LENGTH)
			id = id.substring(0, AUDIT_ID_MAX_LENGTH);
		return id;
	}

	/**
	 * Return a list of user roles as array of RolePrincipal Objects. If the
	 * user does not have any Role, return empty Array.
	 * 
	 * @return array of RolePrincipal, never null.
	 */
	/*
	 * public RolePrincipal[] getUserRoles() { if (userPrincipal == null ||
	 * userPrincipal.getUserRoles() == null) { return
	 * EMPTY_ARRAY_ROLE_PRINCIPAL; } return (RolePrincipal[])
	 * userPrincipal.getUserRoles().toArray( EMPTY_ARRAY_ROLE_PRINCIPAL); }
	 */

	/**
	 * Return the roles as String array.
	 * 
	 * @return
	 */
	public String[] getRolesAsStrings() {
		return (String[]) roles.toArray(new String[0]);
	}

	/**
	 * Checks whether the user is in the given role.
	 * 
	 * @param roleName
	 * @return true if user is in role, false otherwise.
	 */
	public boolean isUserInRole(String roleName) {
		if (roleName == null) {
			return false;
		}
		for (int i = 0; i < roles.size(); i++) {
			if (roleName.equals((String) roles.get(i))) {
				return true;
			}
		}
		return false;
	}



	/**
	 * Return the authentication details (if any available) as String.
	 * 
	 * @return String details or null if no details available.
	 */
	public String getDetails() {
		if (details == null) {
			return null;
		}
		return details.toString();
	}

	/*
	 * Temporarily override, till we change the usage of it in header.jsp
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		if (userPrincipal != null)
			return userPrincipal.getName();
		else
			return "";
	}

	public void setLogicalName(String name) {
		userPrincipal.getUserCredentials().setLogicalID(name);
	}
}