/**
 * Copyright 2005-2016 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.kuali.rice.kim.web.struts.action;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.kuali.rice.core.api.membership.MemberType;
import org.kuali.rice.core.api.util.RiceConstants;
import org.kuali.rice.core.api.util.RiceKeyConstants;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kim.api.KimConstants;
import org.kuali.rice.kim.api.group.Group;
import org.kuali.rice.kim.api.identity.entity.EntityDefault;
import org.kuali.rice.kim.api.identity.principal.Principal;
import org.kuali.rice.kim.api.role.Role;
import org.kuali.rice.kim.api.role.RoleResponsibility;
import org.kuali.rice.kim.api.services.KimApiServiceLocator;
import org.kuali.rice.kim.api.type.KimAttributeField;
import org.kuali.rice.kim.api.type.KimType;
import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember;
import org.kuali.rice.kim.bo.ui.KimDocumentRoleQualifier;
import org.kuali.rice.kim.bo.ui.KimDocumentRoleResponsibilityAction;
import org.kuali.rice.kim.bo.ui.PersonDocumentAddress;
import org.kuali.rice.kim.bo.ui.PersonDocumentAffiliation;
import org.kuali.rice.kim.bo.ui.PersonDocumentCitizenship;
import org.kuali.rice.kim.bo.ui.PersonDocumentEmail;
import org.kuali.rice.kim.bo.ui.PersonDocumentEmploymentInfo;
import org.kuali.rice.kim.bo.ui.PersonDocumentGroup;
import org.kuali.rice.kim.bo.ui.PersonDocumentName;
import org.kuali.rice.kim.bo.ui.PersonDocumentPhone;
import org.kuali.rice.kim.bo.ui.PersonDocumentRole;
import org.kuali.rice.kim.bo.ui.RoleDocumentDelegation;
import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMember;
import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMemberQualifier;
import org.kuali.rice.kim.document.IdentityManagementPersonDocument;
import org.kuali.rice.kim.document.rule.AttributeValidationHelper;
import org.kuali.rice.kim.framework.type.KimTypeService;
import org.kuali.rice.kim.impl.KIMPropertyConstants;
import org.kuali.rice.kim.impl.responsibility.ResponsibilityInternalService;
import org.kuali.rice.kim.impl.role.RoleBo;
import org.kuali.rice.kim.impl.role.RoleMemberBo;
import org.kuali.rice.kim.impl.services.KimImplServiceLocator;
import org.kuali.rice.kim.impl.type.KimTypeAttributesHelper;
import org.kuali.rice.kim.impl.type.KimTypeBo;
import org.kuali.rice.kim.rule.event.ui.AddGroupEvent;
import org.kuali.rice.kim.rule.event.ui.AddPersonDelegationMemberEvent;
import org.kuali.rice.kim.rule.event.ui.AddPersonDocumentRoleQualifierEvent;
import org.kuali.rice.kim.rule.event.ui.AddRoleEvent;
import org.kuali.rice.kim.rules.ui.PersonDocumentRoleRule;
import org.kuali.rice.kim.service.KIMServiceLocatorInternal;
import org.kuali.rice.kim.web.struts.form.IdentityManagementPersonDocumentForm;
import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
import org.kuali.rice.krad.data.KradDataServiceLocator;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.KRADConstants;
import org.kuali.rice.krad.util.UrlFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * This is a description of what this class does - shyu don't forget to fill this in. 
 * 
 * @author Kuali Rice Team (rice.collab@kuali.org)
 *
 */
public class IdentityManagementPersonDocumentAction extends IdentityManagementDocumentActionBase {

