/********************************************************************
 * Copyright � 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.service.impl;

// Java Classes
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
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.text.SimpleDateFormat;

import javax.security.auth.login.LoginException;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.hibernate.exception.ConstraintViolationException;

import com.thoughtworks.xstream.XStream;

import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.infra.TriState;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.SiteYear;
import gov.va.med.esr.common.model.ee.AgentOrangeExposure;
import gov.va.med.esr.common.model.ee.CampLejeuneVerification;
import gov.va.med.esr.common.model.ee.EnvironmentalContaminationExposure;
import gov.va.med.esr.common.model.ee.NoseThroatRadium;
import gov.va.med.esr.common.model.ee.PrisonerOfWar;
import gov.va.med.esr.common.model.ee.PurpleHeart;
import gov.va.med.esr.common.model.ee.RadiationExposure;
import gov.va.med.esr.common.model.ee.SHAD;
import gov.va.med.esr.common.model.ee.VerificationInfo;
import gov.va.med.esr.common.model.ee.VoaFileAttachment;
import gov.va.med.esr.common.model.financials.FinancialStatement;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.lookup.AuthenticationLevel;
import gov.va.med.esr.common.model.lookup.EnrollmentPriorityGroup;
import gov.va.med.esr.common.model.lookup.EnrollmentStatus;
import gov.va.med.esr.common.model.lookup.FunctionalGroup;
import gov.va.med.esr.common.model.lookup.Gender;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.lookup.VOAApplicationStatus;
import gov.va.med.esr.common.model.lookup.VOAFormType;
import gov.va.med.esr.common.model.lookup.WkfCaseType;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.party.Email;
import gov.va.med.esr.common.model.party.Phone;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.FullyQualifiedIdentity;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.VOAApplication;
import gov.va.med.esr.common.model.person.VOAResubmissionData;
import gov.va.med.esr.service.VOASearchCriteria;
import gov.va.med.esr.service.VOASearchResultBean;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKeyImpl;
import gov.va.med.esr.common.persistent.ee.VoaFileAttachmentDAO;
import gov.va.med.esr.common.persistent.person.VOAApplicationDAO;
import gov.va.med.esr.service.CommsEmailBulletinService;
import gov.va.med.esr.service.FinancialsHelperService;
import gov.va.med.esr.service.IdmServiceVO;
import gov.va.med.esr.service.MessagingService;
import gov.va.med.esr.service.PersonSearchQueryInfo;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.esr.service.VOAApplicationService;
import gov.va.med.esr.service.WorkflowService;
import gov.va.med.esr.service.trigger.BulletinTrigger;
import gov.va.med.esr.service.trigger.VOATriggerEvent;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.security.LoginManager;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.security.UserCredentials;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.trigger.TriggerRouter;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.ps.model.PatientIdentifier;
import gov.va.med.fw.service.config.SingletonApplicationContext;
import gov.va.med.fw.service.pagination.SearchQueryInfo;

/**
 * The VOA Application Service implementation.
 * <p/>
 * Project: Common
 *
 * @author DNS   TSAIG
 * @version 3.11
 */
public class VOAApplicationServiceImpl extends AbstractHistoricalInfoServiceImpl implements VOAApplicationService
{

	private static final long serialVersionUID = 8936807483114587339L;

	private static VAFacility VOA_VA_FACILITY = null;

	public VOAApplicationDAO voaApplicationDAO = null;

    private VoaFileAttachmentDAO voaFileAttachmentDAO = null;

    private TriggerRouter triggerRouter = null;

    private IdmWebServiceDelegate idmServiceDelegate = null;

    private PersonService personService = null;

    private SystemParameterService systemParameterService = null;

    private MessagingService messagingService = null;

    private FinancialsHelperService financialsHelperService = null;

    private WorkflowService workflowService = null;

    private CommsEmailBulletinService bulletinService;

    private LoginManager loginManager;

	public static final String TXT_1010EZ = ("1010EZ");
	public static final String TXT_1010EZR = ("1010EZR");
	public static final String TXT_1010HS = ("1010HS");
	public static final String TXT_1010SH = ("1010SH");
	public static final String TXT_1010CG = ("1010CG");
	public static final String TXT_21526EZ = ("21526EZ");  //CCR13857 new form type

	//VOA_IND =1 for Anonymous/LOA1 only, means person found, Proxy PF added successfully
    //VOA_IND = 2 for Anonymous/LOA1 only. It means MVI extended search not found, person was added explicitly
	public static final Character VOA_IND_1 = '1';
	public static final Character VOA_IND_2 = '2';
	private static final Integer defaultIncomeYear = new Integer(Calendar.getInstance().get(Calendar.YEAR)-1);



    /**
     * Default Constructor.
     */
    public VOAApplicationServiceImpl()
    {
        super();
    }

    /******** Begin of property getters/setters *****/
	public VOAApplicationDAO getVoaApplicationDAO() {
		return voaApplicationDAO;
	}

	public void setVoaApplicationDAO(VOAApplicationDAO voaApplicationDAO) {
		this.voaApplicationDAO = voaApplicationDAO;
	}

	public VoaFileAttachmentDAO getVoaFileAttachmentDAO() {
		return voaFileAttachmentDAO;
	}

	public void setVoaFileAttachmentDAO(VoaFileAttachmentDAO voaFileAttachmentDAO) {
		this.voaFileAttachmentDAO = voaFileAttachmentDAO;
	}

	public TriggerRouter getTriggerRouter() {
		return triggerRouter;
	}

	public void setTriggerRouter(TriggerRouter triggerRouter) {
		this.triggerRouter = triggerRouter;
	}



	public IdmWebServiceDelegate getIdmServiceDelegate() {
		return idmServiceDelegate;
	}

	public void setIdmServiceDelegate(IdmWebServiceDelegate idmServiceDelegate) {
		this.idmServiceDelegate = idmServiceDelegate;
	}

	public PersonService getPersonService() {
		return personService;
	}

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

	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;
	}


public CommsEmailBulletinService getBulletinService() {
		return bulletinService;
	}

	public void setBulletinService(CommsEmailBulletinService bulletinService) {
		this.bulletinService = bulletinService;
	}

