/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.common.action;

// Java Classes
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.web.context.WebApplicationContext;

import gov.va.med.fw.conversion.CopyService;
import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.security.PasswordEncryptionService;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.ServiceOptimisticLockException;
import gov.va.med.fw.service.TimeoutServiceException;
import gov.va.med.fw.service.EntityNotChangedException;
import gov.va.med.fw.ui.struts.SecurityAction;
import gov.va.med.fw.util.ReflectionException;
import gov.va.med.fw.util.Reflector;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.validation.ValidationFieldMessage;
import gov.va.med.fw.validation.ValidationMessage;
import gov.va.med.fw.validation.ValidationMessages;
import gov.va.med.fw.validation.ValidationServiceException;

import gov.va.med.esr.common.rule.service.MergeRuleService;

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

import gov.va.med.esr.ui.ApplicationConstants;
import gov.va.med.esr.ui.common.beans.EntityHistory;
import gov.va.med.esr.ui.common.service.LookupCacheService;

/**
 * Common abstract base class for all UI actions.
 * <p/>
 * Project: UI</br> Created on: 10:24:16 AM </br>
 *
 * @author DNS   LEV
 */
public abstract class AbstractAction extends SecurityAction implements InitializingBean
{
    //Message Keys
    public static final String DATA_NOT_CHANGED_MESSAGE_KEY = "message.dataNotChanged";
    public static final String OPTIMISTC_LOCK_ERROR_KEY = "error.optimisticLock";

    public static final String INFO_MESSAGE = "infoMessage";
    public static final String ERROR_MESSAGE = "errorMessage";
    public static final String WARNING_MESSAGE = "warningMessage";
    public static final String RULE_ERROR_MSG_KEY_PREFIX = "rm.";
    public static final String RULE_ERROR_MSG_SPACE_SUBST = "_";

    //Standard forward names
    public static final String FWD_OLERROR = "olerror"; //optimistic lock error page
    public static final String FWD_NO_DATA_CHANGED = "noDataChanged"; // no data changed page
    public static final String FWD_DISPLAY_UPDATE_MSG = "displayUpdateMsg";
    public static final String FWD_DISPLAY_ADD_MSG = "displayAddMessage";
    public static final String FWD_DISPLAY_DELETE_MSG = "displayDeleteMsg";
    public static final String FWD_CONFIRM = "confirm"; //confirmation page
    public static final String FWD_CANCEL = "cancel"; //cancel
    public static final String FWD_CLEAR = "clear"; //clear
    public static final String RETURN_LINK = "returnLink"; //clear
    public static final String FWD_TO = "forwardTo";

    private LookupService lookupService = null;

    private LookupCacheService lookupCacheService = null;

    private PersonHelperService personHelperService = null;

    private DemographicService demographicService = null;

    private PersonService personService = null;

    private AssociationService associationService = null;

    private MessagingService messagingService = null;

    private FinancialsService financialsService = null;

    private CopyService copyService = null;

    private MergeRuleService mergeRuleService = null;

    private InsuranceService insuranceService = null;

    private PersonMergeService personMergeService = null;

    private PersonUnmergeService personUnmergeService = null;

    private EligibilityEnrollmentService enrollmentService = null;

    private MilitaryInfoService militaryInfoService;

    private EGTService egtService = null;

    private RegistryService registryService = null;

    private StandardReportService standardReportService = null;

    private UserAdminService userAdminService = null;

    private SystemParameterService systemParameterService = null;

    private CommsLetterRequestService commsLetterRequestService;

    private CommsLogService commsLogService;

    private PurpleHeartService purpleHeartService;

    private WorkflowService workflowService;

    private CopyService personMergeCopyService = null;

    private EEServiceAdminService eeServiceAdminService = null;

    private PasswordEncryptionService passwordEncryptionService = null;

    private ApplicationInProcessService applicationInProcessService = null;

    private HandBookService handBookService;

    private ArchivedMessagingService archivedMessagingService = null;

    private VOAApplicationService voaApplicationService = null;

    private HealthBenefitPlanService healthBenefitPlanService = null;