    protected ResponsibilityInternalService responsibilityInternalService;

	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		ActionForward forward;
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        // accept either the principal name or principal ID, looking up the latter if necessary
        // this allows inquiry links to work even when only the principal name is present
        String principalId = request.getParameter(KIMPropertyConstants.Person.PRINCIPAL_ID);
        String principalName = request.getParameter(KIMPropertyConstants.Person.PRINCIPAL_NAME);
        if ( StringUtils.isBlank(principalId) && StringUtils.isNotBlank(principalName) ) {
        	Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalName);
        	if ( principal != null ) {
        		principalId = principal.getPrincipalId();
        	}
        }
        if ( principalId != null ) {
        	personDocumentForm.setPrincipalId(principalId);
        }
        forward = super.execute(mapping, form, request, response);
        personDocumentForm.setCanModifyEntity(getUiDocumentService().canModifyEntity(GlobalVariables.getUserSession().getPrincipalId(), personDocumentForm.getPrincipalId()));
        EntityDefault origEntity = null;
        if(personDocumentForm.getPersonDocument()!=null) {
			origEntity = getIdentityService().getEntityDefault(personDocumentForm.getPersonDocument().getEntityId());
		}
        boolean isCreatingNew = (personDocumentForm.getPersonDocument()==null || origEntity==null)?true:false;
        personDocumentForm.setCanOverrideEntityPrivacyPreferences(isCreatingNew || getUiDocumentService().canOverrideEntityPrivacyPreferences(GlobalVariables.getUserSession().getPrincipalId(), personDocumentForm.getPrincipalId()));
		return forward;
    }

	@Override
	protected void loadDocument(KualiDocumentFormBase form)
			throws WorkflowException {
		super.loadDocument(form);
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
		IdentityManagementPersonDocument personDoc = personDocumentForm.getPersonDocument();
		populateRoleInformation(personDoc);
        personDoc.resyncTransientState();
	}

	protected void populateRoleInformation( IdentityManagementPersonDocument personDoc ) {
		for (PersonDocumentRole role : personDoc.getRoles()) {
//			try {
            KimType type = KimApiServiceLocator.getKimTypeInfoService().getKimType(role.getKimTypeId());
            KimTypeService kimTypeService = null;
            if (StringUtils.isNotBlank(type.getServiceName()))  {
                kimTypeService = (KimTypeService) KimImplServiceLocator.getBean(type.getServiceName());
            } else {
                kimTypeService = getKimTypeService(KimTypeBo.to(role.getKimRoleType()));
            }
	        if ( kimTypeService != null ) {
                role.setDefinitions(kimTypeService.getAttributeDefinitions(role.getKimTypeId()));
	        }
        	// when post again, it will need this during populate
            role.setNewRolePrncpl(new KimDocumentRoleMember());
            for (KimAttributeField key : role.getDefinitions()) {
            	KimDocumentRoleQualifier qualifier = new KimDocumentRoleQualifier();
            	//qualifier.setQualifierKey(key);
	        	setAttrDefnIdForQualifier(qualifier,key);
            	role.getNewRolePrncpl().getQualifiers().add(qualifier);
            }
	        role.setAttributeEntry( getUiDocumentService().getAttributeEntries( role.getDefinitions() ) );
		}
    }

	@Override
	protected void createDocument(KualiDocumentFormBase form)
			throws WorkflowException {
		super.createDocument(form);
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        if(StringUtils.isBlank(personDocumentForm.getPrincipalId())){
    		personDocumentForm.getPersonDocument().initializeDocumentForNewPerson();
    		personDocumentForm.setPrincipalId(personDocumentForm.getPersonDocument().getPrincipalId());
        } else {
        	getUiDocumentService().loadEntityToPersonDoc(personDocumentForm.getPersonDocument(), personDocumentForm.getPrincipalId() );
        	populateRoleInformation( personDocumentForm.getPersonDocument() );
        	if(personDocumentForm.getPersonDocument()!=null) {
				personDocumentForm.getPersonDocument().setIfRolesEditable();
			}
        }
	}

	/***
	 * @see org.kuali.rice.kim.web.struts.action.IdentityManagementDocumentActionBase#getActionName()
	 */
	@Override
	public String getActionName(){
		return KimConstants.KimUIConstants.KIM_PERSON_DOCUMENT_ACTION;
	}

	public ActionForward addAffln(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentAffiliation newAffln = personDocumentForm.getNewAffln();
        newAffln.setDocumentNumber(personDocumentForm.getPersonDocument().getDocumentNumber());
        KradDataServiceLocator.getDataObjectService().wrap(newAffln).fetchRelationship("affiliationType");
        personDocumentForm.getPersonDocument().getAffiliations().add(newAffln);
        personDocumentForm.setNewAffln(new PersonDocumentAffiliation());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
	
    public ActionForward deleteAffln(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getAffiliations().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    public ActionForward addCitizenship(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentCitizenship newCitizenship = personDocumentForm.getNewCitizenship();
        personDocumentForm.getPersonDocument().getCitizenships().add(newCitizenship);
        personDocumentForm.setNewCitizenship(new PersonDocumentCitizenship());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteCitizenship(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getCitizenships().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addEmpInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        IdentityManagementPersonDocument personDOc = personDocumentForm.getPersonDocument();
        PersonDocumentAffiliation affiliation = personDOc.getAffiliations().get(getSelectedLine(request));        
        PersonDocumentEmploymentInfo newempInfo = affiliation.getNewEmpInfo();
        newempInfo.setDocumentNumber(personDOc.getDocumentNumber());
        newempInfo.setVersionNumber(1L);
        affiliation.getEmpInfos().add(newempInfo);
        affiliation.setNewEmpInfo(new PersonDocumentEmploymentInfo());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteEmpInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        String selectedIndexes = getSelectedParentChildIdx(request);
        if (selectedIndexes != null) {
	        String [] indexes = StringUtils.split(selectedIndexes,":");
	        PersonDocumentAffiliation affiliation = personDocumentForm.getPersonDocument().getAffiliations().get(Integer.parseInt(indexes[0]));
	        affiliation.getEmpInfos().remove(Integer.parseInt(indexes[1]));
        }
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    protected String getSelectedParentChildIdx(HttpServletRequest request) {
    	String lineNumber = null;
        String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
        if (StringUtils.isNotBlank(parameterName)) {
            lineNumber = StringUtils.substringBetween(parameterName, ".line", ".");
        }
        return lineNumber;
    }

    public ActionForward addName(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentName newName = personDocumentForm.getNewName();
        newName.setDocumentNumber(personDocumentForm.getDocument().getDocumentNumber());
        personDocumentForm.getPersonDocument().getNames().add(newName);
        personDocumentForm.setNewName(new PersonDocumentName());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteName(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getNames().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addAddress(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentAddress newAddress = personDocumentForm.getNewAddress();
        newAddress.setDocumentNumber(personDocumentForm.getDocument().getDocumentNumber());
        personDocumentForm.getPersonDocument().getAddrs().add(newAddress);
        personDocumentForm.setNewAddress(new PersonDocumentAddress());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteAddress(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getAddrs().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addPhone(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentPhone newPhone = personDocumentForm.getNewPhone();
        newPhone.setDocumentNumber(personDocumentForm.getDocument().getDocumentNumber());
        personDocumentForm.getPersonDocument().getPhones().add(newPhone);
        personDocumentForm.setNewPhone(new PersonDocumentPhone());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deletePhone(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getPhones().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addEmail(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentEmail newEmail = personDocumentForm.getNewEmail();
        newEmail.setDocumentNumber(personDocumentForm.getDocument().getDocumentNumber());
        personDocumentForm.getPersonDocument().getEmails().add(newEmail);
        personDocumentForm.setNewEmail(new PersonDocumentEmail());        
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteEmail(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        personDocumentForm.getPersonDocument().getEmails().remove(getLineToDelete(request));
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addGroup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentGroup newGroup = personDocumentForm.getNewGroup();
        if (newGroup.getGroupName() == null 
        		&& newGroup.getNamespaceCode() == null 
        		&& newGroup.getGroupId() != null) {
        	Group tempGroup = KimApiServiceLocator.getGroupService().getGroup(newGroup.getGroupId());
            if (tempGroup == null) {
                GlobalVariables.getMessageMap().putError("newGroup.groupId",
                    RiceKeyConstants.ERROR_ASSIGN_GROUP_INVALID,
                    new String[] { newGroup.getGroupId(),""});
                return mapping.findForward(RiceConstants.MAPPING_BASIC);
            }
        	newGroup.setGroupName(tempGroup.getName());
	        newGroup.setNamespaceCode(tempGroup.getNamespaceCode());
	        newGroup.setKimTypeId(tempGroup.getKimTypeId());
        } else if (StringUtils.isBlank(newGroup.getGroupName())
                 || StringUtils.isBlank(newGroup.getNamespaceCode())) {
                 GlobalVariables.getMessageMap().putError("newGroup.groupName",
                      RiceKeyConstants.ERROR_ASSIGN_GROUP_INVALID,
                      new String[] { newGroup.getNamespaceCode(), newGroup.getGroupName()});
                 return mapping.findForward(RiceConstants.MAPPING_BASIC);
        }
        Group tempGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
            newGroup.getNamespaceCode(), newGroup.getGroupName());
        if (tempGroup == null) {
            GlobalVariables.getMessageMap().putError("newGroup.groupName",
                    RiceKeyConstants.ERROR_ASSIGN_GROUP_INVALID,
                    new String[] { newGroup.getNamespaceCode(), newGroup.getGroupName()});
            return mapping.findForward(RiceConstants.MAPPING_BASIC);
        }
        newGroup.setGroupId(tempGroup.getId());
	    newGroup.setKimTypeId(tempGroup.getKimTypeId());
        if (getKualiRuleService().applyRules(new AddGroupEvent("",personDocumentForm.getPersonDocument(), newGroup))) {
	        Group group = getGroupService().getGroup(newGroup.getGroupId());
	        newGroup.setGroupName(group.getName());
	        newGroup.setNamespaceCode(group.getNamespaceCode());
	        newGroup.setKimTypeId(group.getKimTypeId());
        	personDocumentForm.getPersonDocument().getGroups().add(newGroup);
	        personDocumentForm.setNewGroup(new PersonDocumentGroup());
        }
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteGroup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentGroup inactivedGroupMembership = personDocumentForm.getPersonDocument().getGroups().get(getLineToDelete(request));
        Calendar cal = Calendar.getInstance();
        inactivedGroupMembership.setActiveToDate(new Timestamp(cal.getTimeInMillis()));        
        personDocumentForm.getPersonDocument().getGroups().set(getLineToDelete(request), inactivedGroupMembership);
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

       public ActionForward addRole(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentRole newRole = personDocumentForm.getNewRole();

        if (getKualiRuleService().applyRules(new AddRoleEvent("",personDocumentForm.getPersonDocument(), newRole))) {
         Role role = KimApiServiceLocator.getRoleService().getRole(newRole.getRoleId());
         if(!validateRole(newRole.getRoleId(), role, PersonDocumentRoleRule.ERROR_PATH, "Person")){
          return mapping.findForward(RiceConstants.MAPPING_BASIC);
         }
         newRole.setRoleName(role.getName());
         newRole.setNamespaceCode(role.getNamespaceCode());
         newRole.setKimTypeId(role.getKimTypeId());
            KimDocumentRoleMember roleMember = new KimDocumentRoleMember();
            roleMember.setMemberId(personDocumentForm.getPrincipalId());
            roleMember.setMemberTypeCode(MemberType.PRINCIPAL.getCode());
            roleMember.setRoleId(newRole.getRoleId());
            roleMember.setActiveFromDate(newRole.getNewRolePrncpl().getActiveFromDate());
            roleMember.setActiveToDate(newRole.getNewRolePrncpl().getActiveToDate());
            newRole.setNewRolePrncpl(roleMember);
         if(!validateRoleAssignment(personDocumentForm.getPersonDocument(), newRole)){
          return mapping.findForward(RiceConstants.MAPPING_BASIC);
         }
         KimTypeService kimTypeService = getKimTypeService(KimTypeBo.to(newRole.getKimRoleType()));
         //AttributeDefinitionMap definitions = kimTypeService.getAttributeDefinitions();
         // role type populated from form is not a complete record
         if ( kimTypeService != null ) {
          newRole.setDefinitions(kimTypeService.getAttributeDefinitions(newRole.getKimTypeId()));
         }
         KimDocumentRoleMember newRolePrncpl = newRole.getNewRolePrncpl();

         for (KimAttributeField key : newRole.getDefinitions()) {
          KimDocumentRoleQualifier qualifier = new KimDocumentRoleQualifier();
          //qualifier.setQualifierKey(key);
          setAttrDefnIdForQualifier(qualifier,key);
          newRolePrncpl.getQualifiers().add(qualifier);
         }
         if (newRole.getDefinitions().isEmpty()) {
          List<KimDocumentRoleMember> rolePrncpls = new ArrayList<KimDocumentRoleMember>();
          setupRoleRspActions(newRole, newRolePrncpl);
             rolePrncpls.add(newRolePrncpl);
          newRole.setRolePrncpls(rolePrncpls);
         }
         //newRole.setNewRolePrncpl(newRolePrncpl);
         newRole.setAttributeEntry( getUiDocumentService().getAttributeEntries( newRole.getDefinitions() ) );
         personDocumentForm.getPersonDocument().getRoles().add(newRole);
         personDocumentForm.setNewRole(new PersonDocumentRole());
        }
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
	protected boolean validateRoleAssignment(IdentityManagementPersonDocument document, PersonDocumentRole newRole){
        boolean rulePassed = true;
        if(!document.validAssignRole(newRole)){
			GlobalVariables.getMessageMap().putError("newRole.roleId", 
					RiceKeyConstants.ERROR_ASSIGN_ROLE, 
					new String[] {newRole.getNamespaceCode(), newRole.getRoleName()});
	        rulePassed = false;
        }
		return rulePassed;
	}

    protected void setupRoleRspActions(PersonDocumentRole role, KimDocumentRoleMember rolePrncpl) {
        for (RoleResponsibility roleResp : getResponsibilityInternalService().getRoleResponsibilities(role.getRoleId())) {
        	if (getResponsibilityInternalService().areActionsAtAssignmentLevelById(roleResp.getResponsibilityId())) {
        		KimDocumentRoleResponsibilityAction roleRspAction = new KimDocumentRoleResponsibilityAction();
        		roleRspAction.setRoleResponsibilityId("*");
        		// not linked to a role responsibility - so we set the referenced object to null
        		roleRspAction.setRoleResponsibility(null);
                roleRspAction.setDocumentNumber(role.getDocumentNumber());

        		if(rolePrncpl.getRoleRspActions()==null || rolePrncpl.getRoleRspActions().isEmpty()){
        			if(rolePrncpl.getRoleRspActions()==null) {
						rolePrncpl.setRoleRspActions(new ArrayList<KimDocumentRoleResponsibilityAction>());
					}
        			 rolePrncpl.getRoleRspActions().add(roleRspAction);
        		}
        	}        	
        }
    }
    
//	protected boolean isUniqueRoleRspAction(List<KimDocumentRoleResponsibilityAction> roleRspActions, KimDocumentRoleResponsibilityAction roleRspAction){
//    	if(roleRspActions==null || roleRspAction==null) return false;
//    	for(KimDocumentRoleResponsibilityAction roleRspActionTemp: roleRspActions){
//    		if((StringUtils.isNotEmpty(roleRspActionTemp.getRoleMemberId()) && roleRspActionTemp.getRoleMemberId().equals(roleRspAction.getRoleMemberId())) && 
//    			(StringUtils.isNotEmpty(roleRspActionTemp.getRoleResponsibilityId())	&& roleRspActionTemp.getRoleResponsibilityId().equals(roleRspAction.getRoleResponsibilityId())))
//    			return false;
//    	}
//    	return true;
//    }
	    

    protected void setAttrDefnIdForQualifier(KimDocumentRoleQualifier qualifier,KimAttributeField definition) {
   		qualifier.setKimAttrDefnId(definition.getId());
   		KradDataServiceLocator.getDataObjectService().wrap(qualifier).fetchRelationship("kimAttribute");
    }

    public ActionForward deleteRole(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        PersonDocumentRole personDocumentRole = personDocumentForm.getPersonDocument().getRoles().get(getLineToDelete(request));
        Calendar cal = Calendar.getInstance();
        personDocumentRole.getRolePrncpls().get(0).setActiveToDate(new Timestamp(cal.getTimeInMillis()));
        personDocumentForm.getPersonDocument().getRoles().set(getLineToDelete(request), personDocumentRole);
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward addRoleQualifier(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        IdentityManagementPersonDocument personDOc = personDocumentForm.getPersonDocument();
        int selectedRoleIdx = getSelectedLine(request);
        PersonDocumentRole role = personDOc.getRoles().get(selectedRoleIdx);
        KimDocumentRoleMember newRolePrncpl = role.getNewRolePrncpl();
        newRolePrncpl.setMemberTypeCode(MemberType.PRINCIPAL.getCode());
        newRolePrncpl.setMemberId(personDOc.getPrincipalId());
    	
    	if (getKualiRuleService().applyRules(new AddPersonDocumentRoleQualifierEvent("",
    			personDOc, newRolePrncpl, role, selectedRoleIdx))) {
        	setupRoleRspActions(role, newRolePrncpl);
    		role.getRolePrncpls().add(newRolePrncpl);
            KimDocumentRoleMember roleMember = new KimDocumentRoleMember();
            roleMember.setMemberTypeCode(MemberType.PRINCIPAL.getCode());
            roleMember.setMemberId(personDocumentForm.getPrincipalId());
	        role.setNewRolePrncpl(roleMember);
	        for (KimAttributeField key : role.getDefinitions()) {
	        	KimDocumentRoleQualifier qualifier = new KimDocumentRoleQualifier();
	        	//qualifier.setQualifierKey(key);
	        	setAttrDefnIdForQualifier(qualifier,key);
	        	role.getNewRolePrncpl().getQualifiers().add(qualifier);
	        }
    	}

        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

    public ActionForward deleteRoleQualifier(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        String selectedIndexes = getSelectedParentChildIdx(request);
        if (selectedIndexes != null) {
	        String [] indexes = StringUtils.split(selectedIndexes,":");
	        PersonDocumentRole role = personDocumentForm.getPersonDocument().getRoles().get(Integer.parseInt(indexes[0]));
            KimDocumentRoleMember member = role.getRolePrncpls().get(Integer.parseInt(indexes[1]));
            Calendar cal = Calendar.getInstance();
            member.setActiveToDate(new Timestamp(cal.getTimeInMillis()));
            // role.getRolePrncpls().remove(Integer.parseInt(indexes[1]));
        }
        return mapping.findForward(RiceConstants.MAPPING_BASIC);

    }
    
    public ActionForward addDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm personDocumentForm = (IdentityManagementPersonDocumentForm) form;
        IdentityManagementPersonDocument personDocument = personDocumentForm.getPersonDocument();
        RoleDocumentDelegationMember newDelegationMember = personDocumentForm.getNewDelegationMember();
        KimTypeAttributesHelper attrHelper = newDelegationMember.getAttributesHelper();
        if (getKualiRuleService().applyRules(new AddPersonDelegationMemberEvent("", personDocumentForm.getPersonDocument(), newDelegationMember))) {
	        Role role = KimApiServiceLocator.getRoleService().getRole(newDelegationMember.getRoleBo().getId());
	        if (role != null) {
		        if(!validateRole(newDelegationMember.getRoleBo().getId(),role, PersonDocumentRoleRule.ERROR_PATH, "Person")){
		        	return mapping.findForward(RiceConstants.MAPPING_BASIC);
		        }
		        newDelegationMember.setRoleBo(RoleBo.from(role));
	        }
	        KimAttributeField attrDefinition;
	        RoleMemberBo roleMember = KIMServiceLocatorInternal.getUiDocumentService().getRoleMember(newDelegationMember.getRoleMemberId());
	        Map<String, String>
                    roleMemberAttributes = (new AttributeValidationHelper()).convertAttributesToMap(roleMember.getAttributeDetails());
	        for (KimAttributeField key: attrHelper.getDefinitions()) {
	        	RoleDocumentDelegationMemberQualifier qualifier = new RoleDocumentDelegationMemberQualifier();
	        	attrDefinition = key;
	        	qualifier.setKimAttrDefnId(attrHelper.getKimAttributeDefnId(attrDefinition));
	        	qualifier.setAttrVal(attrHelper.getAttributeValue(roleMemberAttributes, attrDefinition.getAttributeField().getName()));
	           	newDelegationMember.setMemberTypeCode(MemberType.PRINCIPAL.getCode());
	        	newDelegationMember.getQualifiers().add(qualifier);
	        }
	        //newDelegationMember.setAttributeEntry(getUiDocumentService().getAttributeEntries(newDelegationMember.getAttributesHelper().getDefinitions())));
            newDelegationMember.setMemberId(personDocument.getPrincipalId());
	        personDocument.getDelegationMembers().add(newDelegationMember);
	        personDocumentForm.setNewDelegationMember(new RoleDocumentDelegationMember());
        }
        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    
    public ActionForward deleteDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocument personDocument = ((IdentityManagementPersonDocumentForm)form).getPersonDocument();
        int lineToDelete = getLineToDelete(request);
        RoleDocumentDelegationMember deletedMember = personDocument.getDelegationMembers().remove(lineToDelete);

        // determine if we just deleted the last member from the role delegation, there should only be one but we will
        // use a list just to make sure we get any delegations that no longer have any members
        List<RoleDocumentDelegation> delegationsToRemove = new ArrayList<>();
        for (RoleDocumentDelegation delegation : personDocument.getDelegations()) {
            delegation.getMembers().remove(deletedMember);
            if (delegation.getMembers().isEmpty()) {
                delegationsToRemove.add(delegation);
            }
        }
        for (RoleDocumentDelegation delegationToRemove : delegationsToRemove) {
            personDocument.getDelegations().remove(delegationToRemove);
        }

        return mapping.findForward(RiceConstants.MAPPING_BASIC);
    }

	@Override
	public ActionForward save(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		return super.save(mapping, form, request, response);
	}
	
    @Override
    public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        IdentityManagementPersonDocumentForm impdForm = (IdentityManagementPersonDocumentForm) form;

        ActionForward forward = this.refreshAfterDelegationMemberRoleSelection(mapping, impdForm, request);
        if (forward != null) {
            return forward;
        }

        return super.refresh(mapping, form, request, response);
	}
    
    protected ActionForward refreshAfterDelegationMemberRoleSelection(ActionMapping mapping, IdentityManagementPersonDocumentForm impdForm, HttpServletRequest request) {
        String refreshCaller = impdForm.getRefreshCaller();

        boolean isRoleLookupable = KimConstants.KimUIConstants.ROLE_LOOKUPABLE_IMPL.equals(refreshCaller);
        boolean isRoleMemberLookupable = KimConstants.KimUIConstants.KIM_DOCUMENT_ROLE_MEMBER_LOOKUPABLE_IMPL.equals(refreshCaller);

        // do not execute the further refreshing logic if the refresh caller is not a lookupable
        if (!isRoleLookupable && !isRoleMemberLookupable) {
            return null;
        }

        //In case of delegation member lookup impdForm.getNewDelegationMemberRoleId() will be populated.
        if(impdForm.getNewDelegationMemberRoleId() == null){
            return null;
        }
        if(isRoleLookupable){
            return renderRoleMemberSelection(mapping, request, impdForm);
        }

        String roleMemberId = request.getParameter(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID);
        if(StringUtils.isNotBlank(roleMemberId)){
            impdForm.getNewDelegationMember().setRoleMemberId(roleMemberId);
            RoleMemberBo roleMember = getUiDocumentService().getRoleMember(roleMemberId);
            impdForm.getNewDelegationMember().setRoleMemberMemberId(roleMember.getMemberId());
            impdForm.getNewDelegationMember().setRoleMemberMemberTypeCode(roleMember.getType().getCode());
            impdForm.getNewDelegationMember().setRoleMemberName(getUiDocumentService().getMemberName(MemberType.fromCode(impdForm.getNewDelegationMember().getRoleMemberMemberTypeCode()), impdForm.getNewDelegationMember().getRoleMemberMemberId()));
            impdForm.getNewDelegationMember().setRoleMemberNamespaceCode(getUiDocumentService().getMemberNamespaceCode(MemberType.fromCode(impdForm.getNewDelegationMember().getRoleMemberMemberTypeCode()), impdForm.getNewDelegationMember().getRoleMemberMemberId()));

            Role role;
        	role = KimApiServiceLocator.getRoleService().getRole(impdForm.getNewDelegationMember().getRoleBo().getId());
	        if (role != null) {
		        if(!validateRole(impdForm.getNewDelegationMember().getRoleBo().getId(), role, PersonDocumentRoleRule.ERROR_PATH, "Person")){
		        	return mapping.findForward(RiceConstants.MAPPING_BASIC);
		        }
		        impdForm.getNewDelegationMember().setRoleBo(RoleBo.from(role));
	        }
        }
        impdForm.setNewDelegationMemberRoleId(null);
        return null;
    }
    
    protected ActionForward renderRoleMemberSelection(ActionMapping mapping, HttpServletRequest request, IdentityManagementPersonDocumentForm impdForm) {
        Properties props = new Properties();

        props.put(KRADConstants.SUPPRESS_ACTIONS, Boolean.toString(true));
        props.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, KimDocumentRoleMember.class.getName());
        props.put(KRADConstants.LOOKUP_ANCHOR, KRADConstants.ANCHOR_TOP_OF_FORM);
        props.put(KRADConstants.LOOKED_UP_COLLECTION_NAME, KimConstants.KimUIConstants.ROLE_MEMBERS_COLLECTION_NAME);

        String conversionPatttern = "{0}" + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + "{0}";
        StringBuilder fieldConversion = new StringBuilder();
        fieldConversion.append(MessageFormat.format(conversionPatttern, 
       		KimConstants.PrimaryKeyConstants.SUB_ROLE_ID)).append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
        fieldConversion.append(MessageFormat.format(conversionPatttern, 
           		KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID)).append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);

        props.put(KRADConstants.CONVERSION_FIELDS_PARAMETER, fieldConversion);

        props.put(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID, impdForm.getNewDelegationMember().getRoleBo().getId());

        props.put(KRADConstants.RETURN_LOCATION_PARAMETER, this.getReturnLocation(request, mapping));
     //   props.put(KRADConstants.BACK_LOCATION, this.getReturnLocation(request, mapping));

        props.put(KRADConstants.LOOKUP_AUTO_SEARCH, "Yes");
        props.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.SEARCH_METHOD);

        props.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(impdForm));
     //   props.put(KRADConstants.DOC_NUM, impdForm.getDocument().getDocumentNumber());

        // TODO: how should this forward be handled
        String url = UrlFactory.parameterizeUrl(getApplicationBaseUrl() + "/kr/" + KRADConstants.LOOKUP_ACTION, props);

        impdForm.registerEditableProperty("methodToCall");

        return new ActionForward(url, true);
    }


    public ResponsibilityInternalService getResponsibilityInternalService() {
    	if ( responsibilityInternalService == null ) {
    		responsibilityInternalService = KimImplServiceLocator.getResponsibilityInternalService();
    	}
		return responsibilityInternalService;
	}
}