/******** End of property getters/setters *****/



	public MessagingService getMessagingService() {
		return messagingService;
	}

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

	/**
	 * Save a VOAApplication
	 * @param app
	 * @return VOAApplication saved
	 * @throws ServiceException
	 */
	public VOAApplication save(VOAApplication app) throws ServiceException
    {
        try
        {
			Validate.notNull(app, "A VOA Application input must not be null.");
            // Save the person
			voaApplicationDAO.saveObject(app);

			// Notice we do not clone this return object that is attached to Hibernate session
			return app;
		}
        catch (DAOException e)
        {
			throw new ServiceException("Failed to persist a VOAApplication", e);
		}
	}

	/**
     * Gets the VOA attachment by person ID
     *
     * @param personId
     * @return The list of VOA attachments, null when empty
     * @throws DAOException
     *         Thrown when a persistence exception occurs.
     */
    @SuppressWarnings("rawtypes")
	public List findVoaAttachmentByPersonId(BigDecimal personId) throws ServiceException {
        try
        {
            return voaFileAttachmentDAO.findVoaAttachmentByPersonId(personId);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

	/**
     * Gets the VOA attachment by VOA application ID
     *
     * @param applicationId
     * @return The list of VOA attachments, null when empty
     * @throws DAOException
     *         Thrown when a persistence exception occurs.
     */
    @SuppressWarnings("rawtypes")
	public List findVoaAttachmentByApplicationId(BigDecimal applicationId) throws ServiceException {
        try
        {
            return voaFileAttachmentDAO.findVoaAttachmentByApplicationId(applicationId);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }



	/**
     * Update the VOA attachment attributes
     *
     * @param attachment
     * @throws DAOException
     *         Thrown when a persistence exception occurs.
     */
    public void updateAttachmentAttributes(VoaFileAttachment attachment)  throws ServiceException {
        try
        {
            voaFileAttachmentDAO.updateAttachmentAttributes(attachment);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }
    /**
     * Update the Person Id of the VOA attachment with the specified message control id
     * @param msgControlId
     * @param personId
     * @throws ServiceException
     */
    public void updateVoaAttachmentWithPersonId(String msgControlId, BigDecimal personId)  throws ServiceException
    {
        try
        {
            voaFileAttachmentDAO.updateVoaAttachmentWithPersonId(msgControlId, personId);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * forward VOA application to common JMS queue
     * @param applicationId VOA application id
     * @param person person object
     * @throws ServiceException
     * NOTE: applicationId and person must not be null
     */

    public void forwardVOAApplication(BigDecimal applicationId, Person person) throws ServiceException
    {
        Validate.notNull(applicationId, "VOA application id must not be null");
        Validate.notNull(person, "Incoming Person must not be null in forward VOAAplication");

    	this.getTriggerRouter().processTriggerEvent(new VOATriggerEvent(applicationId, person));
    }

	/**
     * Gets the VOA Application by VOA application ID
     *
     * @param applicationId
     * @return VOAApplication
     * @throws ServiceException
     *         Thrown when a persistence exception occurs.
     */
    public VOAApplication findVoaApplicationByApplicationId(BigDecimal applicationId) throws ServiceException {

    	Validate.notNull(applicationId, "VOA application id must not be null");

    	try
        {
            return voaApplicationDAO.getByApplicationId(applicationId);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    @SuppressWarnings("unchecked")
	public VOAApplication findMostRecentApplicationByPersonId(BigDecimal personId)  throws ServiceException {
    	Validate.notNull(personId, "Person id must not be null");

    	VOAApplication result = null;

    	try {
			List<VOAApplication> allApps = this.getVoaApplicationDAO().getByPersonId(personId);

			if (allApps != null) {
				if (allApps.size() == 1) {
					result =  allApps.get(0);
				} else if (allApps.size() > 1) {
					Collections.sort(allApps, new Comparator<VOAApplication>() {
						  public int compare(VOAApplication o1, VOAApplication o2) {
						      return o1.getResponseTimeStamp().compareTo(o2.getResponseTimeStamp());
						  }
						});
					Collections.reverse(allApps);

					result =  allApps.get(0);
				}
			}

		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(), e);
		}

    	return result;

    }


    @SuppressWarnings("unchecked")
	public VOAApplication findMostRecentApplicationBySSN(String ssn)  throws ServiceException {
    	Validate.notNull(ssn, "ssn must not be null");

    	VOAApplication result = null;

    	try {
			List<VOAApplication> allApps = this.getVoaApplicationDAO().getBySSN(ssn);

			if (allApps != null) {
				if (allApps.size() == 1) {
					result =  allApps.get(0);
				} else if (allApps.size() > 1) {
					Collections.sort(allApps, new Comparator<VOAApplication>() {
						  public int compare(VOAApplication o1, VOAApplication o2) {
						      return o1.getResponseTimeStamp().compareTo(o2.getResponseTimeStamp());
						  }
						});
					Collections.reverse(allApps);

					result =  allApps.get(0);
				}
			}

		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(), e);
		}

    	return result;

    }

    @SuppressWarnings("rawtypes")
	public List findByFQID(String fqid) throws ServiceException {
   	 try
        {
            return voaApplicationDAO.getByFQID(fqid);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
   }

    /**
     * Update VOAApplication
     * @param app
     * @return updated VOAApplication
     * @throws ServiceException
     */
    public VOAApplication updateVOAApplication(VOAApplication app) throws ServiceException
    {
        Validate.notNull(app, "VOA application must not be null");
		try {
			this.getVoaApplicationDAO().update(app);
		} catch (Exception de)
		{
			try {
				app.setPersonId(null);
				this.getVoaApplicationDAO().update(app);
			} catch (Exception d) {
				throw new ServiceException(d);
			}
		}

		return app;
    }

    /**
     * ES 4.0.3_CodeCR-13999
     * removeOrphanedVOAApplication
     * @param app
     * @throws ServiceException
     */

    @SuppressWarnings("rawtypes")
	private void removeOrphanedVOAApplication(VOAApplication app) throws ServiceException
    {
        Validate.notNull(app, "VOA application must not be null");
		try {

            List pendingSubmissions = getVoaApplicationDAO().findByNamedQuery("VOAApplication_GetOrphanedApps", app.getSsn());
            for (int i = 0; i < pendingSubmissions.size(); i++) {
            	VOAApplication orphan = (VOAApplication) pendingSubmissions.get(i);
                   orphan.setApplicationStatus((VOAApplicationStatus) this.getLookupService().getByCode(VOAApplicationStatus.class,
                                 VOAApplicationStatus.FORM_RESUBMITTED));
                   orphan.setErrorText("Status Reset. A subsequent application for this person has processed successfully");
                   this.getVoaApplicationDAO().saveObject(orphan);
            }
		} catch (DAOException de) {
			logger.error("failed to reconcile orphaned applications: ", de);
		}
    }


    /**
     * Process VOA Application with application id and person object
     * @param applicationId the application id from VOA Application
     * @param incoming the person comes from the VOA web service
     * @throws ServiceException
     */

    /**
	 * RTC Task 236652 -Fix for When a veteran answers no to the disclose financial details option the VOA form.
	 * This method was changed to public to facilitate the implementation for the task item.
	 */
    public boolean isDSLogonLevel2(VOAApplication app) {
    	if (app.getAuthenticationLevel() == null ||
    			AuthenticationLevel.ANONYMOUS.getCode().equals(app.getAuthenticationLevel().getCode()) ||
    			AuthenticationLevel.DS_LOGON_LEVEL_1.getCode().equals(app.getAuthenticationLevel().getCode()))
    		return false;

    	return true;
    }


    @SuppressWarnings({ "static-access" })
	public Person processVoaApplication(BigDecimal applicationId, Person incoming)
			throws ServiceException {

    	Validate.notNull(applicationId, "VOA application id must not be null");
		Validate.notNull(incoming, "Incoming Person must not be null in processVoaApplication");


		//retrieve VAOApplication
		VOAApplication app = null;
		try {
			app = this.getVoaApplicationDAO().getByApplicationId(applicationId);
		} catch (DAOException de) {
			logger.error("Failed to retrieve VOA Submission ID" + applicationId + " : " + ExceptionUtils.getFullStackTrace(de));

			throw new ServiceException("Failed to retrieve VOA Submission ID " + applicationId, de);
		}

		if (app == null)
		{
			throw new ServiceException("Failed to retrieve VOA Submission ID " + applicationId);
		}


		app.setApplicationStatus((VOAApplicationStatus) this.getLookupService().
				getByCode(VOAApplicationStatus.class, VOAApplicationStatus.FORM_PROCESSING_IN_PROGRESS));

		this.updateVOAApplication(app);

		if (this.VOA_VA_FACILITY == null) {
			VOA_VA_FACILITY = this.getLookupService().getVaFacilityByStationNumber(VAFacility.CODE_MHV.getCode());
		}


		boolean anonymous = true;
		if (this.isDSLogonLevel2(app))
		{
			anonymous = false;
		}

		return this.processVOAPerson(app, incoming, anonymous);
    }

    @SuppressWarnings({ "static-access" })
   	private void reprocessVoaApplication(BigDecimal applicationId, Person incoming)
   			{



       	Validate.notNull(applicationId, "VOA application id must not be null");
   		Validate.notNull(incoming, "Incoming Person must not be null in processVoaApplication");


   		//retrieve VAOApplication
   		VOAApplication app = null;
   		try {
	   		try {
	   			app = this.getVoaApplicationDAO().getByApplicationId(applicationId);
	   		} catch (DAOException de) {
	   			logger.error("Failed to retrieve VOA Submission ID" + applicationId + " : " + ExceptionUtils.getFullStackTrace(de));

	   			throw new ServiceException("Failed to retrieve VOA Submission ID " + applicationId, de);
	   		}

	   		if (app == null)
	   		{
	   			throw new ServiceException("Failed to retrieve VOA Submission ID " + applicationId);
	   		}


	   		app.setApplicationStatus((VOAApplicationStatus) this.getLookupService().
	   				getByCode(VOAApplicationStatus.class, VOAApplicationStatus.FORM_RESUBMITTED));

	   		this.updateVOAApplication(app);

	   		if (this.VOA_VA_FACILITY == null) {
	   			VOA_VA_FACILITY = this.getLookupService().getVaFacilityByStationNumber(VAFacility.CODE_MHV.getCode());
	   		}


	   		boolean anonymous = true;
	   		if (this.isDSLogonLevel2(app))
	   		{
	   			anonymous = false;
	   		}

	   		 this.processVOAPerson(app, incoming, anonymous);
	    	} catch (Exception ex) {
	    		try {
	    			app.setApplicationStatus((VOAApplicationStatus) this.getLookupService().
	    	   				getByCode(VOAApplicationStatus.class, VOAApplicationStatus.FORM_SUBMISSION_FAILED));
	    			this.setVOAFormFailed(app, incoming);
				} catch (ServiceException e) {
					logger.error(e.getMessage());
				}
	    	}
       }

    private void setVeteranIndicator(VOAApplication app, Person incoming) {
    	incoming.setVeteran(Boolean.TRUE);
    }

	public String convertFormType(VOAApplication app){
		String formType=null;
		if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_1010EZ.getCode()))
		{
						formType = TXT_1010EZ;
		}
		else if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_1010EZR.getCode()))
		{
						formType = TXT_1010EZR;
		}
		else if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_1010HS.getCode()))
		{
						formType = TXT_1010HS;
		}
		else if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_1010SH.getCode()))
		{
						formType = TXT_1010SH;
		}
		else if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_1010CG.getCode()))
		{
						formType = TXT_1010CG;
		}
		else if (app.getFormType().getCode().equals(VOAFormType.VOA_FORM_21526EZ.getCode()))
		{
						formType = TXT_21526EZ;
		}
		else formType = " - Unknown Form";
		return formType;
	}

	private Person convertIdmServiceVOToPerson(IdmServiceVO idmServiceVO, VPIDEntityKey vpid)
	    	throws ServiceException
		{
	    	if (vpid == null)
		        return null;

	    	Person target = new Person(vpid);
	    		// name
		    target.addName(idmServiceVO.getLegalName());

		    // dob
		    BirthRecord dob = idmServiceVO.getBirthRecord();

	        target.setBirthRecord(dob);

		    // Gender
		    target.setGender(idmServiceVO.getGender());
		    //target.setSelfIdentifiedGenderIdentity(idmServiceVO.getSigi());

		    // SSNS
		    SSN ssn = idmServiceVO.getSsn();
		    ssn.setType(getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
		    target.addSsn(idmServiceVO.getSsn());


		    // IdM match type:
		    target.setIdmMatchType(idmServiceVO.getIdmMatchType());

	        return target;
		}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private IdmServiceVO createIdmServiceVO(PersonSearchQueryInfo info) throws Exception  {

		IdmServiceVO idmServiceVO = new IdmServiceVO();

		Name lName = new Name();
		lName.setGivenName(info.getGivenName() != null ? info.getGivenName() : "");
		lName.setMiddleName(info.getMiddleName() != null ? info.getMiddleName() : "");
		lName.setFamilyName(info.getFamilyName() != null ? info.getFamilyName() : "");
		lName.setType(getLookupService().getNameTypeByCode(NameType.LEGAL_NAME.getName()));


		HashSet names = new HashSet();
		names.add(lName);
		idmServiceVO.setNames(names);

		BirthRecord br = new BirthRecord();
		br.setBirthDate(new ImpreciseDate(info.getDateOfBirth()));
		idmServiceVO.setBirthRecord(br);
		Gender gender = getLookupService().getGenderByCode(info.getGender());
		idmServiceVO.setGender(gender);

		Address permAddress = new Address();
		permAddress.setLine1(info.getAddress() != null ? info.getAddress() : "");
		permAddress.setLine2("");
		permAddress.setLine3("");
		permAddress.setCity(info.getCity() != null ? info.getCity() : "");
		permAddress.setState(info.getState() != null ? info.getState() : "");
		permAddress.setZipCode(info.getZipCode() != null ? info.getZipCode() : "");
		permAddress.setPostalCode(info.getPostalCode() != null ? info.getPostalCode() : "");

		String country = info.getCountry() != null ? info.getCountry() : "";
		if (StringUtils.isEmpty(country)) {
			country = "USA";
		}
		permAddress.setCountry(country);
		permAddress.setPhoneNumber(info.getHomePhoneNumber() != null ? info.getHomePhoneNumber() : "");
		permAddress.setType(getLookupService().getAddressTypeByCode("P"));
		idmServiceVO.addAddress(permAddress);

		SSN ssN = new SSN();
		ssN.setSsnText(info.getUnformattedSsn());
		idmServiceVO.setSsn(ssN);


		return idmServiceVO;
	}


	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Person processVOAPerson(VOAApplication app, Person incoming, boolean anonymous) throws ServiceException {

		Validate.notNull(app, "VOA application must not be null");
		Validate.notNull(incoming, "Incoming Person must not be null in processVOAPerson");

		//determine and set the veteran indicator
		setVeteranIndicator(app, incoming);

		List<Person> results = null;
		VPIDEntityKey vpid = null;
		Person onFile = null;

		if (anonymous) {

			PersonSearchQueryInfo queryInfo = new PersonSearchQueryInfo();
			queryInfo.setAddAPerson(false);
			queryInfo.setCaseSensitive(false);
			queryInfo.setDateOfBirth(new ImpreciseDate(app.getDateOfBirth()).toStandardFormat());
			queryInfo.setFamilyName(app.getLastName());
			queryInfo.setGender(app.getGender().getCode());
			queryInfo.setGivenName(app.getFirstName());
			queryInfo.setMiddleName(app.getMiddleName());
			queryInfo.setMaxAllowedRecords(10);
			queryInfo.setUnformattedSsn(app.getSsn());


			try {
				results = this.getPersonService().search(queryInfo, true, true, false, 10);
			} catch (ServiceException ex) {
				throw new ServiceException ("Failed to Retrieve Person from trait search to MVI:", ex);
			}

			if (results != null && results.size() > 1) {
				throw new ServiceException ("MVI trait search returned multiple matches. Manual registration is required.");
			}

			//one exact match then use it
			try {
				if (results != null && results.size() == 1) {
					Person p = (Person)results.get(0);
					vpid = p.getVPIDEntityKey();

					//retrieve full person
					onFile = this.getPersonService().getPersonWithCompositeCall(vpid);
					//add 200ESR if not exist
					if (onFile.getIdentityTraits().has200ESRCorrelation().equalsIgnoreCase("N")) {
						getPersonService().addESRCorrelation(onFile);
					}

				}
			} catch (ServiceException ex) {
				throw new ServiceException ("Failed to Retrieve Person from search results:", ex);
			}

			//no match then add
			try {
				if (results == null || results.size() == 0) {
					IdmServiceVO idmServiceVO = this.createIdmServiceVO(queryInfo);
					idmServiceVO.setMothersMaidenName(incoming.getMothersMaidenName());
					idmServiceVO.getBirthRecord().setCity(incoming.getBirthRecord().getCity());
					idmServiceVO.getBirthRecord().setState(incoming.getBirthRecord().getState());

					((Name)idmServiceVO.getNames().iterator().next()).setSuffix(((Name)incoming.getNames().iterator().next()).getSuffix());
					vpid = this.getPersonService().addPerson(idmServiceVO);

					onFile = this.convertIdmServiceVOToPerson(idmServiceVO, vpid);

					// get the ESR person's personKey:
			        PersonEntityKey personKey = getPersonService().getPersonIdByVPID(vpid);
			        if (personKey == null) {
			        	throw new ServiceException("Unable to getPerson Id by vpid added by idmService: " + vpid.getKeyValueAsString());

			        }
			        onFile.setIdentifier(personKey.getKeyValue());
				}
			} catch (Exception ex) {
				throw new ServiceException ("Failed to Add Person to MVI:" + ex.getMessage());
			}


		} else { //not anonymous, retrieve by FQID and fail it if not found

			try {
				List correlations = this.getIdmServiceDelegate().getCorrelationsByFullyQualifiedIdentifier(app.getFullQualifiedId());
				// Person Not found
				if (correlations == null || correlations.size() == 0) {
					throw new ServiceException("No Record Found from MVI with FQID: " + app.getFullQualifiedId());
				}

				String longVpid = VPIDEntityKeyImpl.getLongVPID(getICN(correlations));
				gov.va.med.esr.common.model.person.id.VPIDEntityKey internalVpid = CommonEntityKeyFactory.createVPIDEntityKey(longVpid);
				onFile = this.getPersonService().getPersonWithCompositeCall(internalVpid);

				if (onFile != null && onFile.getIdentityTraits() != null && onFile.getIdentityTraits().has200ESRCorrelation().equalsIgnoreCase("N")) {
					getPersonService().addESRCorrelation(onFile);
				}

			} catch (Exception ex) {
				throw new ServiceException ("Unknown Failure to Retrieve Person by FQID");
			}
		}

		//at this point we cannot continue if no onFile person
		if (onFile == null) {
			throw new ServiceException ("Unknown Failure to Build Person from VOA Submission");
		}

		//if onFile person is deceased, do not continue and open work item
		boolean isDeceased = false;
		if (onFile.getEnrollmentDetermination() != null && onFile.getEnrollmentDetermination().getEnrollmentStatus() != null) {

	        String statusCd = onFile.getEnrollmentDetermination().getEnrollmentStatus().getCode();

	        isDeceased = EnrollmentStatus.CODE_DECEASED.getCode().equals(statusCd);
        }

		if (isDeceased) {
			openCase(onFile);

			throw new ServiceException ("Application not processed for on file Deceased Person. Work case created.");
		}


		//set the traits and keys with the person added or found
		incoming.setIdentityTraits(onFile.getIdentityTraits());
		incoming.setIdentifier(onFile.getPersonEntityKey().getKeyValue());

		//create workflow item if radiation exposure is true
		processRadiationExposure(incoming, onFile);

		//create WI if AOE
		processAOE(incoming, onFile);

		//create WI for CL-V
		processCLV(incoming, onFile);

		//create WI for SHAD
		processSHAD(incoming, onFile);

		//create WI for NTR
		processNTR(incoming, onFile);

		//create WI for SW Asia
		processSWAsia(incoming, onFile);

		//create WI for disability
		processDisabilityInd(incoming, onFile);

		//create WI for purple heart
		processPH(incoming, onFile);

		//create WI for POW
		processPOW(incoming, onFile);

		//create WI for evidence
		processAttachments(app, onFile);

		//do not accept military service, overlay with onfile
		incoming.getMilitaryService().removeAllMilitaryServiceSiteRecords();

		//remove incoming financials if onfile is not subject to MT
		boolean removed = removeIncomingFinancials(incoming, onFile);

		//merge incoming test with existing onfile test of same IY if it exists
		if (!removed) mergeOnFileTest(incoming, onFile);



		//overlay phone and email if they don't submit any or it will get removed in the rules

		if (incoming.getPhones() == null || incoming.getPhones().isEmpty()) {
			if (onFile.getPhones() != null && !onFile.getPhones().isEmpty()) {
				this.getMergeRuleService().mergePhone(onFile, incoming);
			}
		}

		if (incoming.getEmails() == null || incoming.getEmails().isEmpty()) {
			if (onFile.getEmails() != null && !onFile.getEmails().isEmpty()) {
				this.getMergeRuleService().mergeEmail(onFile, incoming);
			}
		}

		onFile = null;
		return processCommonVOA(app, incoming, anonymous);

	}

	//if existing person has current onfile test, transfer the dates and any fields not set from the new test and
	//merge the rest of the information
	public void mergeOnFileTest(Person incoming, Person onFile) throws ServiceException {

		Integer incomeYear = getVOAIncomeYear(incoming);

		if (onFile.getIncomeTest(incomeYear) != null && incoming.getIncomeTest(incomeYear) != null &&
     		   Boolean.TRUE.equals(incoming.getIncomeTest(incomeYear).getDiscloseFinancialInformation())) {

	     	if (onFile.getIncomeTest(incomeYear).getEffectiveDate() != null) {
	     		incoming.getIncomeTest(incomeYear).setEffectiveDate(onFile.getIncomeTest(incomeYear).getEffectiveDate());
	     	} else {
	     		incoming.getIncomeTest(incomeYear).setEffectiveDate(new Date());
	     	}

	     	try {
	     		this.getMergeRuleService().mergeFinancialData(incoming, onFile);
			} catch (ServiceException e) {
				throw new ServiceException("Failed to merge on file and incoming current income test data", e);
			}
	  	   	onFile.setInProcessFinancial(incomeYear, null);

		}
	}

	//do not put a test on them if they disclose financials, if they are not subject to a test
	public boolean removeIncomingFinancials(Person incoming, Person onFile) throws ServiceException {

		boolean removed = false;

		if (onFile != null && !this.getFinancialsHelperService().isSubjectToMeansTest(onFile) &&
				!this.getFinancialsHelperService().isPhramacyCoPayApplicable(onFile)) {
			incoming.removeAllFinancialStatements();
			incoming.removeAllIncomeTests();
			removed = true;
		}
		return removed;
	}

	//have to run in separate thread or it will get rolled back when we fail the application for deceased person
	private void openCase(Person onFile) throws ServiceException {

		final Person existing = this.getPersonService().getPerson(onFile.getPersonEntityKey());

		Thread processDeceased = new Thread(){

	        public void run(){
	        	try {

	        		UserCredentials creds = new UserCredentials();
	        		creds.setAnonymous(true);
	        		creds.setLogicalID("VOA event");
	        		try {
						SecurityContextHelper.initSecurityContextOnThread(getLoginManager(), creds);
					} catch (LoginException e) {

					}

	        		workflowService.autoCreateCase(existing, getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
	    					getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()), null,
	    					"VOA Application Not Processed for On File Deceased Person");
				} catch (ServiceException e) {
					logger.error("VOA work item failed for deceased person " + e.getMessage());
				}
	        }
	   };
	   processDeceased.start();
	}

	public LoginManager getLoginManager() {
		if (loginManager == null) {
			loginManager = (LoginManager) SingletonApplicationContext
					.getInstance().getSingletonContext()
					.getBean("edbLoginManager");
		}

		return loginManager;
	}

	@SuppressWarnings("rawtypes")
	private Integer getVOAIncomeYear(Person incoming) {

		 Map incomeTests = incoming.getIncomeTests();
	     Map financialStatements = incoming.getFinancialStatements();
	     Map patientVisitSummaries = incoming.getPatientVisitSummaries();
	     Map beneficiaryTravels = incoming.getBeneficiaryTravels();

		Integer incomeYear = defaultIncomeYear;

        if( MapUtils.isNotEmpty( incomeTests ) ||
            MapUtils.isNotEmpty(financialStatements) ||
            MapUtils.isNotEmpty(patientVisitSummaries) ||
            MapUtils.isNotEmpty(beneficiaryTravels) ) {

           incomeYear =  getIncomeYear(incomeTests, financialStatements, patientVisitSummaries, beneficiaryTravels);

           if (incomeYear != null && incomeYear.intValue() == 0) //empty value can defulat to 0
           {
        	   //VOA forms 1010EZ/R always use previous calendar year
    	      if (MapUtils.isNotEmpty(incomeTests)) {
    	    	  IncomeTest test = incoming.getIncomeTest(incomeYear);
    	    	  test.setIncomeYear(defaultIncomeYear);
    	    	  incoming.setIncomeTest(incomeYear, null); //remove incomeYear 0
    	    	  incoming.setIncomeTest(defaultIncomeYear, test);

    	       } else if (MapUtils.isNotEmpty(financialStatements)) {
    	    	  FinancialStatement stmt = incoming.getFinancialStatement(incomeYear);
    	    	  stmt.setIncomeYear(defaultIncomeYear);
    	    	  incoming.setFinancialStatement(incomeYear, null); //remove incomeYear 0
    	    	  incoming.setFinancialStatement(defaultIncomeYear, stmt);
    	       } else if (MapUtils.isNotEmpty(patientVisitSummaries)) {
    	          ((SiteYear) patientVisitSummaries.keySet().iterator().next()).setYear(defaultIncomeYear);
    	       }
    	       else{
    	          ((SiteYear) beneficiaryTravels.keySet().iterator().next()).setYear(defaultIncomeYear);
    	       }
    	      incomeYear = defaultIncomeYear;
           }
        }

        return incomeYear;
	}

    @SuppressWarnings("rawtypes")
	private Integer getIncomeYear(Map incomeTests, Map financialStatements, Map patientVisitSummaries, Map beneficiaryTravels) {

        Integer incomeYear;
        if (MapUtils.isNotEmpty(incomeTests)) {
           incomeYear = (Integer) incomeTests.keySet().iterator().next();
        }
        else if (MapUtils.isNotEmpty(financialStatements)) {
           incomeYear = (Integer) financialStatements.keySet().iterator().next();
        }
        else if (MapUtils.isNotEmpty(patientVisitSummaries)) {
           incomeYear = ((SiteYear) patientVisitSummaries.keySet().iterator().next()).getYear();
        }
        else{
           incomeYear = ((SiteYear) beneficiaryTravels.keySet().iterator().next()).getYear();
        }
        return incomeYear;
     }


	@SuppressWarnings({ "rawtypes", "unchecked" })
	private Person processCommonVOA(VOAApplication app, Person incoming, boolean isAnonymousLOA1) throws ServiceException {

		VAFacility sendingFacility = VOA_VA_FACILITY;

		VerificationInfo info = new VerificationInfo();
		info.setSiteNumber(sendingFacility.getCode());

		Person result = null;
		try {
			result = this.getMessagingService().processVOA(incoming, sendingFacility, info, isAnonymousLOA1);
		}
		catch (ServiceException ex) {
			//CCR13417: log it with submission id for better resolution
			logger.error("VOA Process submission failed due to exception: (submission id=" +app.getEntityKey().getKeyValueAsString() +"): " + ExceptionUtils.getFullStackTrace(ex));
			throw new ServiceException("Unknown Service Exception in processVOA " + ex.getMessage(), ex);

		} catch (Exception e) {
			logger.error("Unknonw Error in processVOA " + ExceptionUtils.getFullStackTrace(e));
			throw new ServiceException("Unknown Exception in processVOA " + e.getMessage(), e);
		}

		//determination is done, update MVI and do the APTF
		try {
	        if (result != null) {
	        	this.getPersonService().updateProfileForAAP(result);
	        	FullyQualifiedIdentity fqid = this.getPersonService().addPreferredFacilityCorrelation(result);
	        	if (fqid == null) {
	        		throw new Exception("APTF Failed");
	        	}
	        }
        } catch (Exception ex) {
        	logger.error("APTF Failed, retrying for person: " + result.getPersonEntityKey().getKeyValueAsString());
        	int retryTimes = 0;
        	boolean success = false;

	        	try {
	        		while (!success && retryTimes < 3) {
		        		Thread.sleep(10000);
		        		FullyQualifiedIdentity fqid = this.getPersonService().addPreferredFacilityCorrelation(result);
		        		if (fqid == null) {
			        		retryTimes++;
			        	} else {
			        		success = true;
			        	}
	        		}
	        		if (!success) throw new Exception("APTF Fail after three tries");

	        	} catch (Exception e) {

	        		logger.error("MVI update or APTF Failed for Person:" + result.getPersonEntityKey().getKeyValueAsString() + ": " + ExceptionUtils.getFullStackTrace(e));
	        		throw new ServiceException("Failed to Add Facility Correlation to MVI. Manual Resubmission Needed.");
	        	}

        }

		// 4.15. Set VOA Processing Status to "Form Processed Successfully"
		app.setApplicationStatus((VOAApplicationStatus) this.getLookupService().getByCode(VOAApplicationStatus.class, VOAApplicationStatus.FORM_PROCESSED_SUCCESSFUL));
		this.updateVOAApplication(app);

		removeOrphanedVOAApplication(app);

		// SUC141.18 Bulletin Triggers Decision: decision table row #4:
		// A confirmation email is sent to the veteran when their VOA form
		// submission is accepted for EE processing.
		try {

			if (result.getEmails() != null && result.getEmails().size() > 0) {
				final String toList[] = new String[result.getEmails().size()];
				int i = 0;
				for (Iterator it = result.getEmails().iterator(); it.hasNext();) {
					toList[i] = ((Email) it.next()).getAddress();
					i++;
				}

				final CommsEmailBulletinService emailSrv = this.getBulletinService();
				final Map bulletinData = new HashMap();
				bulletinData.put("FirstName", result.getLegalName().getGivenName());
				bulletinData.put("LastName", result.getLegalName().getFamilyName());
				bulletinData.put("PreferredFacility", result.getPreferredFacility().getDescription());
				bulletinData.put("SubmissionTime", app.getCreatedOn());

				//have to do email in separate runnable or any email failure rollsback entire transaction
					Thread processSubmit = new Thread(){
				        public void run(){
				        	try {
								emailSrv.sendEmailBulletinTo(BulletinTrigger.DataType.Initial_Submission_Confirmation, bulletinData, toList);
							} catch (ServiceException e) {
								logger.error("VOA initial submission email failed " + e.getMessage());
							}
				        }
				    };
				    processSubmit.start();
			}
		}

		catch (Throwable e) {
			logger.error("VOA initial submission email failed " + e.getMessage());
		}

		return result;
	}

    @SuppressWarnings("rawtypes")
	private String getICN(List correlations)
    {
    	if (correlations == null || correlations.size() == 0)
    		return null;

    	PatientIdentifier pid = null;

		Iterator it = correlations.iterator();
		while (it.hasNext())
		{
			pid = (PatientIdentifier)it.next();
			if ("200M".equals(pid.getStationNumber()))
				return pid.getIdentity();
		}

		return null;
    }


	@SuppressWarnings("rawtypes")
	public void resubmit(List applicationIds) throws ServiceException {

		// Resubmit VOA Applications
		List voaApps = find(applicationIds);
		for (Iterator i = voaApps.iterator(); i.hasNext();) {
			VOAApplication voaApp = (VOAApplication) i.next();
			resubmitVoaApplication(voaApp);
			}
	}

	/**
	 * Find VOA Applications by ids
	 * optimize to get the cases in bulk query
	 * @param applicationIds
	 * @return
	 * @throws ServiceException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List find(List applicationIds) throws ServiceException {
		List voaApps = new ArrayList();
		try {
			for (Iterator i = applicationIds.iterator(); i.hasNext();) {
	            BigDecimal appId = (BigDecimal) i.next();
	            VOAApplication voaApp = getVoaApplicationDAO().getByApplicationId(appId);
					if (voaApp != null) {
						voaApps.add(voaApp);
					}
				}
		}
		catch (DAOException e) {
			throw new ServiceException("VOA Application retrieval Failed ", e);
		}
		return voaApps;
	}

    /**
     * Get a list of VOAApplications that are available for resubmission
     * @return List of VOAApplications
     * @throws ServiceException
     */
    @SuppressWarnings("rawtypes")
	public List getResubmissionVOAApplications() throws ServiceException {

    	List lst = null;
    	try {
    		lst= this.getVoaApplicationDAO().getVOAResubmissionApplications();

    	} catch (DAOException dex)
    	{
    		throw new ServiceException ("Error getting Resubmission VOA form list", dex);
    	}
    	return lst;
    }

    /**
     * Resubmit a VOAApplication
     * @param app
     * @throws ServiceException
     */
    public void resubmitVoaApplication(VOAApplication voaApp) throws ServiceException
    {
    	Validate.notNull(voaApp, "Resubmission VOAApplication must not be null");
    	Validate.notNull(voaApp.getEntityKey(), "Resubmission VOAApplication id must not be null");
    	Validate.notNull(voaApp.getVOAResubmissionData(), "Resubmission VOAApplication Data must not be null");
    	Validate.notNull(voaApp.getEntityKey(), "Resubmission VOAApplication id must not be null");

    	if (voaApp.getVOAResubmissionData() == null || voaApp.getVOAResubmissionData().getApplicationData() == null)
    		throw new ServiceException("Resubmit VoaApplication failed with empty resubmission data. Submission id = " + voaApp.getEntityKey().getKeyValueAsString());


    	BigDecimal appId = (BigDecimal) voaApp.getEntityKey().getKeyValue();
    	Person person = null;
    	try {
    		person = deserializeXML(voaApp.getVOAResubmissionData().getApplicationData());
    	} catch (SQLException se)
    	{
    		throw new ServiceException("Resubmit VoaApplication failed: can not serialize person object. Submission id = " + voaApp.getEntityKey().getKeyValueAsString(), se);
    	}

    	//update the status of resubmission and null out the serialized data
		voaApp.setApplicationStatus((VOAApplicationStatus) this
				.getLookupService().getByCode(VOAApplicationStatus.class,
						VOAApplicationStatus.FORM_RESUBMITTED));
    	voaApp.getVOAResubmissionData().setApplicationData(null);

		try {
			this.getVoaApplicationDAO().update(voaApp);
			//must flush hibernate to avoid HibernateOptimisticLockingFailureException
			//because the next transaction forwardVOAApplication() is ASYNC and starts a new txn
			this.getVoaApplicationDAO().flush();
		} catch (DAOException ex)
		{
			throw new ServiceException("Update VOA Resubmition failed: ", ex);
		}

    	//start process the voa application ASYNC because ESR UI can submit multiple resubmissions and needs
		//a non-block call to go back to UI quickly
    	//this.forwardVOAApplication(appId, person);
    	//this.processVoaApplication(appId, person

    	final BigDecimal appIdf = appId;
    	final Person personF = person;
		Thread processresubmit = new Thread(){

	        public void run(){


	        		UserCredentials creds = new UserCredentials();
	        		creds.setAnonymous(true);
	        		creds.setLogicalID("VOA event");
	        		try {
						SecurityContextHelper.initSecurityContextOnThread(getLoginManager(), creds);
					} catch (LoginException e) {

					}

	        		reprocessVoaApplication(appIdf, personF);

	        }
	   };
	   processresubmit.start();

    }

	/**
	 * Common search method for retrieving the pending Submissions
	 */
	@SuppressWarnings("rawtypes")
	public List search(SearchQueryInfo searchQueryInfo) throws ServiceException {
			return searchPendingSubmissions(searchQueryInfo);
	}

	@SuppressWarnings({ "rawtypes", "unused" })
	public List searchPendingSubmissions(SearchQueryInfo searchQueryInfo) throws ServiceException {

		List pendingSubmissions = null;
		try {
			VOASearchCriteria searchCriteria = (VOASearchCriteria) searchQueryInfo;
			List applicationIds = null;


			// update search criteria to include ApplicationIds
			if (applicationIds != null && applicationIds.size() > 0)
			{
				searchCriteria.setApplicationIds(applicationIds);
			}

			// Pending Submission Search Results
            pendingSubmissions = getVoaApplicationDAO().find(searchCriteria);

            for ( int i=0; pendingSubmissions!= null && i< pendingSubmissions.size(); i++)
            {
            	VOASearchResultBean voaBean = (VOASearchResultBean) pendingSubmissions.get(i);
             	BigDecimal applicationId = voaBean.getApplicationId();
            }

		}
		catch (DAOException e) {
			throw new ServiceException("Pending Submissions Search Failed", e);
		}
		return pendingSubmissions;
	}

	@SuppressWarnings("rawtypes")
	private void processAttachments(VOAApplication app, Person onFile) throws ServiceException {

		Validate.notNull(onFile.getPersonEntityKey(), "OnFile Person here must have person id not null");

		// update person id
		BigDecimal personId = (BigDecimal)onFile.getPersonEntityKey().getKeyValue();

		app.setPersonId(personId);
		this.updateVOAApplication(app);

		if (app.getFileAttachments() != null && app.getFileAttachments().size() > 0) {
			// CCR 11996 make sure file attachment has person id
			for (Iterator it = app.getFileAttachments().iterator(); it.hasNext();) {
				VoaFileAttachment att = (VoaFileAttachment) it.next();
				att.setPersonId(personId);
			}

			// 5.3.1. SUC2031.15.1 - Attachment Indicator Test For Presence
			// In step [1436] Apply Processing Requirements, if this is an
			// incoming message from the Veteran's Online Application and the
			// Evidence of Attachments is Yes, create an E&E Case as follows:
			// Type: Veteran's Online Application
			// Reason: VOA Attached Evidence Provided by Applicant.
			this.getWorkflowService().autoCreateCase(onFile, getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
					getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()), null,
					"VOA Attached Evidence Provided by Applicant.");
		}
	}

    private void processRadiationExposure(Person incoming, Person onFile) throws ServiceException
    {
        RadiationExposure rexp = incoming.getRadiationExposure();
        RadiationExposure rad = onFile.getRadiationExposure();

        if (rexp != null && rexp.getRadiationExposureIndicator() != null &&
        		Indicator.YES.getCode().equals(rexp.getRadiationExposureIndicator().getCode()))
        {
        	if (rad == null || rad.getRadiationExposureIndicator() == null ||
        			!Indicator.YES.getCode().equals(rad.getRadiationExposureIndicator().getCode())) {
				this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Radiation Exposure Indicated");
        	}

        }

        if (rexp != null) {
        	incoming.removeSpecialFactor(rexp);
        }

        if (rad != null) {
        	RadiationExposure radNew = new RadiationExposure();
            radNew.setExposureMethod(rad.getExposureMethod());
            radNew.setRadiationExposureIndicator(rad.getRadiationExposureIndicator());
            radNew.setExaminationDate(rad.getExaminationDate());
            radNew.setRegistrationDate(rad.getRegistrationDate());
            radNew.setRegistrationNumber(rad.getRegistrationNumber());
            radNew.setRemarks(rad.getRemarks());
            radNew.setSpecialFactorIndicator(rad.getSpecialFactorIndicator());
        	incoming.addSpecialFactor(radNew);
        }
    }

    private void processAOE(Person incoming, Person onFile) throws ServiceException
    {

        AgentOrangeExposure aoe = incoming.getAgentOrangeExposure();
        AgentOrangeExposure rad = onFile.getAgentOrangeExposure();

        if (aoe != null && aoe.getAgentOrangeExposureIndicator() != null &&
        		Indicator.YES.getCode().equals(aoe.getAgentOrangeExposureIndicator().getCode()))
        {
        	if (rad == null || rad.getAgentOrangeExposureIndicator() ==  null ||
        			!Indicator.YES.getCode().equals(rad.getAgentOrangeExposureIndicator().getCode())) {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Agent Orange Exposure Indicated");
        	}
        }



        if (aoe != null) {
        	incoming.removeSpecialFactor(aoe);
        }

        if (rad != null) {
        	AgentOrangeExposure radNew = new AgentOrangeExposure();
            radNew.setLocation(rad.getLocation());
            radNew.setAgentOrangeExposureIndicator(rad.getAgentOrangeExposureIndicator());
            radNew.setExaminationDate(rad.getExaminationDate());
            radNew.setRegistrationDate(rad.getRegistrationDate());
            radNew.setRegistrationNumber(rad.getRegistrationNumber());
            radNew.setRemarks(rad.getRemarks());
            radNew.setSpecialFactorIndicator(rad.getSpecialFactorIndicator());
        	incoming.addSpecialFactor(radNew);
        }
    }

    private void processCLV(Person incoming, Person onFile) throws ServiceException
    {

        CampLejeuneVerification clv = incoming.getCampLejeuneVerification();
        CampLejeuneVerification onfileclv = onFile.getCampLejeuneVerification();

        if (clv != null && clv.getSpecialFactorIndicator() != null &&
        		Indicator.YES.getCode().equals(clv.getSpecialFactorIndicator().getCode()))
        {
        	if (onfileclv == null || onfileclv.getSpecialFactorIndicator() ==  null ||
        			!Indicator.YES.getCode().equals(onfileclv.getSpecialFactorIndicator().getCode())) {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Camp Lejeune Veteran Indicated");

	        	incoming.removeSpecialFactor(clv);
        	}
        }

    }

    private void processSHAD(Person incoming, Person onFile) throws ServiceException
    {

        SHAD shad = incoming.getShad();
        SHAD rad = onFile.getShad();

        if (shad != null && shad.getShadIndicator()!= null &&
        		Indicator.YES.getCode().equals(shad.getShadIndicator().getCode()))
        {
        	if (rad == null || rad.getShadIndicator() ==  null ||
        			!Indicator.YES.getCode().equals(rad.getShadIndicator().getCode())) {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"SHAD Indicated");
        	}
        }

        if (shad != null) {
        	incoming.setShad(null);
        }

        if (rad != null) {
        	SHAD radNew = new SHAD();
            radNew.setClaimNumber(rad.getClaimNumber());
            radNew.setShadIndicator(rad.getShadIndicator());
            radNew.setRegistryTrait(rad.getRegistryTrait());
        	incoming.setShad(radNew);
        }
    }

    private void processNTR(Person incoming, Person onFile) throws ServiceException
    {

        NoseThroatRadium ntr = incoming.getNoseThroatRadium();
        NoseThroatRadium rad = onFile.getNoseThroatRadium();

        if (ntr != null && ntr.getReceivingTreatment().equals(TriState.TRUE))
        {
        	if (rad == null || rad.getReceivingTreatment() ==  null || !rad.getReceivingTreatment().equals(TriState.TRUE)) {

	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"NTR Treatment Indicated");
        	}
        }


        if (ntr != null) {
        	incoming.setNoseThroatRadium(null);
        }

        if (rad != null) {
        	NoseThroatRadium radNew = new NoseThroatRadium();
        	radNew.setReceivingTreatment(rad.getReceivingTreatment());

        	incoming.setNoseThroatRadium(radNew);
        }
    }

    private void processSWAsia(Person incoming, Person onFile) throws ServiceException
    {

        EnvironmentalContaminationExposure ece = incoming.getEnvironmentalContaminationExposure();
        EnvironmentalContaminationExposure rad = onFile.getEnvironmentalContaminationExposure();

        if (ece != null && ece.getEnvironmentalContaminationExposureIndicator()!= null &&
        		Indicator.YES.getCode().equals(ece.getEnvironmentalContaminationExposureIndicator().getCode()))
        {
        	if (rad == null || rad.getEnvironmentalContaminationExposureIndicator() == null || (rad.getEnvironmentalContaminationExposureIndicator() !=  null &&
        			!Indicator.YES.getCode().equals(rad.getEnvironmentalContaminationExposureIndicator().getCode()))) {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Environmental Contaminants Exposure Indicated");
        	}
        }
        //do not accept
        if (ece != null) {
        	incoming.removeSpecialFactor(ece);
        }

        if (rad != null) {
        	EnvironmentalContaminationExposure radNew = new EnvironmentalContaminationExposure();
            radNew.setEnvironmentalContaminationExposureIndicator(rad.getEnvironmentalContaminationExposureIndicator());
            radNew.setExaminationDate(rad.getExaminationDate());
            radNew.setRegistrationDate(rad.getRegistrationDate());
            radNew.setRegistrationNumber(rad.getRegistrationNumber());
            radNew.setRemarks(rad.getRemarks());
            radNew.setSpecialFactorIndicator(rad.getSpecialFactorIndicator());
        	incoming.addSpecialFactor(radNew);
        }
    }

    private void processPH(Person incoming, Person onFile) throws ServiceException
    {

        PurpleHeart ph = incoming.getPurpleHeart();
        PurpleHeart onfileph = onFile.getPurpleHeart();


        if (ph != null && ph.getPhIndicator()!= null &&
        		(ph.getPhIndicator().equals(Boolean.TRUE)))
        {
        	if (onfileph == null || onfileph.getPhIndicator()== null ||
            		(!onfileph.getPhIndicator().equals(Boolean.TRUE)))
            {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Purple Heart Indicated");

	        	incoming.setPurpleHeart(null);
            }
        }

    }

    private void processPOW(Person incoming, Person onFile) throws ServiceException
    {

        PrisonerOfWar pow = incoming.getPrisonerOfWar();
        PrisonerOfWar onFilePow = onFile.getPrisonerOfWar();


        if (pow != null && pow.getPowIndicator()!= null &&
        		(pow.getPowIndicator().toBoolean().equals(Boolean.TRUE)))
        {
        	if (onFilePow == null || onFilePow.getPowIndicator() == null ||
            		(!onFilePow.getPowIndicator().toBoolean().equals(Boolean.TRUE)))
            {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Prisoner Of War Indicated");

	        	incoming.setPrisonerOfWar(null);
            }
        }


    }

    private void processDisabilityInd(Person incoming, Person onFile) throws ServiceException
    {

        if (incoming.getMilitaryService() != null && incoming.getMilitaryService().getDisabilityRetirementIndicator() != null &&
        		incoming.getMilitaryService().getDisabilityRetirementIndicator().equals(Boolean.TRUE))
        {
        	if (onFile == null || onFile.getMilitaryService() == null && onFile.getMilitaryService().getDisabilityRetirementIndicator() == null ||
        			!onFile.getMilitaryService().getDisabilityRetirementIndicator().equals(Boolean.TRUE)) {
        	this.getWorkflowService().autoCreateCase(
					onFile,
					getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
					getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
					null,
					"Military Disability Retirement Indicated");
        	}



        }



        if (incoming.getMilitaryService() != null && incoming.getMilitaryService().getDischargeDueToDisability() != null &&
        		incoming.getMilitaryService().getDischargeDueToDisability().equals(Boolean.TRUE))
        {
        	if (onFile == null || onFile.getMilitaryService() == null || onFile.getMilitaryService().getDischargeDueToDisability() == null ||
        			!onFile.getMilitaryService().getDischargeDueToDisability().equals(Boolean.TRUE)) {
	        	this.getWorkflowService().autoCreateCase(
						onFile,
						getLookupService().getFunctionalGroupByCode(FunctionalGroup.EE.getCode()),
						getLookupService().getWkfCaseTypeByCode(WkfCaseType.CODE_VETERANS_ONLINE_APPLICATION.getCode()),
						null,
						"Discharge Due To Disability Indicated");
        	}




        }

        if (incoming.getMilitaryService() != null) {
        	incoming.getMilitaryService().setDisabilityRetirementIndicator(null);
        	incoming.getMilitaryService().setDischargeDueToDisability(null);
        }

    }


	private Person deserializeXML(String xml) throws SQLException {

		if (xml == null)
			return null;

		return (Person)new XStream().fromXML(xml);
	}


	public Date stringToDate(String string, String dateFormatStr){
		Date date = null;
		try{
			SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatStr);
		    date = dateFormat.parse(string);

		}catch (Exception ex){

			logger.error("Exception @stringToDate  :", ex);
		}
		return  date;
	}

	public void setLoginManager(LoginManager loginManager) {
		this.loginManager = loginManager;
	}

	public FinancialsHelperService getFinancialsHelperService() {
		return financialsHelperService;
	}

	public void setFinancialsHelperService(
			FinancialsHelperService financialsHelperService) {
		this.financialsHelperService = financialsHelperService;
	}

	public void setVOAFormFailed(VOAApplication app, Person incoming)
			throws ServiceException {

		VOAResubmissionData data = app.getVOAResubmissionData();
		if (data == null)
		{
			data = new VOAResubmissionData();
			data.setVoaApplicationId((BigDecimal)app.getEntityKey().getKeyValue());
			app.setVOAResubmissionData(data);
		}

		try {
			data.setApplicationData(this.serializeXML(incoming));
		} catch (SQLException se)
		{
			throw new ServiceException("processVoaApplication failed when setVOAFormPending - unable to serialize Person object. Submission id = " +
					app.getEntityKey().getKeyValueAsString(), se);
		}

		//if (incoming.getEntityKey() != null)
			//app.setPersonId((BigDecimal)incoming.getEntityKey().getKeyValue());

		app.setPersonId(null);

		this.updateVOAApplication(app);

	}

	private String serializeXML(Person p)throws SQLException {
		if (p == null)
			return null;

		return new XStream().toXML(p);
	}

}