package gov.va.med.esr.common.batchprocess;


import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.comms.DeliveryPreference;
import gov.va.med.esr.common.model.comms.DeliveryPreferenceEmail;
import gov.va.med.esr.common.model.comms.HandBookDocument;
import gov.va.med.esr.common.model.comms.HandBookMailQueue;
import gov.va.med.esr.common.model.comms.HandBookMailStatus;
import gov.va.med.esr.common.model.ee.AgentOrangeExposure;
import gov.va.med.esr.common.model.ee.CatastrophicDisability;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.ee.MedalOfHonor;
import gov.va.med.esr.common.model.ee.MilitaryService;
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.ServiceConnectionAward;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.lookup.ComAACRejectReasonType;
import gov.va.med.esr.common.model.lookup.Country;
import gov.va.med.esr.common.model.lookup.DeliveryPreferenceType;
import gov.va.med.esr.common.model.lookup.EnrollmentPriorityGroup;
import gov.va.med.esr.common.model.lookup.HandBookMailStatusType;
import gov.va.med.esr.common.model.lookup.IncomeTestType;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.MonetaryBenefitType;
import gov.va.med.esr.common.model.lookup.MonetaryBenefitType.Code;
import gov.va.med.esr.common.model.lookup.VAFacility;
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.person.Name;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.service.CommsEmailBulletinService;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.esr.service.EligibilityEnrollmentService;
import gov.va.med.esr.service.HandBookService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.PersonHelperService;
import gov.va.med.esr.service.PersonMergeService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.PreferredFacilityService;
import gov.va.med.esr.service.trigger.BulletinTrigger;
import gov.va.med.fw.batchprocess.DataProcessExecutionContext;
import gov.va.med.fw.batchprocess.DataQueryProcessExecutionContext;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.support.AbstractSpawnedThreadTask;
import gov.va.med.fw.util.DateUtils;
import gov.va.med.fw.util.StringUtils;

import java.io.Writer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang.exception.ExceptionUtils;