    private VHICCardInfoService vhicCardInfoService = null;

    private HBPDefinitionService hbpDefinitionService = null;

    private IRSTransmissionService irsTransmissionService = null;
    
    private CorrespondenceService correspondenceService = null;

    // CR 13726
    private VeteransChoiceInformationService veteransChoiceInformationService = null;

	/**
     * A default constructor.
     */
    protected AbstractAction()
    {
        super();
    }

    /**
     * Handles Rule validation messages, user information messages, etc.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param form The optional ActionForm bean for this request (if any)
     * @param request The HTTP request we are processing
     * @param response The HTTP response we are creating
     *
     * @throws Exception if an exception occurs
     */
    public ActionForward execute(ActionMapping mapping,
        ActionForm form,
        HttpServletRequest request,
        HttpServletResponse response)
        throws Exception
    {
        ActionForward forward = null;
        try
        {
            forward = super.execute(mapping, form, request, response);
            addUserMessage(request);
        }
        catch (ValidationServiceException valEx)
        {
            this.setValidationMessages(request, valEx.getValidationMessages());
            forward = mapping.getInputForward();
        }
        catch (ServiceOptimisticLockException olexp)
        {
            processOptimisticLockException(request, olexp);
            forward =
                handleOptimisticLockException(mapping, form, request, response);
        }
        catch (HibernateOptimisticLockingFailureException olexp)
        {
            ServiceOptimisticLockException newExp =
                new ServiceOptimisticLockException(olexp.getMessage());

            processOptimisticLockException(request, newExp);
            forward =
                handleOptimisticLockException(mapping, form, request, response);
        }
        catch (PersonLockedException ple)
        {
            processPersonLockedException(request, ple);
            forward = handlePersonLockedException(mapping, form, request, response);
        }
        catch (TimeoutServiceException ex)
        {
            processTimeoutException(request, ex);
            forward = handleTimeoutException(mapping, form, request, response);
        }
        catch (EntityNotChangedException ence)
        {
            processEntityNotChangedException(request, ence);
            forward = handleEntityNotChangedException(mapping, form, request, response);
        }
        return forward;
    }

    protected void addActionMessage(HttpServletRequest request, ActionMessage actionMessage)
    {
        ActionMessages errors = new ActionMessages();
        errors.add(ActionMessages.GLOBAL_MESSAGE, actionMessage);
        addErrors(request, errors);
    }

    protected void addActionMessage(HttpServletRequest request, String key)
    {
        addActionMessage(request, new ActionMessage(key));
    }

    protected void addActionMessage(HttpServletRequest request, String key, String value)
    {
        addActionMessage(request, new ActionMessage(key, value));
    }

    protected void addActionMessageForField(HttpServletRequest request, ActionMessage actionMessage, String field)
    {
        ActionMessages errors = new ActionMessages();
        errors.add(field, actionMessage);
        addErrors(request, errors);
    }

    protected void addActionMessageForField(HttpServletRequest request, String key, String field)
    {
        addActionMessageForField(request, new ActionMessage(key), field);
    }

    protected void addActionMessageForField(HttpServletRequest request, String key, String value, String field)
    {
        addActionMessageForField(request, new ActionMessage(key, value), field);
    }

