/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.admin.action;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import gov.va.med.fw.conversion.ConversionServiceException;
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.model.EntityKeyFactory;
import gov.va.med.fw.security.UserPrincipal;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

import gov.va.med.esr.common.model.lookup.Capability;
import gov.va.med.esr.common.model.lookup.FunctionalGroup;
import gov.va.med.esr.common.model.security.CapabilitySet;
import gov.va.med.esr.common.model.security.ESRRolePrincipalImpl;
import gov.va.med.esr.common.model.security.ESRUserPrincipalImpl;

import gov.va.med.esr.service.UserAdminService;

import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.esr.ui.conversion.UIConversionServiceImpl;

public class UserProfileConversionService extends UIConversionServiceImpl{

    private UserAdminService userAdminService = null;
    
    public UserProfileConversionService() {
        super();
    }
    
    public UserAdminService getUserAdminService() {
        return userAdminService;
    }

    public void setUserAdminService(UserAdminService userAdminService) {
        this.userAdminService = userAdminService;
    }

    protected void convertBean(Object source, Object target) throws ConversionServiceException {
        try {
            if (source instanceof CapabilitySet && target instanceof CapabilitySetForm) {
                convert((CapabilitySet)source,(CapabilitySetForm)target);
            }
            else if (source instanceof CapabilitySetForm && target instanceof CapabilitySet) {
                convert((CapabilitySetForm)source,(CapabilitySet)target);
            }
            else if (source instanceof ESRRolePrincipalImpl && target instanceof RoleForm) {
                convert((ESRRolePrincipalImpl)source, (RoleForm) target);
            }
            else if (source instanceof RoleForm && target instanceof ESRRolePrincipalImpl) {
                convert((RoleForm)source, (ESRRolePrincipalImpl)target);
            }
            else if (source instanceof ESRUserPrincipalImpl && target instanceof UserProfileForm) {
                convert((ESRUserPrincipalImpl)source, (UserProfileForm) target);
            }
            else if (source instanceof UserProfileForm && target instanceof ESRUserPrincipalImpl) {
                convert((UserProfileForm)source, (ESRUserPrincipalImpl)target);
            }            
            else 
            {
                throw new Exception("Conversion is not supported");
            }
        }catch (Exception e) {
            throw new ConversionServiceException("Can not convert from " + 
                source.getClass().getName() + " to " + target.getClass().getName(),e); 
        }
    }

    private void convert(ESRUserPrincipalImpl user, UserProfileForm form) throws Exception {

        form.setUserId(user.getEntityKey().getKeyValueAsString());
        form.setName(user.getName());
        form.setFullName(user.getFullName());
        form.setFunctionalGroup(user.getFunctionalGroup() == null ? null : user.getFunctionalGroup().getCode());
        
        //Set assigned Capabilities, CapabilitySets and Roles
        form.setAssignedCapabilitySets(new ArrayList(user.getCapabilitySets()));
        form.setAssignedCapabilities(new ArrayList(user.getUserCapabilities()));
        form.setAssignedRoles(new ArrayList(user.getUserRoles())); 
                        
        //get assigned Capabilities, CapabilitySets and Roles for filtering the available list
        Set assignedCapabilities = user.getCapabilities();
        Set assignedCapabilitySets = user.getCapabilitySets();
        Set assignedRoles = user.getUserRoles();
        //assigned sets and capabilities of roles
        for (Iterator r=assignedRoles.iterator(); r.hasNext();){
            ESRRolePrincipalImpl role = (ESRRolePrincipalImpl)r.next();
            assignedCapabilitySets.addAll(role.getCapabilitySets());
            assignedCapabilities.addAll(role.getCapabilities());
        }
        //assigned capabilities of sets
        for (Iterator c=assignedCapabilitySets.iterator(); c.hasNext();){
            CapabilitySet cset = (CapabilitySet)c.next();
            assignedCapabilities.addAll(cset.getCapabilities());
        }
        
        //filter capability sets
        List availableCapabilitySets = getUserAdminService().getAllCapabilitySets();
        availableCapabilitySets = 
            filterCapabilitySets(availableCapabilitySets,assignedCapabilitySets);
        
        //filter capabilities 
        List availableCapabilities = getUserAdminService().getAllCapabilities();
        availableCapabilities.removeAll(assignedCapabilities);
        
        //filter roles
        List availableRoles = getUserAdminService().getAllRoles();
        availableRoles = filterRoles(availableRoles,assignedRoles);
        
        form.setAvailableCapabilitySets(availableCapabilitySets);
        form.setAvailableCapabilities(availableCapabilities);
        form.setAvailableRoles(availableRoles);
    }
    