public class HandbookBatchProcessSpawnedThreadTask extends
	AbstractSpawnedThreadTask{

	private LookupService lookupService;

	private HandBookService handBookService;

	private PreferredFacilityService preferredFacilityService;

	private PersonService personService;

	private PersonHelperService personHelperService;

	private DemographicService demographicService;

	private EligibilityEnrollmentService eligibilityEnrollmentService;

	private CommsEmailBulletinService commsEmailBulletinService;

	private PersonMergeService personMergeService;

	private Object[] acquiredData;

	final private String HANDBOOK_TYPE = "742-400B";

	final private String FORM_HEADER = "FORM=H";

	//static variable that all instances should share one copy
	private static DataQueryProcessExecutionContext context = null;
	private static String processName = null;


	final private String SEP = "^"; //SEPERATOR
	final private String EOL = "\n";
	final private String EMPTY_STRING = "";
	final private String YES = "Y";
	final private String NO = "N";
	final private String Yes_STRING = "Yes";
	final private String No_STRING = "No";
	final private String REJECT_REASON = "Rejected at HEC";
	final private String ERROR_REASON = "Exception during Handbook Batch Process";
	final private String REJECT_ERROR_DURING_PROCESS_CODE = "1";
	final private String REJECT_ERROR_DEPRECATED_PERSON_CODE = "7";


	/*
	 * (non-Javadoc)
	 *
	 * @see gov.va.med.fw.service.support.SpawnedThreadTask#execute()
	 */
	public void executeTask() throws Throwable {

		BigDecimal personId = (BigDecimal) acquiredData[0];
		String mailingId = (String) acquiredData[1];
		String formNumber = (String) acquiredData[2];

		Person person = null;
		HandBookMailQueue mailQ= null;

		Writer extractWriter = (Writer) context.getContextData().get(HandbookBatchProcess.EXTRACT_WRITER);
		Writer exceptionWriter = (Writer) context.getContextData().get(HandbookBatchProcess.EXCEPTION_WRITER);

		try {
			//TODO: maybe multi-thread this to increase performance??? Cannot multi-thread the whole thing because the duplicate check.
			// Or a slim-down customized person object???
			//5 threads
			person = personService.getPerson(new PersonIdEntityKeyImpl(personId));

			if (person == null)
				throw new ServiceException("Unable to find Person with personId= "+ personId);

			mailQ = getHandBookService().findHandBookByIdentifier(mailingId);
			if (mailQ == null)
				throw new ServiceException("Unable to find HandBookMailQueue with mailingId= " + mailingId);

			String errorMessages = validateFields(person, mailingId, formNumber);

			//CCR11669 check deprecated person
			boolean deprecated = this.personMergeService.hasDeprecatedRecord((PersonIdEntityKey)person.getEntityKey());
			if (deprecated)
			{
				errorMessages = addDeprecatedMsg(errorMessages);
			}

			//reject at hec for deprecated record
			if (errorMessages != null && errorMessages.length() > 0) {
				updateHandbookRejectEntry(mailQ, errorMessages, deprecated);
				HandbookBatchProcess.stats.updateRejectPerReasonPerformTable(errorMessages, formNumber);
				HandbookBatchProcess.stats.incrementNumberRejected();
				context.getProcessStatistics().incrementNumberOfErrorRecords(); //reject at HEC is consiered an error

				//store error messages for excption file
				String errMsg = REJECT_REASON +" (personId= " + personId + " HandBook Mail Queue Id= " + mailingId +
				" Form Number= " + formNumber + ") Reject Reasons= " + errorMessages;
				context.getExceptionData().add(errMsg );

				synchronized (exceptionWriter) {
					exceptionWriter.write(errMsg + "\n"); //write a record to the extract data file
				}
				return;
			}

			Address mailingAddress = this.getDemographicService().getLetterAddress(person);
			String aLine = produceText(person, mailQ, formNumber, context.getProcessStatistics().getProcessingStartDate(), mailingAddress);
			updateHandbookSuccessEntry(mailQ, person, mailingAddress, aLine);
			sendEmailNotice(person);
			HandbookBatchProcess.stats.addToCountPerFormTable(formNumber);
			HandbookBatchProcess.stats.incrementNumberSent();
			context.getProcessStatistics().incrementNumberOfSuccessfulRecords();

			synchronized (extractWriter) {
				extractWriter.write(aLine); //write a line to the extract data file
			}

		} catch (Exception ex) {
			//ERROR situation
			try {
				//create error messages for the excption file
				//CCR 11409 - Check the root cause exception. If it is null, get the whole exception (ex)  instead.
				String errMsg = ERROR_REASON +" (personId= " + personId + " HandBook Mail Queue Id= " + mailingId +
						" Form Number= " + formNumber + ") ";
				//updateHandbookErrorEntry(mailQ, errMsg); //excption does not consider reject by HEC, jsut update error text
				//CCR 13725
				//reject at hec for unknown exception
				//set reject at hec so status does not get hung up in send to cms, preventing remail
				String errText = errMsg;
				if (errMsg != null && errMsg.length() > 400) errText = errMsg.substring(0, 350);
				updateHandbookRejectEntry(mailQ, errText, false);



				if (ExceptionUtils.getRootCause(ex) == null || ex instanceof java.lang.NullPointerException)
					errMsg+= "Exception = " + ex;
				else
					errMsg+= "Root Cause = " + ExceptionUtils.getRootCause(ex);

				context.getExceptionData().add(errMsg );
				logger.error(errMsg, ex); //errMsg + the ex (with stack trace) in the server log

				//update statistics
				HandbookBatchProcess.stats.incrementNumberWithException();
				HandbookBatchProcess.stats.updateRejectPerReasonPerformTable(ERROR_REASON, formNumber);
				context.getProcessStatistics().incrementNumberOfErrorRecords();

				//write a record to the exception file
				synchronized (exceptionWriter) {
					exceptionWriter.write(errMsg +"\n");
				}


			} catch (ServiceException se)
			{
				//nothing we can do here, log it
				logger.error("Cannot Update Handbook Error While Catch the Application Exception:", se);
			}
        } finally {

			HandbookBatchProcess.adjustTaskCount(
					context, -1);
			Object threadCreator = getThreadCreator(context);
			synchronized (threadCreator) {
				threadCreator.notifyAll();
			}

			/*
			 * force release of context as thay will hold the ThreadPool(->Threads)
			 * this is necessary to GC ThreadPool threads at end
			 */
			//context = null;
		}
	}

	//CCR 11669:
	private String addDeprecatedMsg(String errorMessages)
	{
		return errorMessages != null ? errorMessages + "DEPRECATED PERSON RECORD" + CommsExportStatistics.LINE_BREAK:
			"DEPRECATED PERSON RECORD" + CommsExportStatistics.LINE_BREAK;
	}

	private String validateFields(Person person, String mailingId, String formNumber )throws ServiceException {

		/*		ICD section 2.6.1, title Required Data Elements:
				•	  Form Type
				•	  Release Control Number
				•	  File Creation Date
				•	  New Enrollee Indicator
				•	  Unique Identifier
				•	  Veteran Last Name
				•	  Veteran Gender
				•	  Veteran DOB
				•	  Veteran UID
				•	  Veteran Address Line1
				•	  Veteran City
				•	  Veteran State (if US)
				•	  Veteran Country Code
				•	  Veteran Zip Code (if US)
				•	  Preferred facility for 3.5 and Parent Preferred Facility for 3.6 (at least one)
				•	 Enrollment Priority
				•	 Enrollment Sub priority
		*/


		StringBuffer errorMessage = new StringBuffer();

		if (formNumber == null || formNumber.equals(EMPTY_STRING))
			errorMessage.append("FORM TYPE IS REQUIRED").append(CommsExportStatistics.LINE_BREAK);
		//SKIP- release contral number, file creaation Date will be populate during file generation
		if (!calculateNewEnrolee(person))
			errorMessage.append("NOT ENROLLED").append(CommsExportStatistics.LINE_BREAK);
		if (mailingId == null || mailingId.equals(EMPTY_STRING))
			errorMessage.append("UNIQUE IDENTIFIER IS REQUIRED").append(CommsExportStatistics.LINE_BREAK);
		//Veteran last name, Gender, DOB, UID
		String missingTraits = hasReqIdentityTraitData(person);
		if (missingTraits.length() > 0)
			errorMessage.append("MISSING REQUIRED IDENTITY TRAITS INFO - ").append(missingTraits).append(CommsExportStatistics.LINE_BREAK);
		//Address line 1, city, state (US), country code, zip code (US)
		if (!hasValidAddress(person))
			errorMessage.append("INVALID ADDRESS").append(CommsExportStatistics.LINE_BREAK);
		if (!hasPreferredFacility(person))
			errorMessage.append("NO PREFERRED FACILITY LISTED").append(CommsExportStatistics.LINE_BREAK);

		if (!hasPriority(person))
			errorMessage.append("NO PRIORITY GROUP").append(CommsExportStatistics.LINE_BREAK);

		//these two are not in the ICD, commented out from the orginal 3.5 code
//				if (!hasValidEnrollmentStatus(person))
//					errorMessage.append("INVALID ENROLLMENT STATUS\n");
		if (hasDOD(person))
			errorMessage.append("HAS DATE OF DEATH\n");

		return errorMessage.toString();
	}

	private boolean calculateNewEnrolee(Person person) {
		//Carlos is looking into the need for this
		if (person.getEnrollmentDetermination() == null) {
			return false;
		} else {
			return true;
		}
	}

	private String hasReqIdentityTraitData(Person person) {

//		•	  Veteran Last Name
//		•	  Veteran Gender
//		•	  Veteran DOB
//		•	  Veteran UID

		String msg = EMPTY_STRING;

		if (person == null || person.getIdentityTraits() == null )
			return "person or person traits null";

		if(person.getIdentityTraits().getLegalName() == null ||
				person.getIdentityTraits().getLegalName().getFamilyName() == null ||
				person.getIdentityTraits().getLegalName().getFamilyName().length() == 0) // last name
			msg += "last name | ";
		if (person.getIdentityTraits().getGender() == null) //Gender
			msg += "gender | ";
		if(person.getIdentityTraits().getBirthRecord() == null ||
				person.getIdentityTraits().getBirthRecord().getBirthDate() == null ||
				person.getIdentityTraits().getBirthRecord().getBirthDate().equals(EMPTY_STRING)) //DOB
			msg += "DOB | ";
		if(person.getIdentityTraits().getVpid() == null) //vpid
			msg += "UID";

		return msg;
	}

	private boolean hasValidAddress(Person person) throws ServiceException {

	//		•	  Veteran Address Line1
	//		•	  Veteran City
	//		•	  Veteran State (if US)
	//		•	  Veteran Country Code
	//		•	  Veteran Zip Code (if US)

		Address mailingAddress = this.getDemographicService().getLetterAddress(
				person);
		if (mailingAddress != null &&
			(mailingAddress.getLine1() != null && mailingAddress.getLine1().trim().length() > 0) && //line 1
			(mailingAddress.getCity() != null && mailingAddress.getCity().trim().length() > 0) && //city
			mailingAddress.getCountryObject() != null) //country code
		{
			if (Country.CODE_USA.equals(mailingAddress.getCountryObject().getAlpha3Code()))
				return mailingAddress.getState() != null && mailingAddress.getZipCode() != null; //US address
			else
				return true; //non-US address
		}

		return false;
	}

	private boolean hasPreferredFacility(Person person) throws ServiceException {
		// CCR11408 -- return all the active preferred facilities, and if not found, return the latest inactive PF.
		return !preferredFacilityService.getPreferredFacilitySites(person).isEmpty();
	}

	private boolean hasPriority(Person person) {

		if (person.getEnrollmentDetermination() != null &&
			person.getEnrollmentDetermination().getPriorityGroup() != null) {
			if (person.getEnrollmentDetermination().getPriorityGroup().equals(EnrollmentPriorityGroup.GROUP_7) ||
				person.getEnrollmentDetermination().getPriorityGroup().equals(EnrollmentPriorityGroup.GROUP_8)) {
				if (person.getEnrollmentDetermination().getPrioritySubGroup() != null) {
					return true;
				}
			} else {
				return true;
			}
		}

		return false;

	}

	private boolean hasDOD(Person person) {
		boolean hasDod = false;

		if (person.getDeathRecord() != null) {
			if(person.getDeathRecord().getDeathDate() != null){
				hasDod = true;
			}
		}
		return hasDod;
	}

	/**
	 * Processes data for a particular person
	 * @param key
	 * @param VPID
	 * @throws ServiceException
	 */

	protected String produceText(Person person, HandBookMailQueue mailQ, String formNumber, Date startDt,
			Address mailingAddress)  throws Exception {

		if(logger.isDebugEnabled())
			logger.debug("Entering produceText()...");

		StringBuffer aLine = new StringBuffer(1024); //make it big enough so it does not need to grow dynamically to increase performance


		populateHeader(formNumber, mailQ.getHandBookReleaseControl().getCode(), outputDate(startDt), aLine);
		if(logger.isDebugEnabled())
			logger.debug("Entering populateQ_N01()...");
		populateQ_N01(person, mailQ, formNumber, aLine);

		if(logger.isDebugEnabled())
			logger.debug("Entering populateA_N03()...");
		populateA_N03(person, aLine);

		if(logger.isDebugEnabled())
			logger.debug("Entering populateB_P01()...");
		populateB_P01(person, mailingAddress, aLine);

		if(logger.isDebugEnabled())
			logger.debug("Entering populateE()...");
		populateE(person, aLine);


		if(logger.isDebugEnabled())
			logger.debug("Entering populateF()...");
		populateF(person, aLine);

		if(logger.isDebugEnabled())
			logger.debug("Entering populateG()...");
		populateG(person, aLine);


		if(logger.isDebugEnabled())
			logger.debug("Entering populateM_N05()...");
		populateM_N05(person, startDt, aLine);

		if(logger.isDebugEnabled())
			logger.debug("Leaving produceText()...");

		return aLine.toString();
	}

	private String outputDate(Date incomingDate){
		String date = DateUtils.format(incomingDate,DateUtils.MMDDYYYY);

		return date == null ? EMPTY_STRING : date.replaceAll("/",EMPTY_STRING);

	}

	private void populateHeader(String formNumber, String releaseControlNum, String createDate, StringBuffer aLine) {
		/*
		FORM=H400H^	Beginning – of –New –Form
		001^	Release Control Number
		04042011^	Creation Date

		 */

        String formSuffix = formNumber;
        int index = formNumber.indexOf("-");
        if (index > 0) {
              formSuffix = formNumber.substring(index + 1);
        }
        aLine.append(FORM_HEADER).append(formSuffix).append(SEP)
              .append(releaseControlNum).append(SEP)
              .append(createDate).append(SEP);


	}

	private void populateQ_N01(Person person, HandBookMailQueue mailQ, String formNumber, StringBuffer aLine) throws ServiceException {
		/*
		 * 	Q01=Mail^	Delivery Preference
			Q02=123423459^	Unique ID of Mailing Request
			N01=Yes	New Enrollee Indicator (never before enrolled)

		 */

		aLine.append("Q01=").append(getPreferredFacilityType(person)).append(SEP)
				.append("Q02=").append(mailQ.getId()).append(SEP)
				.append("N01=").append(isNewEnrollee(mailQ, person, formNumber)).append(SEP);
	}

	private void populateA_N03(Person person, StringBuffer aLine) throws ServiceException {
		/*
		 * 	A00=Mr^	Client -Prefix
			A01=BEASLEY^	Client - Last Name
			A02=JAMES^	Client - First Name
			A03=LEE^	Client Middle Name or  Init.
			A04=R^	Client –Name -Suffix
			A15=2000494810V827364^	Client -UID
			N02=M^	Gender
			N03=04041983^	Date of Birth
		 */

		Name name = person.getIdentityTraits().getLegalName();

		aLine.append("A00=").append(name.getPrefix() == null ? EMPTY_STRING : name.getPrefix()).append(SEP)
				.append("A01=").append(name.getFamilyName()).append(SEP)
				.append("A02=").append(name.getGivenName()).append(SEP)
				.append("A03=").append(name.getMiddleName() == null ? EMPTY_STRING : name.getMiddleName()).append(SEP)
				.append("A04=").append(name.getSuffix() == null ? EMPTY_STRING : name.getSuffix()).append(SEP)
				.append("A15=").append(person.getIdentityTraits().getVpid().getShortVPID()).append(SEP)
				.append("N02=").append(person.getIdentityTraits().getGender().getCode()).append(SEP)
				.append("N03=").append(outputDate(ImpreciseDateUtils.getDateWithDefault(person.getIdentityTraits().getBirthRecord().getBirthDate()))).append(SEP);
	}

	private void populateB_P01(Person person, Address mailingAddress, StringBuffer aLine) throws ServiceException {
		/*
		 * 	B01=3602 SNOWBIRD LN^	Client Address Line 1
			B02=PO BOX 23^	Client -Address Line 2
			B03=RR #3^	Client -Address Line 3
			B04=CLIFTON PARK^	Client-City
			B05=NY^	Client –State
			B06=USA^	Client - Country Code
			B06=12065-1234^	Client –Zip Code
			B07=8E423X^	Postal Code for foreign address
			B08=SARATOGA^	Client –County
			B09=Quebec^	Province for foreign address
			B10=username@provider.com^	Email Address
			B11=Y^	Bad Address Indicator (if set to Y, a hardcopy will not be printed and mailed to the Veteran even if the delivery preference is “Mail”)
			P01=574|440|553	Parent Preferred Facility
		 */

		aLine.append("B01=").append(mailingAddress.getLine1()).append(SEP)
				.append("B02=").append(mailingAddress.getLine2() == null ? EMPTY_STRING : mailingAddress.getLine2()).append(SEP)
				.append("B03=").append(mailingAddress.getLine3() == null ? EMPTY_STRING : mailingAddress.getLine3()).append(SEP)
				.append("B04=").append(mailingAddress.getCity() == null ? EMPTY_STRING : mailingAddress.getCity()).append(SEP)
				.append("B05=").append(mailingAddress.getState() == null ? EMPTY_STRING : mailingAddress.getState()).append(SEP)
				.append("B06=").append(mailingAddress.getCountryObject().getAlpha3Code()).append(SEP)
				.append("B06=").append(mailingAddress.getZipCode() == null ? EMPTY_STRING : buildZipCode(mailingAddress)).append(SEP)
				.append("B07=").append(mailingAddress.getPostalCode() == null ? EMPTY_STRING : mailingAddress.getPostalCode()).append(SEP)
				.append("B08=").append(mailingAddress.getCounty() == null ? EMPTY_STRING: mailingAddress.getCounty()).append(SEP)
				.append("B09=").append(mailingAddress.getProvince() == null ? EMPTY_STRING : mailingAddress.getProvince()).append(SEP)
				.append("B10=").append(getEmailAddress(person)).append(SEP)
				.append("B11=").append(mailingAddress.getBadAddressReason() == null ? EMPTY_STRING : YES).append(SEP)
				.append("P01=");

		//preferred facility
		// CCR11408 -- return all the active preferred facilities, and if not found, return the latest inactive PF.
		Set preferredFacilitySites = preferredFacilityService.getPreferredFacilitySites(person);

		boolean first = true;
		VAFacility actualPF = null;

		// when there are multiple PF with the same parent there are duplicates.
		// save station number in a set and only write out a particular PF once.
		HashSet stations = new HashSet();
		for (Iterator iter = preferredFacilitySites.iterator(); iter.hasNext();) {

			// CCR11076 -- set parent PF instead of preferred facility
			// CCR11667 -- set preferred facility instead of parent PF
			actualPF = (VAFacility) iter.next();

			String stationNum = actualPF.getStationNumber();
			if (stations.contains(stationNum)) {
				// found a duplicate stationNum so don't write it out
				continue;
			}
			stations.add(stationNum);
			if (first) {
				first = false;
			} else {
				aLine.append("|");
			}
			aLine.append(stationNum);
		}
		aLine.append(SEP);

	}

	private void populateE(Person person, StringBuffer aLine) throws ServiceException
	{
		/*
		 * 	E01=10011999^	Application Date
			E02=10011999^	Enrollment Date
			E03=10011999^	Enrollment End Date
			E04=06301999^	Earliest Effective Date of Change
			E05=06301999^	Most Recent Effective Date of Change
			E06=N^	Enrollment Category
			E07=Rejected; Below Enrollment Group Threshold^	Enrollment Status
			E08=8^	Enrollment Priority
			E09=e^	Enrollment Subpriority
		 */

		aLine.append("E01=").append(getApplicationDate(person)).append(SEP)
				.append("E02=").append(getEnrollmentDate(person)).append(SEP)
				.append("E03=").append(getEnrollmentEndDate(person)).append(SEP)
				.append("E04=").append(earliestChangeEffDate(person)).append(SEP)
				.append("E05=").append(mostRecentEffDateOfChange(person)).append(SEP)
				.append("E06=").append(getEnrollmentCategory(person)).append(SEP)
				.append("E07=").append(getEnrollmentStatus(person)).append(SEP)
				.append("E08=").append(person.getEnrollmentDetermination().getPriorityGroup().getCode()).append(SEP)
				.append("E09=").append(getEnrollmentSubPriority(person)).append(SEP);

	}

	private void populateF(Person person, StringBuffer aLine) throws ServiceException
	{
		/*
		 * 	F01=Y^	Service-Connected?
			F02=0^ 	Service-Connected % (if SC = YES, then SC % must be populated)
			F03=9,999,999.00^	Total Check Amount
			F04=Y^	Unemployable Indicator
			F05=N^	P&T indicator
			F06=N^	VA Pension Indicator
			N06=75,000.00^	Attibutable Income
			F07=N^	Purple Heart Indicator
			F08=Confirmed^	Purple Heart Status
			F09=N^	POW Indicator
			F10=Y^	Medal of Honor Indicator

		 */

		IncomeTest personIncomeTest = getCurrentIncomeTest(person);

		aLine.append("F01=").append(getServiceConnectedIndicator(person)).append(SEP)
				.append("F02=").append(getServiceConnectedPercentage(person)).append(SEP)
				.append("F03=").append(getCheckAmount(person)).append(SEP)
				.append("F04=").append(getUnemployableIndicator(person)).append(SEP)
				.append("F05=").append(getPTIndicator(person)).append(SEP)
				.append("F06=").append(getVAPensionIndicator(person)).append(SEP)
				.append("N06=").append(getAttributableIncome(personIncomeTest)).append(SEP)
				.append("F07=").append(populatePhIndicator(person.getPurpleHeart())).append(SEP)
				.append("F08=").append(
						(person.getPurpleHeart() != null && person.getPurpleHeart().getStatus() != null) ?
						person.getPurpleHeart().getStatus().getDescription() :
						EMPTY_STRING).append(SEP)
				.append("F09=").append(populatePowIndicator(person.getPrisonerOfWar())).append(SEP)
				.append("F10=").append(populateMohIndicator(person.getMedalOfHonor())).append(SEP);

	}

	private void populateG(Person person, StringBuffer aLine) throws ServiceException
	{
		/*
		 * 	G01=Y^	A&A Status
			G02=N^	Housebound Status
			G03=Service Connected Less Than 50%^	Primary Eligibility Code
			G04=GMT Copay Required^	MT Status
			G05=Rx Copay Required^	RX Copay Status
			G06=12102010^	Hardship End Date
			G07=Y^	Medicaid Status
		 */

		IncomeTest personIncomeTest = getCurrentIncomeTest(person);

		aLine.append("G01=").append(getAAStatus(person)).append(SEP)
				.append("G02=").append(getHouseBoundStatus(person)).append(SEP)
				.append("G03=").append(getPrimaryEligCode(person)).append(SEP)
				.append("G04=").append(getMTStatus(personIncomeTest)).append(SEP)
				.append("G05=").append(getRXCopay(personIncomeTest)).append(SEP)
				.append("G06=").append(getHardshipEndDate(personIncomeTest)).append(SEP)
				.append("G07=").append(getMedicaidStatus(person)).append(SEP);

	}

	private void populateM_N05(Person person, Date startDt, StringBuffer aLine) throws ServiceException
	{
		/*
			M01=N^	Combat Veteran Eligibility Status
			M02=10152009^	Combat Veteran Eligibility End Date
			M03=Y^	Discharged due to Disability
			M04=N^	Military Disability Retirement
			M05=N^	Radiation Exposure Indicator
			M06=Atmospheric Nuclear Testing^	Radiation Exposure Method
			M07=N^	Project 112/SHAD Indicator
			M08=Y^	NTR Indicator
			M09=574GA^	NTR Verification Method Station Number
			M10=Medical Records^	NTR Verification Method
			M11=N^	Agent Orange
			M12=Vietnam^	Agent Orange Location
			M13=N^	SW Asia Indicator
			M14=N^	Catastrophically Disabled Indicator
			N05=N^	Receiving VA Disability Compensation
		 */

		MilitaryService ms = person.getMilitaryService();

		if (ms != null) {

			aLine.append("M01=").append(calculateCombatVeteranEligStatus(ms, startDt)).append(SEP)
					.append("M02=").append(outputDate(ms.getCombatVeteranEligibilityEndDate())).append(SEP)
					.append("M03=").append(getDischargeDueToDisability(ms)).append(SEP)
					.append("M04=").append(getDisabilityRetirement(ms)).append(SEP);
		} else {
			aLine.append("M01=").append(EMPTY_STRING).append(SEP)
					.append("M02=").append(EMPTY_STRING).append(SEP)
					.append("M03=").append(EMPTY_STRING).append(SEP)
					.append("M04=").append(EMPTY_STRING).append(SEP);
		}

		RadiationExposure re = person.getRadiationExposure();
		if (re != null) {
			aLine.append("M05=").append(populateExposureInd(re)).append(SEP)
					.append("M06=").append(populateExposureMethod(re)).append(SEP);
		} else {
			aLine.append("M05=").append(EMPTY_STRING).append(SEP)
					.append("M06=").append(EMPTY_STRING).append(SEP);
		}

		if (person.getShad() != null && person.getShad().getShadIndicator() != null) {
			aLine.append("M07=").append(convertIndicator(person.getShad().getShadIndicator().getCode())).append(SEP);
		} else {
			aLine.append("M07=").append(EMPTY_STRING).append(SEP);
		}

		NoseThroatRadium ntr = person.getNoseThroatRadium();
		if (ntr != null) {
			aLine.append("M08=").append(cancerDiagnose(ntr)).append(SEP)
					.append("M09=").append(ntr.getVerificationFacility() != null ? ntr.getVerificationFacility().getStationNumber() : EMPTY_STRING).append(SEP)
					.append("M10=").append(ntr.getVerificationMethod() != null ? ntr.getVerificationMethod().getDescription() : EMPTY_STRING).append(SEP);
		} else
		{
			aLine.append("M08=").append(EMPTY_STRING).append(SEP)
					.append("M09=").append(EMPTY_STRING).append(SEP)
					.append("M10=").append(EMPTY_STRING).append(SEP);
		}

		AgentOrangeExposure aoe = person.getAgentOrangeExposure();
		if (aoe != null) {
			aLine.append("M11=").append(populateOrangeExposureInd(aoe)).append(SEP)
					.append("M12=").append(populateOrangeExposureMethod(aoe)).append(SEP);

		} else {
			aLine.append("M11=").append(EMPTY_STRING).append(SEP)
					.append("M12=").append(EMPTY_STRING).append(SEP);
		}

		aLine.append("M13=").append(getEnvironementalContaminationExposure(person)).append(SEP);
		aLine.append("M14=").append(person.getCatastrophicDisability() != null ?
								catastrophicallyDisabledInd(person.getCatastrophicDisability()) :
								EMPTY_STRING).append(SEP)

				.append("N05=").append(this.getVADisabilityComp(person)).append(SEP).append(EOL);

	}

	private String isNewEnrollee(HandBookMailQueue mailQ, Person person,
			String formNumber) throws ServiceException {
		if (calculateNewEnrolleeData(mailQ, person, formNumber)) {
			return Yes_STRING;
		}

		return No_STRING;

	}
	private String buildZipCode(Address mailingAddress) {
		String zipCode;
		if (mailingAddress.getZipPlus4() != null) {
			zipCode = mailingAddress.getZipCode() + "-"
					+ mailingAddress.getZipPlus4();
		} else {
			zipCode = mailingAddress.getZipCode();
		}
		return zipCode;

	}

	private String getEmailAddress(Person person) {

		ArrayList emails = new ArrayList(person.getEmails());
		String emailaddress = EMPTY_STRING;
		for (Iterator iterator = emails.iterator(); iterator.hasNext();) {
			Email vemail = (Email) iterator.next();
			emailaddress = vemail.getAddress();
			if (emailaddress != null && StringUtils.isNotEmpty(emailaddress))
				break;
		}
		return emailaddress;

	}
	private boolean calculateNewEnrolleeData(HandBookMailQueue mailQ, Person person,
		String formNumber) throws ServiceException {

	if (!formNumber.equals(HANDBOOK_TYPE)) {

		Date mailQRecordCreatedDate = mailQ.getCreatedOn();

		Date recModifiedDate = person.getEnrollmentDetermination().getModifiedOn();

		if (this.getEligibilityEnrollmentService()
				.getPriorToEnrDetermHistory(person.getEntityKey(),
						mailQRecordCreatedDate, recModifiedDate)) {
			return false;
		}

	} else {
		return false;
	}

	return true;

	}

	private String getCheckAmount(Person person) {

	if (person.getMonetaryBenefitAward() != null
			&& person.getMonetaryBenefitAward().getCheckAmount() != null) {
		return person.getMonetaryBenefitAward().getCheckAmount().toString();
	} else {
		return EMPTY_STRING;
	}

	}

	private String getVAPensionIndicator(Person person) {
	return getMonetaryBenefitIndicator(person,
			MonetaryBenefitType.CODE_VA_PENSION);
	}

	private String getAAStatus(Person person) {
		return getMonetaryBenefitIndicator(person,
			MonetaryBenefitType.CODE_AID_AND_ATTENDANCE);
	}

	private String getHouseBoundStatus(Person person) {
		return getMonetaryBenefitIndicator(person,
			MonetaryBenefitType.CODE_HOUSEBOUND);
	}

	private String getVADisabilityComp(Person person) {
		return getMonetaryBenefitIndicator(person,
			MonetaryBenefitType.CODE_DISABILITY_COMPENSATION);
	}

	private String getMonetaryBenefitIndicator(Person person, Code mbt) {
		String indicator = EMPTY_STRING;
		if (person.getMonetaryBenefitAward() != null
				&& person.getMonetaryBenefitAward().getMonetaryBenefitByType(
						mbt) != null
				&& person.getMonetaryBenefitAward().getMonetaryBenefitByType(
						mbt).getMonetaryBenefitIndicator() != null) {

			if (person.getMonetaryBenefitAward().getMonetaryBenefitByType(mbt)
					.getMonetaryBenefitIndicator().getCode().equals(
							Indicator.NO.getCode())) {
				indicator = NO;
			} else if (person.getMonetaryBenefitAward()
					.getMonetaryBenefitByType(mbt)
					.getMonetaryBenefitIndicator().getCode().equals(
							Indicator.YES.getCode())) {
				indicator = YES;

			}
		}
		return indicator;
	}

	private String getServiceConnectedPercentage(Person person) {


		if (person.getServiceConnectionAward() != null) {
			ServiceConnectionAward award = person.getServiceConnectionAward();
			Integer percentage = (award != null) ? award
					.getServiceConnectedPercentage() : null;
			if (percentage != null) {
				return percentage.toString();
			} else {
				return EMPTY_STRING;
			}
		} else {
			return EMPTY_STRING;
		}

	}

	private String getServiceConnectedIndicator(Person person) {

		if (person.getServiceConnectionAward() != null) {
			ServiceConnectionAward award = person.getServiceConnectionAward();
			if(award.getServiceConnectedIndicator() != null){
				return convertBoolean(award.getServiceConnectedIndicator().booleanValue());
			}
	}

	return EMPTY_STRING;

	}

	private String getPTIndicator(Person person) {

		if (person.getServiceConnectionAward() != null) {
			ServiceConnectionAward award = person.getServiceConnectionAward();
			if(award.getPermanentAndTotal() != null){
				return convertBoolean(award.getPermanentAndTotal().booleanValue());
			}
	}
	return EMPTY_STRING;
	}

	private String getUnemployableIndicator(Person person) {

		if (person.getServiceConnectionAward() != null) {
			ServiceConnectionAward award = person.getServiceConnectionAward();
			if(award.getUnemployable() != null){
				return convertBoolean(award.getUnemployable().booleanValue());
			}
		}
		return EMPTY_STRING;

	}

	private String earliestChangeEffDate(Person person) throws ServiceException {

		//returns an ordered list from earliest to the latest date so get the 1st on the list
		Iterator iter = this.getEligibilityEnrollmentService()
				.getEnrollmentDeterminationHistory(person.getEntityKey())
				.iterator();

		EnrollmentDetermination ed = iter.hasNext() ? (EnrollmentDetermination) iter
				.next()
				: null;

		if (ed != null) {
			return outputDate(ed.getEffectiveDate());
		} else {
			return EMPTY_STRING;
		}

	}

	private IncomeTest getCurrentIncomeTest(Person person) {

		return getPersonHelperService().getCurrentIncomeTest(person);

	}

	private void updateHandbookRejectEntry(HandBookMailQueue mailQ, String errMessage, boolean deprecated) throws ServiceException {
		/* Update status to REJECT_AT_HEC */
		if (mailQ == null) return;
		HandBookMailStatus status = mailQ.getHandBookMailStatus();
		HandBookMailStatusType statusType = this.getLookupService()
			.getHandBookMailingStatusTypeByCode(HandBookMailStatusType.REJECT_AT_HEC.getCode());
		status.setStatusType(statusType);

		//CCR116699
		if (deprecated)
		{
			status.setRejectReasonType(getLookupService().getComAACRejectReasonTypeByCode(REJECT_ERROR_DEPRECATED_PERSON_CODE));
		} else
		{
			status.setRejectReasonType(getLookupService().getComAACRejectReasonTypeByCode(REJECT_ERROR_DURING_PROCESS_CODE));
		}
		status.setErrorText(errMessage);

		try {
		    getHandBookService().saveHandBookMailQueue(mailQ);

			//mergeAacLetterObj(mailingId, stats, true); //3.5 code, not needed anymore?

		} catch (ServiceException se) {

			throw new ServiceException ("Error while updating REJECT_AT_HEC with Handbook Mail Queue Id" + mailQ.getId(), se);
		}

	}

	private void updateHandbookErrorEntry(HandBookMailQueue mailQ, String errMessage) throws ServiceException {
		/* Update error text */
		if (mailQ == null)
			return;

		mailQ.getHandBookMailStatus().setErrorText(errMessage);

		try {
		    getHandBookService().saveHandBookMailQueue(mailQ);

			//mergeAacLetterObj(mailingId, stats, true); //3.5 code, not needed anymore?

		} catch (ServiceException se) {

			throw new ServiceException ("Error while updating REJECT_AT_HEC with Handbook Mail Queue Id" + mailQ.getId(), se);
		}
	}

	private void updateHandbookSuccessEntry(HandBookMailQueue mailQ, Person person, Address mailingAddr, String aLine)
	throws ServiceException {


		//Update status to SENT_TO_CMS

		HandBookMailStatus status = mailQ.getHandBookMailStatus();
		HandBookMailStatusType statusType = this.getLookupService()
			.getHandBookMailingStatusTypeByCode(HandBookMailStatusType.SENT_TO_CMS.getCode());
		status.setStatusType(statusType);

        //CCR11908: populate the CMS_FILE_GENERATED_DATE when status is set “SENT_TO_CMS”.
		//Date today = DateUtils.getCurrentDate();

		//CCR11985: populate the CMS_FILE_GENERATED_DATE with date&time when status is set “SENT_TO_CMS”.
		Date today = DateUtils.getCurrentDateTime();
		status.setCmsFileGeneratedDate(today);

		//CCR 11412: wipe out data in case it is a retry from previous failure
		status.setErrorText(null);
		status.setRejectReasonType(null); //shouldn't have to, but just in case

		//Update Address
		mailQ.setAddressId((BigDecimal)mailingAddr.getEntityKey().getKeyValue());
		//mailQ.setAddress(mailingAddr);

		//Update Document
		HandBookDocument doc = new HandBookDocument();
		doc.setDocumentText(aLine);
		doc.setMailStatus(status);
		status.setDocument(doc);

		try {

			getHandBookService().saveHandBookMailQueue(mailQ);

		} catch (ServiceException se) {
			throw new ServiceException ("Error while updating SENT_TO_CMS with Handbook Mail Queue Id" + mailQ.getId(), se);
		}
	}

	/**
	 * Send email notice to person if his/her preferred delivery preference is
	 * Online.
	 *
	 * @param person
	 */
	private void sendEmailNotice(Person person) throws ServiceException {
		String personId = person.getPersonEntityKey().getKeyValueAsString();

		DeliveryPreference deliveryPreference = handBookService
				.findDeliveryPreferenceByPersonId(personId);
		if (deliveryPreference != null) {
			DeliveryPreferenceType deliveryPreferenceType = deliveryPreference
					.getDeliveryPreferenceType();
			// if delivery preference is Online, send email.
			if (DeliveryPreferenceType.CODE_ONLINE.getCode().equals(
					deliveryPreferenceType.getCode())) {
				Set<DeliveryPreferenceEmail> deliveryPreferenceEmailSet = deliveryPreference
						.getDeliveryPreferenceEmail();
				for (DeliveryPreferenceEmail deliveryPreferenceEmail : deliveryPreferenceEmailSet) {
					String emailAddress = deliveryPreferenceEmail.getAddress();
					commsEmailBulletinService
							.sendEmailBulletin(
									BulletinTrigger.DataType.TRIGGER_HANDBOOK_COMMUNICATION,
									emailAddress);
				}
			}
		}
	}

	private String getPreferredFacilityType(Person person) throws ServiceException {
		String personId = person.getPersonEntityKey().getKeyValueAsString();

		DeliveryPreference deliveryPreference = handBookService
				.findDeliveryPreferenceByPersonId(personId);

		if (deliveryPreference != null && deliveryPreference.getDeliveryPreferenceType() != null) {
			DeliveryPreferenceType deliveryPreferenceType = deliveryPreference
					.getDeliveryPreferenceType();
			// if delivery preference is Online, send email.
			return deliveryPreferenceType.getName();
		}
		else
			return "Mail";
	}


	private String catastrophicallyDisabledInd(CatastrophicDisability cd ){
		if(cd.getCatastrophicallyDisabled() != null){
			return convertBoolean(cd.getCatastrophicallyDisabled().booleanValue());
		}
		else
			return EMPTY_STRING;
	}


	private String cancerDiagnose(NoseThroatRadium ntr){
		if(ntr.getDiagnosedWithCancer() != null){
			return convertBoolean(ntr.getDiagnosedWithCancer().booleanValue());
		}
		else{
			return EMPTY_STRING;
		}
	}



	private String populateExposureInd(RadiationExposure ra) {

		if (ra.getRadiationExposureIndicator() != null) {
			return convertIndicator(ra.getRadiationExposureIndicator().getCode());
		}
		return EMPTY_STRING;
	}

	private String populateExposureMethod(RadiationExposure ra) {

		if (ra.getExposureMethod() != null) {
			return ra.getExposureMethod().getDescription();
		}
		return EMPTY_STRING;
	}




	private String populateOrangeExposureInd(AgentOrangeExposure ao) {

		if (ao.getAgentOrangeExposureIndicator() != null) {
			return convertIndicator(ao.getAgentOrangeExposureIndicator().getCode());
		}
		return EMPTY_STRING;
	}

	private String populateOrangeExposureMethod(AgentOrangeExposure ao) {

		if (ao.getLocation() != null) {
			return ao.getLocation().getDescription();
		}
		return EMPTY_STRING;
	}




	private String getDischargeDueToDisability(MilitaryService incomingMilitaryService) {

		if(incomingMilitaryService.getDischargeDueToDisability() != null){
			return convertBoolean(incomingMilitaryService.getDischargeDueToDisability().booleanValue());
		}
		else
			return EMPTY_STRING;
	}

	private String getDisabilityRetirement(
			MilitaryService incomingMilitaryService) {

		if (incomingMilitaryService.getDisabilityRetirementIndicator() != null) {
			return convertBoolean(incomingMilitaryService.getDisabilityRetirementIndicator().booleanValue());
		} else
			return EMPTY_STRING;
	}

	private String calculateCombatVeteranEligStatus(
			MilitaryService militaryService, Date startDt) {

		if (militaryService.getCombatVeteranEligibilityEndDate() != null) {
			if (startDt.after(militaryService
					.getCombatVeteranEligibilityEndDate())) {
				return NO;
			} else {
				return YES;
			}
		}
		return EMPTY_STRING;
	}


	private String populatePhIndicator(PurpleHeart ph) {

		if(ph != null){
			if (ph.getPhIndicator() != null) {
				return convertBoolean(ph.getPhIndicator().booleanValue());
			}
		}
		return EMPTY_STRING;
	}

	private String populatePowIndicator(PrisonerOfWar pw) {

		return pw != null && pw.getPowIndicator() != null ? convertIndicator(pw.getPowIndicator().getCode()): EMPTY_STRING;
	}

	private String populateMohIndicator(MedalOfHonor moh) {

		return moh != null && moh.getMhIndicator() != null ? convertBoolean(moh.getMhIndicator().booleanValue()) : EMPTY_STRING;
	}



	private String convertIndicator(String code) {
		return code.equals("1") ? YES : NO;
	}

	private String convertBoolean(boolean value) {
		return value ? YES : NO;

	}

	// CCR 11275
	private String getEnvironementalContaminationExposure(Person person) {
		String value = EMPTY_STRING;
		if (person.getEnvironmentalContaminationExposure() != null
				&& person.getEnvironmentalContaminationExposure().getEnvironmentalContaminationExposureIndicator() != null) {
			String indicator =
				person.getEnvironmentalContaminationExposure().getEnvironmentalContaminationExposureIndicator().getCode();
			// The indicator can have the value 0, 1, or UNKNOWN
			if (indicator.equals("0")) {
				value = NO;
			} else if (indicator.equals("1")) {
				value = YES;
			}
		}
		return value;
	}


	private String getEnrollmentSubPriority(Person person){

		if(person.getEnrollmentDetermination().getPrioritySubGroup() != null){
			return person.getEnrollmentDetermination().getPrioritySubGroup().getDescription().toUpperCase();
		}

		return EMPTY_STRING;

	}

	private String getAttributableIncome(IncomeTest currentIncomeTest) throws ServiceException {
		return currentIncomeTest != null ? calculateNetIncome(currentIncomeTest).toString() :EMPTY_STRING;

	}

	private String getMTStatus(IncomeTest currentIncomeTest) {
		// CCR 11267.  If the income test is Co-Pay Exemption Test then return a null.  If the primary income
		// test is Rx copay then a means test is not done so return null.
		// CCR 11411 check null of currentIncomeTest to avoid null pointer exception.
		if (currentIncomeTest == null || currentIncomeTest.getStatus() == null ||
			(currentIncomeTest.getPrimaryTestType() != null && IncomeTestType.CODE_CO_PAY_EXEMPTION_TEST.getCode().equals(currentIncomeTest.getPrimaryTestType().getCode()))
			) {
			return EMPTY_STRING;
		}

		return currentIncomeTest.getStatus().getDescription();

	}

	private String getRXCopay(IncomeTest currentIncomeTest) {
		return currentIncomeTest != null && currentIncomeTest.getPharmacyCoPayStatus() != null ?
					currentIncomeTest.getPharmacyCoPayStatus().getStatus().getDescription():
					EMPTY_STRING;
	}

	private String getHardshipEndDate(IncomeTest currentIncomeTest) {
		return currentIncomeTest != null && currentIncomeTest.getHardship() != null ?
					outputDate(currentIncomeTest.getHardship().getReviewDate()) :
					EMPTY_STRING;
	}

	private String getMedicaidStatus(Person person) {
		return person.getMedicaidFactor() != null && person.getMedicaidFactor().getEligibleForMedicaid().booleanValue() ? YES : NO;

	}

	protected BigDecimal calculateNetIncome(IncomeTest test)
			throws ServiceException {

		if (test != null) {
			BigDecimal netIncome = test.getNetIncome();
			if (netIncome != null) {
				// Hard work already done
				return netIncome;
			} else {
				// Need to calculate on the fly using existing data.
				// Note that HL7 will always follow this path
				// since they don't provide Net Income
				BigDecimal totalIncome = test.getTotalIncome();
				BigDecimal deductableExpenses = test.getDeductibleExpenses();
				if (totalIncome != null && deductableExpenses != null) {
					return isGreaterThan(totalIncome, deductableExpenses) ? totalIncome
							.subtract(deductableExpenses)
							: new BigDecimal(0);
				} else if (totalIncome != null) {
					return totalIncome;
				}
				// For other cases we use default of 0
			}
		}
		return new BigDecimal(0);
	}

	public boolean isGreaterThan(BigDecimal value, BigDecimal lower) {
		boolean compare = false;
		if (value != null && lower != null) {
			compare = value.compareTo(lower) == 1;
		}
		if (logger.isDebugEnabled()) {
			logger.debug(" value: " + value);
			logger.debug(" Lower bound: " + lower);
			logger.debug(" Returned value: " + compare);
		}
		return compare;
	}

	private String getEnrollmentCategory(Person person) {
		if (hasEnrollment(person) &&
			person.getEnrollmentDetermination().getEnrollmentStatus() != null &&
			person.getEnrollmentDetermination().getEnrollmentStatus().getEnrollmentCategory() != null) {
				return person.getEnrollmentDetermination()
						.getEnrollmentStatus().getEnrollmentCategory()
						.getCode();
		}

		return EMPTY_STRING;
	}

	private String getEnrollmentStatus(Person person) {
		if (hasEnrollment(person) &&
			person.getEnrollmentDetermination().getEnrollmentStatus() != null) {
				return person.getEnrollmentDetermination()
						.getEnrollmentStatus().getDescription();
		}
		return EMPTY_STRING;

	}

	private String getPrimaryEligCode(Person person) {
		if (hasEnrollment(person) &&
			person.getEnrollmentDetermination().getPrimaryEligibility() != null) {
				return person.getEnrollmentDetermination()
						.getPrimaryEligibility().getType().getDescription();
		}
		return EMPTY_STRING;
	}

	private String getEnrollmentDate(Person person) {
		return hasEnrollment(person) ? outputDate(person.getEnrollmentDetermination().getEnrollmentDate()) : EMPTY_STRING;
	}

	private String getEnrollmentEndDate(Person person) {
		return hasEnrollment(person) ? outputDate(person.getEnrollmentDetermination().getEndDate()) : EMPTY_STRING;
	}

	private String mostRecentEffDateOfChange(Person person) {
		return hasEnrollment(person) ? outputDate(person.getEnrollmentDetermination().getEffectiveDate()) :EMPTY_STRING;
	}

	private boolean hasEnrollment(Person person) {
		return person.getEnrollmentDetermination() != null ? true : false;
	}

	private String getApplicationDate(Person person) {
		if (person.getApplication() != null) {
			return outputDate(person.getApplication().getApplicationDate());

		} else {
			return EMPTY_STRING;
		}

	}

	private Object getThreadCreator(DataProcessExecutionContext context) {
		return context.getContextData().get(HandbookBatchProcess.CONTEXT_THREAD_CREATOR);
	}

	/**
	 * @return Returns the acquiredData.
	 */
	public Object[] getAcquiredData() {
		return acquiredData;
	}

	/**
	 * @param acquiredData
	 *            The acquiredData to set.
	 */
	public void setAcquiredData(Object[] acquiredData) {
		this.acquiredData = acquiredData;
	}


	/**
	 * @return Returns the personService.
	 */
	public PersonService getPersonService() {
		return this.personService;
	}

	/**
	 * @param personService The personService to set.
	 */
	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}

	public EligibilityEnrollmentService getEligibilityEnrollmentService() {
		return eligibilityEnrollmentService;
	}

	public void setEligibilityEnrollmentService(
			EligibilityEnrollmentService eligibilityEnrollmentService) {
		this.eligibilityEnrollmentService = eligibilityEnrollmentService;
	}

	public DemographicService getDemographicService() {
		return demographicService;
	}

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

	public PreferredFacilityService getPreferredFacilityService() {
		return preferredFacilityService;
	}

	public void setPreferredFacilityService(
			PreferredFacilityService preferredFacilityService) {
		this.preferredFacilityService = preferredFacilityService;
	}

	public PersonHelperService getPersonHelperService() {
		return personHelperService;
	}

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

	/**
     * @return Returns the lookupService.
     */
    public LookupService getLookupService() {
        return lookupService;
    }

    /**
     * @param lookupService
     *           The lookupService to set.
     */
    public void setLookupService(LookupService lookupService) {
        this.lookupService = lookupService;
    }

	public HandBookService getHandBookService() {
		return handBookService;
	}

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

	/*
	 * all getter/setter for static variables
	 */
	public DataQueryProcessExecutionContext getContext() {
		return context;
	}

	public void setContext(DataQueryProcessExecutionContext context) {
		this.context = context;
	}

	public String getProcessName() {
		return processName;
	}

	public void setProcessName(String processName) {
		this.processName = processName;
	}

	public CommsEmailBulletinService getCommsEmailBulletinService() {
		return commsEmailBulletinService;
	}

	public void setCommsEmailBulletinService(
			CommsEmailBulletinService commsEmailBulletinService) {
		this.commsEmailBulletinService = commsEmailBulletinService;
	}
	public PersonMergeService getPersonMergeService() {
		return personMergeService;
	}
	public void setPersonMergeService(PersonMergeService personMergeService) {
		this.personMergeService = personMergeService;
	}

}
