/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/authenticator/userdb/impl/URMGroupImpl.java,v 1.5 2005/03/02 10:53:34 eckehard Exp $
 * $Revision: 1.5 $
 * $Date: 2005/03/02 10:53:34 $
 *
 * ====================================================================
 *
 * 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.authenticator.userdb.impl;

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

import org.apache.slide.urm.URMForbiddenException;
import org.apache.slide.urm.URMNotImplementedException;
import org.apache.slide.urm.authenticator.URMAuthenticator;
import org.apache.slide.urm.authenticator.URMSubject;
import org.apache.slide.urm.authenticator.rolemanager.URMRoleManagerSpi;
import org.apache.slide.urm.authenticator.rolemanager.impl.URMRoleImpl;
import org.apache.slide.urm.authenticator.userdb.URMGroup;
import org.apache.slide.urm.authenticator.userdb.URMMetadataPropsSpi;
import org.apache.slide.urm.authenticator.userdb.URMUserDBManagerSpi;
import org.apache.slide.urm.common.URMConstants;
import org.apache.slide.urm.common.URMDeleteException;
import org.apache.slide.urm.common.URMInsertException;
import org.apache.slide.urm.common.URMInternalServerException;
import org.apache.slide.urm.common.URMUpdateException;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
import java.util.Hashtable;
import java.util.Map;

