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

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

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

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.ui.WebAuthenticationDetails;

/**
 * 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 implements Serializable {
	/** 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 web authentication details.
     * 
     * @return WebauthenticationDetails or null if no details avaialable.
     */
    public WebAuthenticationDetails getWebAuthenticationDetails() {
        if (details != null && details instanceof WebAuthenticationDetails) {
            return (WebAuthenticationDetails) details;
        }
        return null;
    }

    /**
     * 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);
    }
}