/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/common/impl/URMPrincipalImpl.java,v 1.5 2005/03/02 10:53:35 eckehard Exp $
 * $Revision: 1.5 $
 * $Date: 2005/03/02 10:53:35 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.slide.urm.common.impl;

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

import org.apache.slide.urm.URMException;
import org.apache.slide.urm.URMForbiddenException;
import org.apache.slide.urm.URMNotImplementedException;
import org.apache.slide.urm.accesscontroler.URMAclAdministrator;
import org.apache.slide.urm.accesscontroler.URMAclValidator;
import org.apache.slide.urm.accesscontroler.impl.URMAclAdministratorImpl;
import org.apache.slide.urm.authenticator.URMAdministrator;
import org.apache.slide.urm.authenticator.URMAuthenticator;
import org.apache.slide.urm.authenticator.URMSubject;
import org.apache.slide.urm.authenticator.impl.URMAdministratorImpl;
import org.apache.slide.urm.authenticator.impl.URMGuestAdministratorImpl;
import org.apache.slide.urm.authenticator.impl.URMUserAdministratorImpl;
import org.apache.slide.urm.authenticator.rolemanager.URMRole;
import org.apache.slide.urm.authenticator.rolemanager.impl.URMRoleGuestImpl;
import org.apache.slide.urm.authenticator.rolemanager.impl.URMRoleImpl;
import org.apache.slide.urm.authenticator.userdb.URMGroup;
import org.apache.slide.urm.authenticator.userdb.URMUser;
import org.apache.slide.urm.common.URMCloseConnectionException;
import org.apache.slide.urm.common.URMConnectionException;
import org.apache.slide.urm.common.URMConstants;
import org.apache.slide.urm.common.URMInternalServerException;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.urm.common.URMSetRoleException;
import org.apache.slide.urm.common.URMUpdateException;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
//import weblogic.security.principal.WLSUserImpl;
//import weblogic.security.principal.WLSPrincipal;

/**
 * Implementation of a Java Principal
 *
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
public class URMPrincipalImpl implements URMPrincipal{//, WLSPrincipal {

    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMPrincipalImpl.class.getName());

    private URMRole             mActiveRole     = null;
    private String              mUserName       = null;
    private String              mDomain         = null;
    private String              mName           = null;
    private long                mCreationTime   = 0;
    private URMAdministrator      mUrmAdmin       = null;
    private URMAdministrator      mActiveUrmAdmin = null;
    private URMAclAdministrator  mUrmAclAdmin    = null;
    private char[] 				mAuthID			=  null;
//	private WLSUserImpl wlprin = null;
	
    public URMPrincipalImpl(String inUser, char[] pwd, String inDomain,
                                URMAdministrator urmAdmin,
                                URMAclAdministrator urmAclAdmin) {
//		wlprin = new WLSUserImpl(user);
    	if ((inDomain != null) && !URMAuthenticator.isCaseSensitive()) mDomain = inDomain.toUpperCase();
    	else mDomain = inDomain;
    	// check if case sensitive    	
    	if ((inUser != null) && !URMAuthenticator.isCaseSensitive()) mUserName = inUser.toUpperCase();
    	else mUserName = inUser;

//        if (domain != null && domain.length() > 0)
//            mName = domain + "/" + user;
//        else

    	mName = mUserName;    
        mCreationTime   = System.currentTimeMillis();
        mUrmAdmin       = urmAdmin;
        mActiveUrmAdmin = new URMUserAdministratorImpl(mUrmAdmin);
        mUrmAclAdmin    = urmAclAdmin;
        mAuthID = pwd;
    }
    
    /**
     * creates a new URMPrincipal with the active role URMGuest
     */
    public URMPrincipalImpl(URMAdministrator urmAdmin, URMAclAdministrator urmAclAdmin)
            throws URMException {
        mCreationTime = System.currentTimeMillis();
        mUrmAclAdmin  = urmAclAdmin;
        mUrmAdmin     = (URMAdministrator) urmAdmin;
        mActiveUrmAdmin = urmAdmin;
        mActiveRole   = urmAdmin.getRole(URMConstants.URM_GUEST_ROLE);
        if (mActiveRole == null) {
            throw new URMSetRoleException(
                    MessageLogger.getAndLogMessage(msLogger, "URMCOE0045", URMConstants.URM_GUEST_ROLE));
        }
    }
    