/**
 * Implementation of the generic Group class.
 *
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
public class URMGroupImpl implements URMGroup {

    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMGroupImpl.class.getName());
    
    protected String mDomain = null;
    protected String mGroupName = null;
    protected URMUserDBManagerSpi mUserDBManagerSpi = null;
    protected URMMetadataPropsSpi mMetadataPropsSpi = null;
    protected URMRoleManagerSpi mRoleManagerSpi = null;
    
    private int mHashCode;
    
    /*
     * Constructor: create new URMUser instance
     *
     * @param user name
     * @param domain name
     * @param URMUserDBManagerSpi
     * @param URMRoleManagerSpi
     */
    public URMGroupImpl(String inGroupname, String inDomain,
                        URMUserDBManagerSpi userDbManagerSpi,
                        URMMetadataPropsSpi metadataPropsSpi,
                        URMRoleManagerSpi roleManagerSpi) {
        mUserDBManagerSpi = userDbManagerSpi;
        mMetadataPropsSpi = metadataPropsSpi;
        mRoleManagerSpi   = roleManagerSpi;
        if (inGroupname.endsWith("(local)")) {
			String groupName = inGroupname.substring(0,inGroupname.indexOf("(local)"));

	    	// check if case sensitive    	
	    	if ((groupName != null) && !URMAuthenticator.isCaseSensitive()) mGroupName = groupName.toUpperCase();
	    	else mGroupName = groupName;
	    	
        } else {
        	if ((inDomain != null) && !URMAuthenticator.isCaseSensitive()) mDomain = inDomain.toUpperCase();
        	else mDomain = inDomain;
        	// check if case sensitive    	
        	if ((inGroupname != null) && !URMAuthenticator.isCaseSensitive()) mGroupName = inGroupname.toUpperCase();
        	else mGroupName = inGroupname;        	
        	
        }
        mHashCode = ((mDomain != null ? (mDomain + "/") : "") + (mGroupName != null ? mGroupName : "")).hashCode();
    }

    public String getDomain() {
        return mDomain;
    }

    public Set getGroupsMemberOf()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        return getURMGroupObjectSetFromStringSet(
                mUserDBManagerSpi.getGroupsMemberOf(mGroupName, mDomain),
                mDomain, mUserDBManagerSpi, mMetadataPropsSpi, mRoleManagerSpi);
    }

    private void readAncestorGroups(String group, Set groups)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        Set grps = mUserDBManagerSpi.getGroupsMemberOf(group, mDomain);
        for (Iterator iter = grps.iterator(); iter.hasNext(); ) {
            String grp = (String)iter.next();
            if (!groups.contains(grp)) {
                groups.add(grp);
                readAncestorGroups(grp, groups);
            }
        }
    }
    
    public Set getAllGroupsMemberOf()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        Set set = new HashSet();
        readAncestorGroups(mGroupName, set);
        return getURMGroupObjectSetFromStringSet(set, mDomain,
                mUserDBManagerSpi, mMetadataPropsSpi, mRoleManagerSpi);
    }
  
    public Properties getProperties()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        Properties props = new Properties();
        Properties gprs = mUserDBManagerSpi.getGroupProperties(mGroupName, mDomain);
        if (gprs != null)
            props.putAll(gprs);
        if (mMetadataPropsSpi != null)
            props.putAll(mMetadataPropsSpi.getProperties(mGroupName, mDomain, false));
        return props;
    }

    public Set getGroupMembers()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        List membernames = mUserDBManagerSpi.getGroupMembers(mGroupName, mDomain);
        HashSet retmembers = new HashSet();
        if (membernames == null)
            return retmembers;
        Iterator iter = membernames.iterator();
        String member = null;
        // groups
        while (iter.hasNext())
            if ((member = (String)iter.next()) != null)
                retmembers.add(new URMGroupImpl(member, mDomain,
                                        mUserDBManagerSpi, mMetadataPropsSpi, mRoleManagerSpi));
            else
                break;
        // users
        while (iter.hasNext())
            if ((member = (String)iter.next()) != null)
                retmembers.add(new URMUserImpl(member, mDomain,
                                        mUserDBManagerSpi, mMetadataPropsSpi, mRoleManagerSpi));
        return retmembers;
    }

    public boolean isGroupMember(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        List members = mUserDBManagerSpi.getGroupMembers(mGroupName, domain);
        if (members != null) {
            int idx = members.indexOf(group);
            if (idx >= 0 && idx < members.indexOf(null))
                return true;
        }
        return false;
    }

    public boolean isUserMember(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        List members = mUserDBManagerSpi.getGroupMembers(mGroupName, domain);
        if (members != null) {
            int idx = members.indexOf(user);
            if (idx > members.indexOf(null))
                return true;
        }
        return false;
    }

    public Set getRoleMapping()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        return URMRoleImpl.getURMRoleObjectSetFromSubjectSet(
                    mRoleManagerSpi.getRoleMappingOfGroup(mGroupName, mDomain), mRoleManagerSpi,
                                            mUserDBManagerSpi, mMetadataPropsSpi);
    }

    public Set getAllRoleMapping()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        return URMRoleImpl.getURMRoleObjectSetFromSubjectSet(
                    mRoleManagerSpi.getAllRoleMappingOfGroup(mGroupName, mDomain), mRoleManagerSpi,
                                            mUserDBManagerSpi, mMetadataPropsSpi);
    }

    public String getName() {
        return mGroupName;
    }

    public int getType() {
        return URMConstants.GROUP;
    }
    
    /**
     * Retrieves a specific property
     *
     * @param key property key
     * @return property value or null if the property has not been found
     *
     * @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
     */
    public Object getProperty(String key)throws URMNotImplementedException, URMForbiddenException,URMInternalServerException {
        //Properties props = mUserDBManagerSpi.getGroupProperties(mGroupName, mDomain);
        Properties props = getProperties();
        return props.getProperty(key);
    }
            
    /**
     * Retrieves a aggregated set of values of a specific property. The result set
     * contains the values of the property defined for the ancestors of the subject.
     *
     * @param key property key
     * @return aggregated property value
     *
     * @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
     */
    public Set getAggregatedProperty(String key) throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        HashSet allProps = new HashSet();
        Object prop = this.getProperty(key);
        if (prop != null)
            allProps.add(prop);
        for (Iterator iter = this.getAllGroupsMemberOf().iterator(); iter.hasNext(); ) {
            URMGroup currentGroup = (URMGroup) iter.next();
            prop = currentGroup.getProperty((String) key);
            if (prop != null)
                allProps.add(prop);
        }
        
        return allProps;
    }
                            
    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        //if (obj instanceof String)
        //    return mGroupName.equals((String)obj);
        if (obj instanceof URMGroup) {
            URMGroup grp = (URMGroup)obj;
            String dom = grp.getDomain();
            if (dom != null)
                if (mDomain != null)
                    return mGroupName.equals(grp.getName()) && mDomain.equals(dom);
                else
                    return false;
            else
                if (mDomain == null)
                    return mGroupName.equals(grp.getName());
                else
                    return false;
        }
        return false;
    }

    public int hashCode() {
         return mHashCode;
    }

    public static Set getURMGroupObjectSetFromStringSet(Set groupnames, String domain,
                                                    URMUserDBManagerSpi userDbManagerSpi,
                                                    URMMetadataPropsSpi metadataPropsSpi,
                                                    URMRoleManagerSpi roleManagerSpi) {
        if (groupnames == null)
            return null;
        Iterator iter = groupnames.iterator();
        HashSet retgrps = new HashSet();
        while (iter.hasNext())
            retgrps.add(new URMGroupImpl((String)iter.next(), domain,
                                        userDbManagerSpi, metadataPropsSpi, roleManagerSpi));
        return retgrps;
    }
    
    public static Set getURMGroupObjectSetFromSubjectSet(Set subjects,
                                                    URMUserDBManagerSpi userDbManagerSpi,
                                                    URMMetadataPropsSpi metadataPropsSpi,
                                                    URMRoleManagerSpi roleManagerSpi) {
        if (subjects == null)
            return null;
        Iterator iter = subjects.iterator();
        HashSet retgrps = new HashSet();
        while (iter.hasNext()) {
            URMSubject subj = (URMSubject)iter.next();
            retgrps.add(new URMGroupImpl(subj.getName(), subj.getDomain(),
                                        userDbManagerSpi, metadataPropsSpi, roleManagerSpi));
        }
        return retgrps;
    }
    
    public static boolean contains(Set groups, String group, String domain) {
        if (groups == null || group == null)
            return false;
        
        URMGroup trole = new URMGroupImpl(group, domain, null, null, null);
        return groups.contains(trole);
    }

    public void setProperties(Properties props)
            throws URMNotImplementedException, URMForbiddenException, URMUpdateException, URMDeleteException, URMInternalServerException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }
    
    public void addUserToGroup(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }

    public void removeUserFromGroup(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }

    public void addGroupToGroup(String group, String domain) throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }

    public void removeGroupFromGroup(String group, String domain) throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }

    public void linkToRole(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException, URMInternalServerException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));

    }

    public void deleteRoleLink(String role)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }

    /**
     * Sets new subject specific properties
     *
     * @param key property key
     * @param prop property value
     *
     * @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
     */
    public void setProperty(String key, Object prop) throws URMNotImplementedException, URMForbiddenException, URMUpdateException, URMDeleteException, URMInternalServerException{
        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0027"));
    }
    
    public Map getAvailablePropertyNames() {
        Hashtable map = new Hashtable();
        Object obj = null;
        // property names from userdb spi
        Set props = mUserDBManagerSpi.getWriteablePropKeys(false);
        for (Iterator iter = props.iterator(); iter.hasNext();)
            map.put(iter.next(), Boolean.TRUE);
        props = mUserDBManagerSpi.getAvailablePropKeys(false);
        for (Iterator iter = props.iterator(); iter.hasNext();)
            if (!map.containsKey(obj = iter.next()))
                map.put(obj, Boolean.FALSE);
        // property names from metaprops spi
        props = mMetadataPropsSpi.getWriteableGroupPropKeys();
        for (Iterator iter = props.iterator(); iter.hasNext();)
            map.put(iter.next(), Boolean.TRUE);
        props = mMetadataPropsSpi.getAvailableGroupPropKeys();
        for (Iterator iter = props.iterator(); iter.hasNext();)
            if (!map.containsKey(obj = iter.next()))
                map.put(obj, Boolean.FALSE);
        return map;
    }
}