    private void convert(UserProfileForm form, ESRUserPrincipalImpl user) 
    throws Exception {
        //update functional group
        FunctionalGroup fg = null;
        if (StringUtils.isNotEmpty(form.getFunctionalGroup())) {
            fg = (FunctionalGroup) getLookupCacheService().getByCodeFromCache(
                    FunctionalGroup.class,form.getFunctionalGroup());            
        }
        user.setFunctionalGroup(fg);
        
        //update roles
        updateUserRoles(form, user);
        //update capabilitysets
        updateUserCapabilitySets(form, user);
        //update capabilities
        updateUserCapabilities(form, user);              
    }
    
    private void updateUserRoles(UserProfileForm form, ESRUserPrincipalImpl user) 
    throws Exception {
        //Process Previoulsy assigned list
        List currentList = new ArrayList ();
        List idList = form.getAssignedRoleIdList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                                
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedRoleInd(i);
                String roleId = form.getAssignedRoleId(i);
                               
                //if not selected remove the Role
                if (Boolean.TRUE.equals(selected)){
                    
                    //create entity key for role
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(roleId), ESRRolePrincipalImpl.class);
                    
                    ESRRolePrincipalImpl role = (ESRRolePrincipalImpl) getUserAdminService().getRoleById(entityKey);
                    user.addUserRole(role);
                    currentList.add(role);
                }
            }
        }
        
        //Add the newly selected roles
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List indList = form.getRoleIndList();
        if (indList != null && indList.size() > 0) {
            for (int i=0; i<indList.size(); i++) {
                //Check whether this role has been checked
                Boolean selected = (Boolean) form.getRoleInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    String setId = form.getRoleId(i);
                    //get the role from admin service
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(setId), ESRRolePrincipalImpl.class);
                    ESRRolePrincipalImpl role = (ESRRolePrincipalImpl) getUserAdminService().getRoleById(entityKey);
                    user.addUserRole(role);
                    currentList.add(role);
                }
            }
        }
        
        Set deletedSet = user.getUserRoles();
        deletedSet.removeAll(currentList);
        for (Iterator i=deletedSet.iterator(); i.hasNext();) {
            user.removeUserRole((ESRRolePrincipalImpl)i.next());
        } 
    }    
    
    private void updateUserCapabilitySets(UserProfileForm form, ESRUserPrincipalImpl user) 
    throws Exception {

        //Process Previoulsy assigned list
        List currentList = new ArrayList ();
        List idList = form.getAssignedCapabilitySetIdList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                                
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedCapabilitySetInd(i);
                
                //if selected add the capabilityset
                if (Boolean.TRUE.equals(selected)){
                   String setId = form.getAssignedCapabilitySetId(i);
                    //get the Capability from lookup service
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(setId), CapabilitySet.class);
                    CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);
                    user.addCapabilitySet(capabilitySet);
                    currentList.add(capabilitySet);
                }
            }
        }
        
        //Add the newly selected Capabilities
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List indList = form.getCapabilitySetIndList();
        if (indList != null && indList.size() > 0) {
            for (int i=0; i<indList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getCapabilitySetInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    String setId = form.getCapabilitySetId(i);
                    //get the Capability from lookup service
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(setId), CapabilitySet.class);
                    CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);
                    user.addCapabilitySet(capabilitySet);
                    currentList.add(capabilitySet);
                }
            }
        }
        //Get all capabilitysets and remove the deleted ones
        Collection deletedSet = filterById(user.getCapabilitySets(),currentList);
                
        for (Iterator i=deletedSet.iterator(); i.hasNext();) {
            user.removeCapabilitySet((CapabilitySet)i.next());
        }       
    }
    
    private void updateUserCapabilities(UserProfileForm form, ESRUserPrincipalImpl user) 
        throws Exception {

        //Process Previoulsy assigned list
        //keep track off added/updated list to remove the unselected ones
        List currentList = new ArrayList ();
        
        List codeList = form.getAssignedCapabilityCodeList();
        if (codeList != null && codeList.size() > 0) {
            
            for (int i=0; i<codeList.size(); i++) {                                
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedCapabilityInd(i);
                
                if (Boolean.TRUE.equals(selected)){                    
                    //get the Capability from lookup service
                    Capability capability = (Capability)
                        getLookupCacheService().getByCodeFromCache(
                                Capability.class, form.getAssignedCapabilityCode(i));
                    
                    Date activeDate = DateUtils.getDate(form.getAssignedCapabilityActiveDate(i));
                    Date inactiveDate = DateUtils.getDate(form.getAssignedCapabilityInactiveDate(i));
                    //not found adds a new one else updates active, inactive dates
                    user.addCapability(capability,activeDate,inactiveDate);
                    currentList.add(capability);
                }    
            }
        }        
                
        //Add the newly selected or removed and added Capabilities
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List idList = form.getCapabilityIndList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getCapabilityInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    //get the Capability from lookup service
                    Capability capability = (Capability)
                        getLookupCacheService().getByCodeFromCache(
                                Capability.class, form.getCapabilityCode(i));
                    
                    Date activeDate = DateUtils.getDate(form.getCapabilityActiveDate(i));
                    Date inactiveDate = DateUtils.getDate(form.getCapabilityInactiveDate(i));
                    //adds or updates user capability
                    user.addCapability(capability,activeDate,inactiveDate);
                    currentList.add(capability);
                }
            }
        }
        
        //remove the deleted capabilities
        Set deletedSet = user.getCapabilities();
        deletedSet.removeAll(currentList);
        for (Iterator i=deletedSet.iterator(); i.hasNext();) {
            user.removeCapability((Capability)i.next());
        }
    }    
    /**
     * Conversion function for Role to Form
     * @param role
     * @param roleForm
     * @throws Exception
     */
    private void convert(ESRRolePrincipalImpl role, RoleForm roleForm) throws Exception {
        if (role.getEntityKey() != null)
            roleForm.setRoleId(role.getEntityKey().getKeyValueAsString());
 
        roleForm.setName(role.getName());
        roleForm.setDescription(role.getDescription());
        roleForm.setActiveDate(DateUtils.format(role.getActiveDate(),null));
        roleForm.setInactiveDate(DateUtils.format(role.getInactiveDate(),null));
                
        //Set assigned Capabilities, CapabilitySets and Roles
        Set assignedCapabilities = role.getCapabilities();
        Set assignedCapabilitySets = role.getCapabilitySets();
        roleForm.setAssignedCapabilitySets(new ArrayList(role.getCapabilitySets()));
        roleForm.setAssignedCapabilities(new ArrayList(role.getCapabilities()));

        List availableCapabilitySets = getUserAdminService().getAllCapabilitySets();
        List deleteList = new ArrayList ();
        for (Iterator i=assignedCapabilitySets.iterator(); i.hasNext();) {
            String key1 = ((CapabilitySet)i.next()).getEntityKey().getKeyValueAsString();
            for (Iterator j=availableCapabilitySets.iterator(); j.hasNext();) {
                CapabilitySet deletedSet = (CapabilitySet)j.next();
                String key2 = deletedSet.getEntityKey().getKeyValueAsString();
                if (key1.equals(key2)) {
                    deleteList.add(deletedSet);
                }
            }
        }                
        availableCapabilitySets.removeAll(deleteList);
        
        List assignedCapabilityList = new ArrayList();
        assignedCapabilityList.addAll(assignedCapabilities);
        for (Iterator i=assignedCapabilitySets.iterator(); i.hasNext();) {
            assignedCapabilityList.addAll(((CapabilitySet)i.next()).getCapabilities());
        }
        List availableCapabilities = getUserAdminService().getAllCapabilities();
        availableCapabilities.removeAll(assignedCapabilityList);
        //Set available Capabilities, CapabilitySets and Roles
        roleForm.setAvailableCapabilitySets(availableCapabilitySets);
        roleForm.setAvailableCapabilities(availableCapabilities);          
    }
    
    /**
     * Conversion function for Form to Role
     * @param role
     * @param roleForm
     * @throws Exception
     */    
    private void convert(RoleForm form, ESRRolePrincipalImpl role) throws Exception {
        //Exclude read only fields while updating an existing Capability Set
        if (role.getEntityKey() == null) {
            role.setName(form.getName());
            role.setDescription(form.getDescription());
        }
        else {
            //name and description are read only
        }
        role.setActiveDate(DateUtils.getDate(form.getActiveDate()));
        role.setInactiveDate(DateUtils.getDate(form.getInactiveDate()));        
        //update active dates
        
        //update capabilitysets
        updateRoleCapabilitySets(form, role);
        //update capabilities
        updateRoleCapabilities(form, role);    
    }
    private void updateRoleCapabilitySets(RoleForm form, ESRRolePrincipalImpl role) 
    throws Exception {

        //Process Previoulsy assigned list
        List addList = new ArrayList ();
        List idList = form.getAssignedCapabilitySetIndList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                                
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedCapabilitySetInd(i);
                
                //if not selected remove the capability
                if (Boolean.TRUE.equals(selected)){
                   String setId = form.getAssignedCapabilitySetId(i);
                    //get the Capability from lookup service
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(setId), CapabilitySet.class);
                    CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);
                    addList.add(capabilitySet);
                }
            }
        }
        
        //Add the newly selected Capabilities
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List indList = form.getCapabilitySetIndList();
        if (indList != null && indList.size() > 0) {
            for (int i=0; i<indList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getCapabilitySetInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    String setId = form.getCapabilitySetId(i);
                    //get the Capability from lookup service
                    EntityKey entityKey = EntityKeyFactory.createEntityKey(
                            new BigDecimal(setId), CapabilitySet.class);
                    CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);
                    addList.add(capabilitySet);
                }
            }
        }
        
        //deleted list is existing list - (add + retained) list
        List deletedList = new ArrayList(role.getCapabilitySets());
        deletedList.removeAll(addList);
        for (Iterator i=deletedList.iterator(); i.hasNext();) {
            role.removeCapabilitySet((CapabilitySet)i.next());
        }

        
        //Add the selected capabilities from the avaiable list
        for (int i=0; i<addList.size(); i++) {
            role.addCapabilitySet((CapabilitySet)addList.get(i));
        }        
    }
    
    private void updateRoleCapabilities(RoleForm form, ESRRolePrincipalImpl role) 
        throws Exception {

        //Process Previoulsy assigned list
        List addList = new ArrayList ();
        List codeList = form.getAssignedCapabilityCodeList();
        if (codeList != null && codeList.size() > 0) {
            for (int i=0; i<codeList.size(); i++) {
                
                //get the Capability from lookup service
                Capability capability = (Capability)
                    getLookupCacheService().getByCodeFromCache(
                            Capability.class, form.getAssignedCapabilityCode(i));
                
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedCapabilityInd(i);
                
                if (Boolean.TRUE.equals(selected)){
                    addList.add(capability);                
                }    
            }
        }        
                
        //Add the newly selected Capabilities
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List idList = form.getCapabilityIndList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getCapabilityInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    //get the Capability from lookup service
                    Capability capability = (Capability)
                        getLookupCacheService().getByCodeFromCache(
                                Capability.class, form.getCapabilityCode(i));
                    addList.add(capability);//,activeDate,inactiveDate);
                }
            }
        }
        //deleted list is existing list - (add + retained) list
        List deletedList = new ArrayList(role.getCapabilities());
        deletedList.removeAll(addList);
        for (Iterator i=deletedList.iterator(); i.hasNext();) {
            role.removeCapability((Capability)i.next());
        }

        
        //Add the selected capabilities from the avaiable list
        for (int i=0; i<addList.size(); i++) {
            role.addCapability((Capability)addList.get(i));
        }        
    }    
    /**
     * Convert from set to form
     * @param capabilitySet
     * @param setForm
     * @throws Exception
     */
    private void convert(CapabilitySet capabilitySet, CapabilitySetForm setForm) 
    throws Exception {
        //CapabilitySet could be an unsaved CapabilitySet retuned from Confirmation 
        if (capabilitySet.getEntityKey() != null)
            setForm.setCapabilitySetId(capabilitySet.getEntityKey().getKeyValueAsString());
        
        setForm.setName(capabilitySet.getName());
        setForm.setDescription(capabilitySet.getDescription());
        setForm.setActiveDate(DateUtils.format(capabilitySet.getActiveDate(),null));
        setForm.setInactiveDate(DateUtils.format(capabilitySet.getInactiveDate(),null));
        
        List availableCapabilities = getUserAdminService().getAllCapabilities();        
                
        List assignedCapabilities = new ArrayList (capabilitySet.getCapabilities());

        setForm.setAssignedCapabilities(assignedCapabilities);
        availableCapabilities.removeAll(assignedCapabilities);
        setForm.setAvailableCapabilities(availableCapabilities);            
    }
    /**
     * convert from from to set
     * @param form
     * @param set
     * @throws Exception
     */
    private void convert(CapabilitySetForm form, CapabilitySet set) throws Exception {
        
        //Exclude read only fields while updating an existing Capability Set
        if (set.getEntityKey() == null) {
            set.setName(form.getName());
            set.setDescription(form.getDescription());
        }
        else {

        }
        set.setActiveDate(DateUtils.getDate(form.getActiveDate()));
        set.setInactiveDate(DateUtils.getDate(form.getInactiveDate()));
        
        //Add the selected Capabilities
        //Note: The array could be incomplete or empty as unchecked check boxes are not included 
        List addList = new ArrayList ();
        List idList = form.getCapabilityIndList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getCapabilityInd(i);
                if (Boolean.TRUE.equals(selected)) {
                    //get the Capability from lookup service
                    Capability capability = (Capability)
                        getLookupCacheService().getByCodeFromCache(
                                Capability.class, form.getCapabilityCode(i));
                    addList.add(capability);
                }
            }
        }

        //Process Previoulsy assigned list in the edit case        
        idList = form.getAssignedCapabilityCodeList();
        if (idList != null && idList.size() > 0) {
            for (int i=0; i<idList.size(); i++) {
                //Check whether this capabilitye has been checked
                Boolean selected = (Boolean) form.getAssignedCapabilityInd(i);
                //get the Capability from lookup service
                Capability capability = (Capability)
                    getLookupCacheService().getByCodeFromCache(
                            Capability.class, form.getAssignedCapabilityCode(i));                
                if (Boolean.TRUE.equals(selected)) {
                    addList.add(capability);                    
                }
            }        
        }
            
        //deleted list is existing list - (add + retained) list
        List deletedList = new ArrayList(set.getCapabilities());
        deletedList.removeAll(addList);
        for (Iterator i=deletedList.iterator(); i.hasNext();) {
            set.removeCapability((Capability)i.next());
        }
        
        //Add the selected capabilities from the avaiable list
        for (int i=0; i<addList.size(); i++) {
            set.addCapability((Capability)addList.get(i));
        }
    }
    /**
     * Filter available roles based assigned roles and permissions
     * @param availableRoles
     * @param assignedRoles
     * @return
     */
    private List filterRoles(List availableRoles,Set assignedRoles) throws ServiceException{
        
        UserPrincipal loggedinUser = getLoggedInUser();
        
        Set assignedRoleNames = new HashSet();
        List roles = new ArrayList ();
        for (Iterator i=assignedRoles.iterator(); i.hasNext();) {
            assignedRoleNames.add(((ESRRolePrincipalImpl)i.next()).getName());
        }
        
        Map rolePermissionMap = getUserAdminService().getRolePermissionMap();
        for (Iterator j=availableRoles.iterator(); j.hasNext();) {
            ESRRolePrincipalImpl role = (ESRRolePrincipalImpl)j.next();
            if (!assignedRoleNames.contains(role.getName())){
                //check for permissions
                String requiredRoleName = (String) rolePermissionMap.get(role.getName());
                if (requiredRoleName == null || loggedinUser.isPermissionGranted(requiredRoleName)){
                    roles.add(role);
                }
            }
        }                
        return roles;
    }
        
    private List filterCapabilitySets(List availableCapabilitySets, Set assignedCapabilitySets) {
        //filter sets
       List deleteList = new ArrayList ();
        for (Iterator i=assignedCapabilitySets.iterator(); i.hasNext();) {
            String key1 = ((CapabilitySet)i.next()).getEntityKey().getKeyValueAsString();
            for (Iterator j=availableCapabilitySets.iterator(); j.hasNext();) {
                CapabilitySet deletedSet = (CapabilitySet)j.next();
                String key2 = deletedSet.getEntityKey().getKeyValueAsString();
                if (key1.equals(key2)) {
                    deleteList.add(deletedSet);
                }
            }
        }                
        availableCapabilitySets.removeAll(deleteList);
        return availableCapabilitySets;
    }
    
    /**
     * Filter src collection with target collection and return the src collection
     * The object type is assumed to be AbstractKeyedEntity and uniform collection
     * @param src
     * @param target
     * @return
     */
    private Collection filterById(Collection src, Collection target){
        
        for (Iterator i=src.iterator(); i.hasNext();) {
            AbstractKeyedEntity srcEntity = (AbstractKeyedEntity)i.next();
            String key1 = srcEntity.getEntityKey().getKeyValueAsString();
            for (Iterator j=target.iterator(); j.hasNext();) {
                AbstractKeyedEntity targetEntity = (AbstractKeyedEntity)j.next();
                String key2 = targetEntity.getEntityKey().getKeyValueAsString();
                //compare keys and class names
                if (key1.equals(key2) && 
                        srcEntity.getClass().equals(targetEntity.getClass())) {
                    i.remove();
                }
            }
        }                 
        return src;
    }
}