//	public String getName() {
//		return wlprin.getName();
//	}
//    
//	public byte[] getSalt(){
//		return wlprin.getSalt();
//	}
//	
//	public byte[] getSignedData(){
//		return wlprin.getSignedData();
//	}
//	
//	public void setSignature(byte[] signature) {
//		wlprin.setSignature(signature);
//	}
//	
//	public byte[] getSignature(){
//		return wlprin.getSignature();
//	}
    

    public URMPrincipal copyPrincipal(String activeRole)
            throws URMSetRoleException, URMNotImplementedException, URMForbiddenException, URMInternalServerException, URMConnectionException {
        if (mUserName == null)
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0056"));
        Object owner = new Object();
        URMPrincipal copy = new URMPrincipalImpl(mUserName, mAuthID, mDomain,
                                                new URMAdministratorImpl(mUrmAdmin, owner),
                                                new URMAclAdministratorImpl(mUrmAclAdmin, owner));
        if (activeRole != null)
            copy.setActiveRole(activeRole);
        return copy;
    }

    /*
     * Create a copy of the principal, allowing to continue with the same Tamino Connection
     * as the original.
     */
    public URMPrincipal copyPrincipalwithTA(String activeRole)
            throws URMSetRoleException, URMNotImplementedException, URMForbiddenException, URMInternalServerException, URMConnectionException {
        if (mUserName == null)
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0056"));
        URMPrincipal copy = new URMPrincipalImpl(mUserName, mAuthID, mDomain,
                                                new URMAdministratorImpl(mUrmAdmin, mUrmAdmin.getOwner()),
                                                new URMAclAdministratorImpl(mUrmAclAdmin, mUrmAclAdmin.getOwner()));
        if (activeRole != null)
            copy.setActiveRole(activeRole);
        return copy;
    }

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

    /**
     * Sets a specific role into the active state.
     * This method must be called before the URMPrincipal object is functional.
     * Any calls that use an instance of this class without a particular role
     * will result in exception.
     * Note: 'null' as role is possible. In this case, all possible roles will
     * be considered when roles are compared. Carefull: Having null as the active
     * role is more performance intensive during these check operations.
     *
     */
    public void setActiveRole(String activeRole) throws URMSetRoleException, URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        if (mUserName == null)
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0057"));
        if (mActiveRole == null ||
                mName.equals(URMConstants.URM_ADMIN_ROLE) ||
                mName.equals(URMConstants.URM_GUEST_ROLE)) {
            URMUser urm_user = mUrmAdmin.getUser(mUserName, mDomain);
            if (urm_user == null) {
                throw new URMSetRoleException(
                    MessageLogger.getAndLogMessage(msLogger, "URMCOC0014", mName));
            }
            Set possible_roles = null;
            try {
                possible_roles = getPossibleRoles();
            } catch (URMException e) {
                throw new URMSetRoleException(msLogger, "E", e);
            }
            if (!URMRoleGuestImpl.contains(possible_roles, activeRole)) {
                throw new URMSetRoleException(
                    MessageLogger.getAndLogMessage(msLogger, "URMCOE0045", activeRole));
            }
            if (/*activeRole.equals(URMConstants.URM_ROOT_ROLE)
                        || */activeRole.equals(URMConstants.URM_ADMIN_ROLE)) {
                mActiveUrmAdmin = mUrmAdmin;
            }
            else if (activeRole.equals(URMConstants.URM_GUEST_ROLE)) {
                mActiveUrmAdmin = new URMGuestAdministratorImpl(mUrmAdmin);
            }
            else {
                mActiveUrmAdmin = new URMUserAdministratorImpl(mUrmAdmin);
            }
            mActiveRole = mActiveUrmAdmin.getRole(activeRole);
        }
        else {
            throw new URMSetRoleException(
                MessageLogger.getAndLogMessage(msLogger, "URMTRC0005"));
        }
    }

    public URMRole getActiveRole()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        if (mActiveRole != null) {
            if (mActiveUrmAdmin.isRole(mActiveRole.getName()))
                return mActiveRole;
            else
                throw new URMInternalServerException(MessageLogger.getAndLogMessage(
                                        msLogger, "URMCOE0005", mActiveRole.getName()));
        }
        else
            return null;
    }

    public String getDomain() {
        return mDomain;
    }

    public String getUserName() {
        return mUserName;
    }

    public URMAdministrator getURMAdministrator() throws URMException {
        return mActiveUrmAdmin;
    }

    public URMAclAdministrator getURMAclAdministrator() throws URMException {
        return mUrmAclAdmin;
    }

    public URMAclValidator getURMAclValidator() throws URMException {
        return URMAclValidator.newInstance();
    }

    public Properties getProperties() throws URMNotImplementedException, URMException {
       
        URMUser user = mUrmAdmin.getUser(mUserName, mDomain);
        if (user == null)
            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOC0014", mName));
        else
          return user.getProperties();
    }

    public Set getGroups() throws URMNotImplementedException, URMException {

        URMUser user = mUrmAdmin.getUser(mUserName, mDomain);
        if (user == null)
            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOC0014", mName));
        else
          return user.getGroups();
    }

    /*private Set getPossibleAncestorRoles(Set roles)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        Set possible_roles = new HashSet(roles);
        Set aroles = new HashSet();
        Iterator iter = roles.iterator();
        while (iter.hasNext()){
            Set currentAnchestors = ((URMRole)iter.next()).getAncestors();
            if (currentAnchestors != null) {
                aroles.addAll(currentAnchestors);
            }
        }
        if (!aroles.isEmpty()) possible_roles.addAll(getPossibleAncestorRoles(aroles));
        return possible_roles;
    }*/

    public Set getPossibleRoles() throws URMNotImplementedException, URMException {
        Set ret_roles = new HashSet();
    	if (mUserName == null){
    		URMRole guestRole = mUrmAdmin.getRole(URMConstants.URM_GUEST_ROLE);
    		ret_roles.add(guestRole);
    		ret_roles.addAll(guestRole.getAllAncestors());

        } else {
	
	        URMUser user = null;
	        try {
	            user = mUrmAdmin.getUser(mUserName, mDomain);
	        } catch (URMForbiddenException e) { }
	        if (user == null)
	            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOC0014", mName));
	        // get direct roles
	        ret_roles.addAll(user.getAllRoleMapping());
	        
	        Set grps = user.getAllGroups();
	        if (grps != null) {
	            Iterator iter = grps.iterator();
	            while (iter.hasNext())
	                ret_roles.addAll(((URMGroup)iter.next()).getAllRoleMapping());
	        }

//    		URMRole guestRole = mUrmAdmin.getRole(URMConstants.URM_GUEST_ROLE);
//    		ret_roles.add(guestRole);
//    		ret_roles.addAll(guestRole.getAllAncestors());
    		
	        //if (!roleMapping.isEmpty()) ret_roles.addAll(getPossibleAncestorRoles(roleMapping));
        }
        return ret_roles;
    }

    public URMRole getSpecificPossibleRoles(String name) throws URMNotImplementedException, URMException {
 
        URMRole role = mUrmAdmin.getRole(name);
        if (role == null)
            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOC0015", name));
        if (URMRoleImpl.contains(getPossibleRoles(), name))
            return role;
        else
            return null;
    }

    public Set getPrimaryRoles() throws URMNotImplementedException, URMException {
        if (mUserName == null) {
            Set roles = new HashSet();
            roles.add(mUrmAdmin.getRole(URMConstants.URM_GUEST_ROLE));
            return roles;
        } else {
	        URMUser user = mUrmAdmin.getUser(mUserName, mDomain);
	        if (user == null)
	            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOC0014", mName));
	        return user.getRoleMapping();
        }
    }

    public long getCreationTime() {
        return mCreationTime;
    }
    
    public void close() throws URMCloseConnectionException {
        /*if (mUrmAdmin != null)
          mUrmAdmin.close();
        if (mUrmAclAdmin != null)
            mUrmAclAdmin.close();*/
    }
    
    /**
     * Changes the password of this principal in the user database
     *
     * @param oldpassword the user's current password
     *
     * @param newpassword the desired password of the userd
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMException if an unpredictable internal error occurs
     * @exception URMException if an unpredictable error occurs
     */
    public void setPassword(char[] oldpassword, char[] newpassword)
            throws URMInternalServerException, URMNotImplementedException, URMForbiddenException, URMUpdateException {
        if (mUserName == null)
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0057"));
        mUrmAdmin.getUser(mUserName, mDomain).setPassword(oldpassword, newpassword);
        mAuthID=newpassword;
   }
    
    /**
     *  Delivers the an authentication ID for Single Sign On prozedure.
     * 
     * @return Authentication ID
     * @throws URMInternalServerException
     * @throws URMNotImplementedException
     * @throws URMForbiddenException
     */
    public char[] getAuthenticationID()
    		throws URMInternalServerException, URMNotImplementedException, URMForbiddenException {
    	return mAuthID;    
    }
}