    /**
     * Create rule validation error messages
     *
     * @param request the Http Request
     * @param valMessages The validation messages
     */
    protected void setValidationMessages(HttpServletRequest request, ValidationMessages valMessages)
    {
        ActionMessages errors = new ActionMessages();

        //Add Global message if rule errors are not present
        if (valMessages == null || valMessages.getCount() < 1)
        {
            errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("message.validationErrorsFound"));
        }
        else
        {
            //Get message resources
            MessageResources msgResources = getResources(request);

            //loop though and replace the field name with the UI field Name
            for (Iterator iter = valMessages.get(); iter.hasNext();)
            {
                ValidationMessage valMsg = (ValidationMessage)iter.next();
                ActionMessage actionMsg = new ActionMessage(valMsg.getKey(), valMsg.getValues());
                String fieldName = null;
                String uiFieldList = null;
                String[] uiFieldNames = null;

                if (valMsg instanceof ValidationFieldMessage)
                {
                    fieldName = ((ValidationFieldMessage)valMsg).getFieldName();
                    String fieldNameKey = RULE_ERROR_MSG_KEY_PREFIX + fieldName.replace(' ', '_');
                    if (StringUtils.isNotEmpty(fieldName))
                    {
                        uiFieldList = msgResources.getMessage(fieldNameKey);
                        if (StringUtils.isNotEmpty(uiFieldList))
                        {
                            uiFieldNames = uiFieldList.split(",");
                            //Add field specific validation messages if field name is provided
                            if (uiFieldNames != null && uiFieldNames.length > 0)
                            {
                                for (int i = 0; i < uiFieldNames.length; i++)
                                {
                                    errors.add(uiFieldNames[i], actionMsg);
                                    errors.add(uiFieldNames[i] + "_" + valMsg.getIdentifier(), actionMsg);
                                }
                            }
                        }
                        else
                        {
                            errors.add(fieldName, actionMsg);
                            if (StringUtils.isNotEmpty(valMsg.getIdentifier()))
                            {
                                errors.add(fieldName + "_" + valMsg.getIdentifier(), actionMsg);
                            }
                        }
                    }
                }
                //Add defualt message if the field map is not specified
                else
                {
                    errors.add(ActionMessages.GLOBAL_MESSAGE, actionMsg);
                }
            }
        }
        //Add errors to the action
        addErrors(request, errors);
    }

    protected void addInformationMessage(HttpServletRequest request, ActionMessage actionMessage)
    {
        if (actionMessage == null) return;

        ActionMessages messages = (ActionMessages)request.getAttribute(Globals.MESSAGE_KEY);
        if (messages == null)
        {
            messages = new ActionMessages();
            request.setAttribute(Globals.MESSAGE_KEY, messages);
        }
        messages.add(ActionMessages.GLOBAL_MESSAGE, actionMessage);
    }

    protected void addInformationMessage(HttpServletRequest request, String messageKey)
    {
        addInformationMessage(request, new ActionMessage(messageKey));
    }

    protected void addInformationMessage(HttpServletRequest request, String key, String value)
    {
        addInformationMessage(request, new ActionMessage(key, value));
    }

    private void addUserMessage(HttpServletRequest request)
    {
        processMessages(request, INFO_MESSAGE);
        processMessages(request, ERROR_MESSAGE);
        processMessages(request, WARNING_MESSAGE);
    }

    private void processMessages(HttpServletRequest request, String messageCategory)
    {
        // Get the optional value from the request
        String value = getValueFromParamOrAtttributeKey(request, messageCategory);
        processMessage(request, messageCategory, value);
    }

    /**
     * Processes a user message by adding the appropriate ActionMessages.
     * @param request the HttpServletRequest.
     * @param messageCategory the message category.
     * @param value the message value that contains comma delimited message keys.
     */
    protected void processMessage(HttpServletRequest request, String messageCategory, String value)
    {
        if (value != null)
        {
            // Multiple keys are delimited by a ","
            String[] messageKeys = value.split(",");
            if (messageKeys != null && messageKeys.length > 0)
            {
                // Process each key
                for (int i=0; i < messageKeys.length; i++)
                {
                    // Add the message based on the category type
                    String messageKey = messageKeys[i];

                    // Process "info" message
                    if (messageCategory.equals(INFO_MESSAGE))
                    {
                        addInformationMessage(request, messageKey);
                    }

                    // Process "info" message
                    if (messageCategory.equals(ERROR_MESSAGE))
                    {
                        addActionMessage(request, messageKey);
                    }

                    // Process "warning" message
                    if (messageCategory.equals(WARNING_MESSAGE))
                    {
                        // ***** REVISIT *****
                        // Add as informational for now.  Need to add support for warning messages in the future.
                        addInformationMessage(request, messageKey);
                    }
                }
            }
        }
    }

    /**
     * Gets the value for the specified key from the list of parameters or the list of attributes in the request.
     *
     * @param request The HttpServletRequest
     * @param key The key to check
     *
     * @return The value for the specified key or null if one wasn't found.
     */
    protected String getValueFromParamOrAtttributeKey(HttpServletRequest request, String key)
    {
        String value = null;

        // Get the value from the parameter list
        value = request.getParameter(key);

        // If a value wasn't found, try the attribute list
        if (StringUtils.isEmpty(value))
        {
            value = (String)request.getAttribute(key);
        }

        // If we still don't have a value, ensure it is null (as opposed to the empty string)
        if (StringUtils.isEmpty(value))
        {
            value = null;
        }

        return value;
    }

    /**
     * Default implementation method for getting the forward page when an optimistic lock error occurs. Action classes
     * can override this method to implement custom forward logic.
     *
     * @param mapping the Action Mapping
     * @param form The Action Form
     * @param request The Http Request
     * @param response The Http Response
     * @return The Action Forward
     * @throws Exception if any errors were encountered
     */
    protected ActionForward handleOptimisticLockException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get the olerror page
        ActionForward forward = mapping.findForward(FWD_OLERROR);

        // Get the input page if the oleror page is not specified
        if (forward == null)
        {
            forward = mapping.getInputForward();
        }

        return forward;
    }

    /**
     * This default implementation does nothing.  Child classes should extend this method if they wish to implement
     * custom behavior for processing optimistic locking exceptions.
     *
     * @param request The request
     * @param ex The service optimistic lock exception
     *
     * @throws Exception If any problems are encountered.
     */
    protected void processOptimisticLockException(HttpServletRequest request,
        ServiceOptimisticLockException ex) throws Exception
    {
    }

    /**
     * This default implementation calls handleOptimisticLockException since it's processing should be the same
     * for when a person is locked.
     *
     * @param mapping the ActionMapping
     * @param form the ActionForm
     * @param request The request
     * @param response The response
     * @return an ActionForward
     *
     * @throws Exception If any problems are encountered.
     */
    protected ActionForward handlePersonLockedException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        return handleOptimisticLockException(mapping, form, request, response);
    }

    /**
     * This default implementation calls handlePersonLockedException since it's processing should be the same
     * for when an entity hasn't changed.
     *
     * @param mapping the ActionMapping
     * @param form the ActionForm
     * @param request The request
     * @param response The response
     * @return an action forward
     *
     * @throws Exception If any problems are encountered.
     */
    protected ActionForward handleEntityNotChangedException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get the olerror page
        ActionForward forward = mapping.findForward(FWD_NO_DATA_CHANGED);

        // Get the input page if the oleror page is not specified
        if (forward == null)
        {
            forward = mapping.getInputForward();
        }

        return forward;
    }

    /**
     * This default implementation does nothing.  Child classes should extend this method if they wish to implement
     * custom behavior for processing person locked exceptions.
     *
     * @param request The request
     * @param ex The person locked exception
     *
     * @throws Exception If any problems are encountered.
     */
    protected void processPersonLockedException(HttpServletRequest request,
        PersonLockedException ex) throws Exception
    {
    }

    /**
     * This default implementation does nothing.  Child classes should extend this method if they wish to implement
     * custom behavior for processing entity not changed exceptions.
     *
     * @param request The request
     * @param ex The EntityNotChangedException
     *
     * @throws Exception If any problems are encountered.
     */
    protected void processEntityNotChangedException(HttpServletRequest request,
        EntityNotChangedException ex) throws Exception
    {
    }

    /**
     * This default implementation calls handleOptimisticLockException since it's processing should be the same.
     *
     * @param mapping the ActionMapping
     * @param form the ActionForm
     * @param request The request
     * @param response The response
     * @return an ActionForward
     *
     * @throws Exception If any problems are encountered.
     */
    protected ActionForward handleTimeoutException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        return handleOptimisticLockException(mapping, form, request, response);
    }

    /**
     * This default implementation does nothing.  Child classes should extend this method if they wish to implement
     * custom behavior for processing timeout exceptions.
     *
     * @param request The request
     * @param ex The person locked exception
     *
     * @throws Exception If any problems are encountered.
     */
    protected void processTimeoutException(HttpServletRequest request,
        TimeoutServiceException ex) throws Exception
    {
    }

    /**
     *
     * Get ActionForward path based on the the ValidationMessages.
     * Used to display info messages for update scenarios.
     *
     * If there are no ValidationMessages, return an ActionForward instance with
     * the specified forwardPath
     * If ValidationMessages are present, appends the ValidationMessages keys to the forward
     * path.
     *
     * e.g <forward name="overviewError" path="/insuranceInfoDisplay.do?infoMessage=" redirect="true"/>
     * Adds the error key from the ValidationMessage after the infoMessage.
     *
     * @param mapping an Action Mapping
     * @param messages the validation messages
     * @param forwardPath The forward path
     * @return The action forward
     */
    protected ActionForward getForwardPathFromValidationMessages(
            ActionMapping mapping, ValidationMessages messages,
            String forwardPath)
    {
        ActionForward forward =
            new ActionForward(mapping.findForward(forwardPath));

        //Create a comma separated String consisting of ValidationMessage keys
        StringBuffer messageKeys = new StringBuffer();

        if (messages != null && !messages.isEmpty())
        {
            int count = 0;

            for (Iterator iter = messages.get(); iter.hasNext();)
            {
                count++;

                ValidationMessage message = (ValidationMessage) iter.next();
                messageKeys.append(message.getKey());

                if (count < messages.getCount())
                    messageKeys.append(",");

            }

            //If a forward path already contains some params, then append the
            // message keys.Else add the keys as infoMessage params to the forward path
            if ((forward.getPath().indexOf(INFO_MESSAGE) != -1)
                    || (forward.getPath().indexOf(ERROR_MESSAGE) != -1)
                    || (forward.getPath().indexOf(WARNING_MESSAGE) != -1))
            {
                forward.setPath(forward.getPath() + ","
                        + messageKeys.toString());
            } else
            {
                forward.setPath(forward.getPath() + "?infoMessage="
                        + messageKeys.toString());
            }

        }

        return forward;
    }


    /**
     * Generic method to get the Configured bean from WebApplicationContext
     *
     * @param name Bean Id return Object
     * @return the bean
     * @throws ServiceException if the bean could not be obtained
     */
    public final Object getBean(String name) throws ServiceException {
        try {
      	  // Returns a bean from a web context
      	  WebApplicationContext wac = this.getWebApplicationContext();
      	  return wac.getBean(name);
        }
        catch( Exception e ) {
      	  log.error( "Bean lookup error ", e );
      	  throw new ServiceException("Bean lookup error", e);
        }
    }

    /**
     * Invokes a service to process a request.  A service information is encapsulated in a service descriptor object.
     * Request data is encapsulated in an array of parameters.
     *
     * @param params An array of parameters to be passed to a service's method
     * @param serviceName A service descriptor encapsulating a service information
     * @param methodName The method name on the service to invoke
     *
     * @return A generic object representing data returned from a service
     * @throws ServiceException Thrown if failed to serve a request
     */
    public final Object invokeService(Object[] params, String serviceName, String methodName) throws ServiceException
    {
        Object service = getBean(serviceName);

        if (logger.isDebugEnabled())
        {
            logger.debug("Service class " + service.getClass().getName());
            logger.debug("Service name " + serviceName);
            logger.debug("Method name" + methodName);
        }
        Object value = null;
        try
        {
            value = Reflector.invoke(service, methodName, params);
        }
        catch (NoSuchMethodException e)
        {
            throw new ServiceException("Failed to find a method: " + methodName + "to invoke", e);
        }
        catch (InvocationTargetException e)
        {
            throw new ServiceException("Failed to invoke a method: " + methodName + " in service " + serviceName, e);
        }
        catch (ReflectionException e)
        {
            throw new ServiceException("Access to method: " + methodName + " is restricted", e);
        }
        return value;
    }

    public PersonService getPersonService()
    {
        return personService;
    }

    public void setPersonService(PersonService personService)
    {
        this.personService = personService;
    }

    public LookupService getLookupService()
    {
        return lookupService;
    }

    public void setLookupService(LookupService lookupService)
    {
        this.lookupService = lookupService;
    }

    public LookupCacheService getLookupCacheService()
    {
        return this.lookupCacheService;
    }

    public void setLookupCacheService(LookupCacheService lookupCacheService)
    {
        this.lookupCacheService = lookupCacheService;
    }

    public PersonHelperService getPersonHelperService()
    {
        return this.personHelperService;
    }

    public DemographicService getDemographicService()
    {
        return demographicService;
    }

    public void setDemographicService(DemographicService demographicService)
    {
        this.demographicService = demographicService;
    }

    public void setPersonHelperService(PersonHelperService personHelperService)
    {
        this.personHelperService = personHelperService;
    }

    public AssociationService getAssociationService()
    {
        return associationService;
    }

    public void setAssociationService(AssociationService associationService)
    {
        this.associationService = associationService;
    }

    public MessagingService getMessagingService()
    {
        return messagingService;
    }

    public void setMessagingService(MessagingService messagingService)
    {
        this.messagingService = messagingService;
    }

    public FinancialsService getFinancialsService()
    {
        return financialsService;
    }

    public void setFinancialsService(FinancialsService financialsService)
    {
        this.financialsService = financialsService;
    }

    public CopyService getCopyService()
    {
        return copyService;
    }

    public void setCopyService(CopyService copyService)
    {
        this.copyService = copyService;
    }

    public MergeRuleService getMergeRuleService()
    {
        return mergeRuleService;
    }

    public void setMergeRuleService(MergeRuleService mergeRuleService)
    {
        this.mergeRuleService = mergeRuleService;
    }

    public InsuranceService getInsuranceService()
    {
        return insuranceService;
    }

    public void setInsuranceService(InsuranceService insuranceService)
    {
        this.insuranceService = insuranceService;
    }

    public PersonMergeService getPersonMergeService()
    {
        return personMergeService;
    }

    public void setPersonMergeService(PersonMergeService personMergeService)
    {
        this.personMergeService = personMergeService;
    }

    public PersonUnmergeService getPersonUnmergeService()
    {
        return personUnmergeService;
    }

    public void setPersonUnmergeService(PersonUnmergeService personUnmergeService)
    {
        this.personUnmergeService = personUnmergeService;
    }

    public EligibilityEnrollmentService getEnrollmentService()
    {
        return enrollmentService;
    }

    public void setEnrollmentService(EligibilityEnrollmentService enrollmentService)
    {
        this.enrollmentService = enrollmentService;
    }

    public MilitaryInfoService getMilitaryInfoService()
    {
        return militaryInfoService;
    }

    public void setMilitaryInfoService(MilitaryInfoService militaryInfoService)
    {
        this.militaryInfoService = militaryInfoService;
    }

    public EGTService getEgtService()
    {
        return egtService;
    }

    public void setEgtService(EGTService egtService)
    {
        this.egtService = egtService;
    }

    public RegistryService getRegistryService() {
        return registryService;
    }

    public void setRegistryService(RegistryService registryService) {
        this.registryService = registryService;
    }

    public StandardReportService getStandardReportService() {
        return standardReportService;
    }

    public void setStandardReportService(StandardReportService standardReportService) {
        this.standardReportService = standardReportService;
    }

    public UserAdminService getUserAdminService() {
        return userAdminService;
    }

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

    public SystemParameterService getSystemParameterService() {
        return systemParameterService;
    }

    public void setSystemParameterService(
            SystemParameterService systemParameterService) {
        this.systemParameterService = systemParameterService;
    }
    public WorkflowService getWorkflowService() {
        return workflowService;
    }

    public void setWorkflowService(WorkflowService workflowService) {
        this.workflowService = workflowService;
    }
	/**
	 * @return Returns the commsLetterRequestService.
	 */
	public CommsLetterRequestService getCommsLetterRequestService() {
		return commsLetterRequestService;
	}
	/**
	 * @param commsLetterRequestService The commsLetterRequestService to set.
	 */
	public void setCommsLetterRequestService(
			CommsLetterRequestService commsLetterRequestService) {
		this.commsLetterRequestService = commsLetterRequestService;
	}
	/**
	 * @return Returns the commsLogService.
	 */
	public CommsLogService getCommsLogService() {
		return commsLogService;
	}
	/**
	 * @param commsLogService The commsLogService to set.
	 */
	public void setCommsLogService(CommsLogService commsLogService) {
		this.commsLogService = commsLogService;
	}

    public PurpleHeartService getPurpleHeartService() {
        return purpleHeartService;
    }

    public void setPurpleHeartService(PurpleHeartService purpleHeartService) {
        this.purpleHeartService = purpleHeartService;
    }

    public CopyService getPersonMergeCopyService() {
        return personMergeCopyService;
    }

    public void setPersonMergeCopyService(CopyService personMergeCopyService) {
        this.personMergeCopyService = personMergeCopyService;
    }

    public EEServiceAdminService getEeServiceAdminService() {
		return eeServiceAdminService;
	}

	public void setEeServiceAdminService(EEServiceAdminService eeServiceAdminService) {
		this.eeServiceAdminService = eeServiceAdminService;
	}

	public ApplicationInProcessService getApplicationInProcessService() {
		return applicationInProcessService;
	}

	public void setApplicationInProcessService(ApplicationInProcessService applicationInProcessService) {
		this.applicationInProcessService = applicationInProcessService;
	}

	public HealthBenefitPlanService getHealthBenefitPlanService() {
		return healthBenefitPlanService;
	}

	public void setHealthBenefitPlanService(HealthBenefitPlanService healthBenefitPlanService) {
		this.healthBenefitPlanService = healthBenefitPlanService;
	}

	public List matchSets(Set current, Set previous) {
        List list = new ArrayList ();

        //find the deleted list
        Set currentSet = current == null ? new HashSet() : new HashSet(current);
        Set previousSet = previous == null ? new HashSet() : new HashSet(previous);

        for (Iterator i=previousSet.iterator(); i.hasNext();) {

            Object objPrevious = i.next();

            //get the matchig element from the current set
            Object objCurrent = getMatch(objPrevious,currentSet);
            list.add(new EntityHistory(objCurrent,objPrevious));
            if (objCurrent != null) {
                currentSet.remove(objCurrent);
            }
        }

        //find the new and modified list (remaining objects in the current set)
        for (Iterator i=currentSet.iterator(); i.hasNext();) {
            Object objCurrent = i.next();
            list.add(new EntityHistory(objCurrent,null));
        }
        return list;
    }

    /**
     * Match the AbstractKeyedEntity objects based on identifier (key) value
     * and by object equality for all others
     * @param obj the object to get a match on
     * @param set the set of objects to search
     * @return the matched object or null if no match
     */
    public Object getMatch(Object obj, Set set){
        if (obj != null && obj instanceof AbstractKeyedEntity) {
            //Loop through the set and match the identifers
            for (Iterator i= set.iterator(); i.hasNext();)
            {
                EntityKey keySrc = ((AbstractKeyedEntity)obj).getEntityKey();
                AbstractKeyedEntity target = (AbstractKeyedEntity)i.next();
                //TODO target should not be null - sometimes history is getting null objects
                //needs to investigate 12/11/2006 Madhu
                if (target == null)
                    continue;
                if (keySrc.equals(target.getEntityKey()))
                {
                    return target;
                }
                else if (match(obj, target)) {
                    return target;
                }
            }
            //No Match
            return null;
        }
        //for generic String and Date objects if any
        else {
            return (set.contains(obj) ? obj: null);
        }
    }

	/**
     * Generic match methods for ordering the lists
     * @param src the soruce object
     * @param target the target object
     * @return whether the objects match or not
	 */
    public boolean match(Object src, Object target) {
        return src.equals(target);
    }
    /**
     * Generic methods to set and get Pristine and Updated entities
     * @param request the Http Request
     * @return the pristine entity
     */
    protected Object getPristineEntity(HttpServletRequest request) {
        return request.getSession().getAttribute(
                ApplicationConstants.SessionData.PRISTINE_ENTITY);
    }
    protected void setPristineEntity(HttpServletRequest request, Object attr) {
        request.getSession().setAttribute(
                ApplicationConstants.SessionData.PRISTINE_ENTITY,attr);
    }
    protected Object getUpdatedEntity(HttpServletRequest request) {
        return request.getSession().getAttribute(
                ApplicationConstants.SessionData.UPDATED_ENTITY);
    }
    protected void setUpdatedEntity(HttpServletRequest request, Object attr) {
        request.getSession().setAttribute(
                ApplicationConstants.SessionData.UPDATED_ENTITY,attr);
    }
    protected Object getLockedMergeInfoEntityKey(HttpServletRequest request) {
        return request.getSession().getAttribute(
                ApplicationConstants.SessionData.LOCKED_MERGE_INFO_ENTITYKEY);
    }
    protected void setLockedMergeInfoEntityKey(HttpServletRequest request, Object attr) {
        request.getSession().setAttribute(
                ApplicationConstants.SessionData.LOCKED_MERGE_INFO_ENTITYKEY,attr);
    }
    protected List getAsyncMessages(HttpSession session)
    {
        if (session != null)
        {
            return (List)session.getAttribute(ApplicationConstants.SessionData.ASYNC_MESSAGES);
        }
        else
        {
            return null;
        }
    }
    protected void setAsyncMessages(HttpSession session, List messages)
    {
        if (session != null)
        {
            session.setAttribute(ApplicationConstants.SessionData.ASYNC_MESSAGES, messages);
        }
    }
    protected void addAsyncMessages(HttpSession session, String message)
    {
        if (session != null)
        {
            List messageList = getAsyncMessages(session);
            if (messageList == null)
            {
                messageList = new ArrayList();
                setAsyncMessages(session, messageList);
            }
            messageList.add(message);
        }
    }
    protected String getMessage(HttpServletRequest request, String key){
    	return getResources(request).getMessage(key);
    }
    public PasswordEncryptionService getPasswordEncryptionService() {
        return passwordEncryptionService;
    }

    public void setPasswordEncryptionService(
            PasswordEncryptionService passwordEncryptionService) {
        this.passwordEncryptionService = passwordEncryptionService;
    }

	public HandBookService getHandBookService() {
		return handBookService;
	}

	public void setHandBookService(HandBookService handBookService) {
		this.handBookService = handBookService;
	}

	public ArchivedMessagingService getArchivedMessagingService() {
		return archivedMessagingService;
	}

	public void setArchivedMessagingService(
			ArchivedMessagingService archivedMessagingService) {
		this.archivedMessagingService = archivedMessagingService;
	}

	public VOAApplicationService getVoaApplicationService() {
		return voaApplicationService;
	}

	public void setVoaApplicationService(VOAApplicationService voaApplicationService) {
		this.voaApplicationService = voaApplicationService;
	}

	 public VHICCardInfoService getVhicCardInfoService() {
			return vhicCardInfoService;
		}

		public void setVhicCardInfoService(VHICCardInfoService vhicCardInfoService) {
			this.vhicCardInfoService = vhicCardInfoService;
		}

    public HBPDefinitionService getHbpDefinitionService() {
            return hbpDefinitionService;
        }

    public void setHbpDefinitionService(HBPDefinitionService hbpDefinitionService) {
            this.hbpDefinitionService = hbpDefinitionService;
        }

	public IRSTransmissionService getIrsTransmissionService() {
		return irsTransmissionService;
	}

	public void setIrsTransmissionService(IRSTransmissionService irsTransmissionService) {
		this.irsTransmissionService = irsTransmissionService;
	}

	public VeteransChoiceInformationService getVeteransChoiceInformationService() {
		return veteransChoiceInformationService;
	}

	public void setVeteransChoiceInformationService(VeteransChoiceInformationService veteransChoiceInformationService) {
		this.veteransChoiceInformationService = veteransChoiceInformationService;
	}
	public CorrespondenceService getCorrespondenceService() {
		return correspondenceService;
	}

	public void setCorrespondenceService(CorrespondenceService correspondenceService) {
		this.correspondenceService = correspondenceService;
	}

}