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

//Java Classes

import gov.va.med.esr.common.batchprocess.HandBookBatchRequestConsumerProcess;
import gov.va.med.esr.common.batchprocess.HealthBenefitPlanData;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.comms.CommsTemplate;
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.Directory;
import gov.va.med.esr.common.model.comms.Document;
import gov.va.med.esr.common.model.comms.DocumentAccessLog;
import gov.va.med.esr.common.model.comms.DocumentReceipt;
import gov.va.med.esr.common.model.comms.FileInfo;
import gov.va.med.esr.common.model.comms.HandBookBatchRequest;
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.comms.HandbookBatchFileProcessStatistics;
import gov.va.med.esr.common.model.comms.HandbookBatchRequestStatistics;
import gov.va.med.esr.common.model.comms.HealthBenefitPlan;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;
import gov.va.med.esr.common.model.lookup.DeliveryPreferenceSourceOfChange;
import gov.va.med.esr.common.model.lookup.DeliveryPreferenceType;
import gov.va.med.esr.common.model.lookup.DocumentType;
import gov.va.med.esr.common.model.lookup.EmailType;
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.HandBookMailStatusType;
import gov.va.med.esr.common.model.lookup.HandBookReleaseControl;
import gov.va.med.esr.common.model.lookup.HandBookRequestStatusType;
import gov.va.med.esr.common.model.lookup.VeteranIdentifierType;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.DeathRecord;
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.PreferredFacility;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.persistent.comms.CommsTemplateDAO;
import gov.va.med.esr.common.persistent.comms.DeliveryPreferenceDAO;
import gov.va.med.esr.common.persistent.comms.DocumentReceiptDAO;
import gov.va.med.esr.common.persistent.comms.FileInfoDAO;
import gov.va.med.esr.common.persistent.comms.HandBookMailQueueDAO;
import gov.va.med.esr.common.persistent.comms.HandbookBatchFileProcessStatisticsDAO;
import gov.va.med.esr.common.persistent.comms.HandbookBatchRequestDAO;
import gov.va.med.esr.common.persistent.comms.HandbookBatchStatisticsDAO;
import gov.va.med.esr.common.persistent.demographic.AddressDAO;
import gov.va.med.esr.common.persistent.history.HandBookHistoryDAO;
import gov.va.med.esr.common.persistent.history.HistoryDAO;
import gov.va.med.esr.service.CommsLetterRequestService;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.esr.service.DuplicatePrintRequestServiceException;
import gov.va.med.esr.service.HandBookService;
import gov.va.med.esr.service.PersonHelperService;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.esr.service.external.person.DeliveryPreferenceInfo;
import gov.va.med.esr.service.trigger.LetterTrigger;
import gov.va.med.esr.service.trigger.LetterTriggerIdentity;
import gov.va.med.esr.vcg.webservice.generated.GetHandbookRequest;
import gov.va.med.esr.vcg.webservice.generated.GetHandbookResponse;
import gov.va.med.esr.vcg.webservice.generated.HandbookServicePortType;
import gov.va.med.fw.batchprocess.DataFileProcessExecutionContext;
import gov.va.med.fw.batchprocess.HealthBenefitsPlanProcessStatistics;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.model.UserPrincipalImpl;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.security.Principal;
import gov.va.med.fw.security.SecurityContext;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.security.UserPrincipal;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.DateUtils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.Validate;
import org.springframework.util.FileCopyUtils;

/**
 * The Eligibility and Enrollment Service implementation. <p/> Project: Common
 *
 *
 * @version ESR 3.5
 */
public class HandBookServiceImpl extends AbstractHistoricalInfoServiceImpl  implements
HandBookService {


	/**
	 *
	 */
	private static final long serialVersionUID = 1267686755986748702L;

	public static final String DUPE_CHECK_DELIMITER = ":";
	private static Principal USER_SERVICE_DP = new UserPrincipalImpl("Veteran Self Service");

	private DocumentReceiptDAO documentReceiptDao = null;

	private CommsTemplateDAO templDAO = null;
	private HandBookMailQueueDAO mailQueueDAO = null;
	private CommsLetterRequestService letterRequestService = null;
	private PersonHelperService personHelperService = null;
	private HandbookBatchRequestDAO handbookBatchRequestDAO=null;
	private HandbookBatchStatisticsDAO handbookBatchStatisticsDAO=null;
	private HandbookBatchFileProcessStatisticsDAO handbookBatchFileProcessStatisticsDAO=null;
	private HandBookHistoryDAO mailQueueHistoryDAO = null;
	private HistoryDAO addressHistoryDAO = null;
	private AddressDAO addressDAO = null;
    private DemographicService demographicService = null;

	private String environmentName = null;

	private String localVBRLocation;
	private HandBookBatchRequestConsumerProcess processInvoker;
	private DeliveryPreferenceDAO deliveryPreferenceDAO = null;
	private HistoryDAO deliveryPreferenceHistoryDAO = null;

	private CommsTemplate commsTemplate400H = null;

    private FileInfoDAO fileInfoDAO;
    private String vcgWsdlLocation;
    private String vcgWsdlServiceName;
    private String vcgWsdlServiceNamespace;

	/*
	 * (non-Javadoc)
	 *
	 * @see gov.va.med.esr.service.PersonService#getEligibilitySummary(gov.va.med.esr.service.external.person.VPIDEntityKey)
	 */
	public List getHandbookInformation(String vpid) throws ServiceException,
	DAOException {

		List results = getDocumentReceiptDao().findDocumentReceipts(vpid);


		return results;
		// return results.isEmpty() ? null : (DocumentReceipt) results.get(0);
	}

    public FileInfoDAO getFileInfoDAO()
    {
        return fileInfoDAO;
    }

    /**
     * @param genericDAO The genericDAO to set.
     */
    public void setFileInfoDAO(FileInfoDAO fileInfoDAO)
    {
        this.fileInfoDAO = fileInfoDAO;
    }

	/**
	 * Get the list of handbook info sorted by receipt date in descending order
	 *
	 * @param vpid
	 * @return
	 * @throws ServiceException
	 */
	public List getLatestHandbookInformation(String vpid) throws ServiceException,
			DAOException {

		List results = getDocumentReceiptDao().findLatestDocumentReceipts(vpid);

		return results;
	}

	public Directory findActiveVBRDirectory() throws ServiceException {
		try {
			return getDocumentReceiptDao().getActiveVBRDirectoty();
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
	}

	public void saveDocumentReceipt(DocumentReceipt documentReceipt)
	throws ServiceException {
		try {
			getDocumentReceiptDao().saveObject(documentReceipt);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
	}


	public void deleteDocumentReceipt(DocumentReceipt documentReceipt)
	throws ServiceException {
		try {
			getDocumentReceiptDao().deleteDocumentReceipt(documentReceipt);
		} catch (DAOException e) {
			throw new ServiceException(e);

		}
	}

	public String getVBRFileLocation(Directory dir) {
		if ("Local".equals(getEnvironmentName())) {
			// return local folder name.
			return getLocalVBRLocation();
		}
		return dir.getMountPoint().getName() + dir.getName();
	}

	public void processHealthBenefitsPlanRecord(
			HealthBenefitPlanData healthBenefitPlanData, String pdfFileLocation, DataFileProcessExecutionContext context)
	throws ServiceException {

		HealthBenefitsPlanProcessStatistics stats = (HealthBenefitsPlanProcessStatistics)context.getProcessStatistics();

		DocumentType handBookFileType = (DocumentType) getLookupService()
		.getByCode(DocumentType.class,
				DocumentType.CODE_HANDBOOK_BY_CMS .getCode());
		DocumentType benefitsProfileFileType = (DocumentType) getLookupService()
		.getByCode(DocumentType.class,
				DocumentType.CODE_BENEFITS_PROFILE_BY_CMS.getCode());

		List documentReiptList = findDocumentReceipts(healthBenefitPlanData
				.getVpid());
		String receiptNumber = healthBenefitPlanData.getHandbookRequestId();
		Directory currentDirectory = findActiveVBRDirectory();

		String vbrFolderName = getVBRFileLocation(currentDirectory);
		File vbrFolder  = new File(vbrFolderName);
		if ( ! vbrFolder.exists() ) {
			if ( !vbrFolder.mkdirs() ) {
				throw new ServiceException("Unable to Create VBR Folder :" + vbrFolderName);
			}
		}


		DocumentReceipt currentReceipt = null;
		int maxVersion = 0;
		List deleteReceipts = new ArrayList();

		for (int i = 0; i < documentReiptList.size(); i++) {
			DocumentReceipt receipt = (DocumentReceipt) documentReiptList
			.get(i);
			if (receiptNumber.equals(receipt.getReceiptString())) {
				currentReceipt = receipt;
			}
			if (maxVersion < receipt.getVersionNumber()) {
				maxVersion = receipt.getVersionNumber();
			}

			/**
			 * documentReiptList is ordered by version number desc. So we can
			 * delete the older version at the end of the list.
			 */
			if ((i + 1) >= handBookFileType.getVersionsKept()) {
				deleteReceipts.add(receipt);
			}
		}

		int newVersionNumber = maxVersion + 1;
		boolean newDocumentReceipt = false;
		if (currentReceipt == null) {
			newDocumentReceipt = true;
			// get the documentReceipt by documentreceiptNumber. if not
			// found create a new Object.
			currentReceipt = new DocumentReceipt();
			currentReceipt.setReceiptDate(new Date());
			currentReceipt.setReleaseControlNumber(healthBenefitPlanData
					.getReleaseControlNumber());
			currentReceipt.setVPIDValue(healthBenefitPlanData.getVpid());
			currentReceipt.setReceiptString(healthBenefitPlanData
					.getHandbookRequestId());
			currentReceipt.setVersionNumber(newVersionNumber);
			currentReceipt
			.setVeteranIdentifierType((VeteranIdentifierType) getLookupService()
					.getByName(VeteranIdentifierType.class, "VPID"));

			// Create the handbook document.
			Document handBookDoc = new Document();
			handBookDoc.setDocumentType(handBookFileType);
			handBookDoc.setCreationDate(new Date());
			FileInfo handBookFile = new FileInfo();
			handBookFile.setName(healthBenefitPlanData.getVpid()
					+ "_HANDBOOK_V" + newVersionNumber + ".pdf");
			handBookFile.setDirectory(currentDirectory);
			handBookDoc.setFileInfo(handBookFile);
			currentReceipt.addDocument(handBookDoc);

			// Create Benefits Profile document.
			Document benefitsDoc = new Document();
			benefitsDoc.setDocumentType(benefitsProfileFileType);

			FileInfo benefitsFile = new FileInfo();
			benefitsFile.setName(healthBenefitPlanData.getVpid()
					+ "_BENEFITS_PROFILE_V" + newVersionNumber + ".pdf");
			benefitsFile.setDirectory(currentDirectory);
			benefitsDoc.setFileInfo(benefitsFile);
			benefitsDoc.setCreationDate(new Date());
			currentReceipt.addDocument(benefitsDoc);
		}

		HealthBenefitPlan hbPlan = new HealthBenefitPlan();
		hbPlan
		.setHealthBenefitCategory(healthBenefitPlanData
				.getCategoryCode());
		hbPlan.setCoveragePlanCode(healthBenefitPlanData.getCoveragePlanCode());
		hbPlan.setHealthBenefitCode(healthBenefitPlanData
				.getHealthBenefitCode());
		currentReceipt.addHealthBenefitPlan(hbPlan);

		// save the receipt
		saveDocumentReceipt(currentReceipt);

		// Only do this incase of a new documentreceipt record. No need to
		// do this after the first record is processed.
		// 1. Move the pdf files from current location to the VBR folder.
		// 2a. Delete the older versions if they are more than 3 versions
		// old.[from the table]
		// 2b. Delete old version pdf files from the VBR folder.

		// Asp per CCR12154 the following code is commented out--it is vioalting the document_access_log constraint
		// 03/20/2013
		//As per CCR 12155 the comments are removed 3/27/2013

		if (newDocumentReceipt) {
			File handBookfile = new File(pdfFileLocation + "/"
					+ healthBenefitPlanData.getIcn() + "_HB_"
					+ healthBenefitPlanData.getHandbookRequestId() + ".pdf");
			File benefitsProfilefile = new File(pdfFileLocation + "/"
					+ healthBenefitPlanData.getIcn() + "_BP_"
					+ healthBenefitPlanData.getHandbookRequestId() + ".pdf");
			// Destination directory
			File handBookfileAtVBR = new File(
					getVBRFileLocation(currentDirectory) + healthBenefitPlanData.getVpid()
					+ "_HANDBOOK_V" + newVersionNumber + ".pdf");
			File benProfilefileAtVBR = new File(
					getVBRFileLocation(currentDirectory)+ healthBenefitPlanData.getVpid()
					+ "_BENEFITS_PROFILE_V" + newVersionNumber + ".pdf");

			try{
				  if(benefitsProfilefile.exists() && handBookfile.exists()){

					  FileCopyUtils.copy(handBookfile, handBookfileAtVBR);
					  stats.incrementNumHandbooksStored();

					  FileCopyUtils.copy(benefitsProfilefile, benProfilefileAtVBR);
					  stats.incrementNumBenefitsProfilesStored();

					  if (! handBookfile.delete() ) {
						  // just log this information.
						  logger.error("Failed to delete file : " + handBookfile.getPath());
					  }
					  if ( ! benefitsProfilefile.delete() ) {
						  logger.error("Failed to delete file : " + benefitsProfilefile.getPath());
					  }
				  }else{
					  if (! benefitsProfilefile.exists() ) {
						  // The copy will fail and the missing BP file will be recorded into exceptino file.
						  FileCopyUtils.copy(benefitsProfilefile, benProfilefileAtVBR);
					  }

					  if (! handBookfile.exists() ) {
						  // The copy will fail and the missing HP file will be recorded into exceptino file.
						  FileCopyUtils.copy(handBookfile, handBookfileAtVBR);
					  }

				  }
			} catch(IOException ioe) {
				throw new ServiceException(ioe);
			}

// commented out as per CCR 12154
			// comment is removed as per CC12155

			for (int j = 0; deleteReceipts != null && j < deleteReceipts.size(); j++) {
				DocumentReceipt receipt = (DocumentReceipt) deleteReceipts
				.get(j);
				Set delDocs = receipt.getDocuments();
				//CCR 12155
				deleteDocumentReceipt(receipt);

				if (delDocs != null && delDocs.size() > 0) {
					Iterator delDocItr = delDocs.iterator();
					while (delDocItr.hasNext()) {
						Document delDoc = (Document) delDocItr.next();
						FileInfo file = delDoc.getFileInfo();
						File phyFile = null;
						try {

							phyFile = new File(getVBRFileLocation(file
									.getDirectory())
									+ file.getName());
						} catch (Exception e) {
							// do not fail on exception/
						}

						if (phyFile != null && !phyFile.delete()) {
							// may be log and continue....
						}
					}
				}

			}

		}

	}



	public String getEnvironmentName() {
		return environmentName;
	}

	public void setEnvironmentName(String environmentName) {
		this.environmentName = environmentName;
	}

	public String getLocalVBRLocation() {
		return localVBRLocation;
	}

	public void setLocalVBRLocation(String localVBRLocation) {
		this.localVBRLocation = localVBRLocation;
	}



	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull(mailQueueDAO, "dao is required");
		Validate.notNull(letterRequestService, "letterRequestService is required");
		Validate.notNull(personHelperService, "personHelperService is required");
	}


	public DocumentReceiptDAO getDocumentReceiptDao() {
		return documentReceiptDao;
	}

	public void setDocumentReceiptDao(DocumentReceiptDAO documentReceiptDao) {
		this.documentReceiptDao = documentReceiptDao;
	}




	public CommsTemplateDAO getTemplDAO() {
		return templDAO;
	}



	public void setTemplDAO(CommsTemplateDAO templDAO) {
		this.templDAO = templDAO;
	}

	public void recordDocumentAccess(BigDecimal fileId) throws Exception {

		DocumentAccessLog documentAccessLog = new DocumentAccessLog();

		documentAccessLog.setAccessDate(new Date());
		documentAccessLog.setFileId(fileId);
		UserPrincipal principal = getLoggedInUser();
		documentAccessLog.setAccessedBy(principal.getName());
		mailQueueDAO.recordDocumentAccess(documentAccessLog);
	}

	protected UserPrincipal getLoggedInUser() {
		SecurityContext securityContext = SecurityContextHelper.getSecurityContext();
		return (securityContext != null) ? securityContext.getUserPrincipal() : null;
	}



	public HandBookMailQueueDAO getMailQueueDAO() {
		return mailQueueDAO;
	}



	public void setMailQueueDAO(HandBookMailQueueDAO mailQueueDAO) {
		this.mailQueueDAO = mailQueueDAO;
	}


	/**
	 * CCR10960
	 */
	public List findHandbookEntriesByPersonId(String personId) throws ServiceException
	{
		try
		{
			return mailQueueDAO.findHandbookListByPersonId(personId);
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook by Person Id: " + personId, ex);
		}
	}
	public List findAnyHandbookSentOrMailedForPersonId(String personId) throws ServiceException
	{
		try
		{
			return mailQueueDAO.findAnyHandbookSentOrMailedForPersonId(personId);
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook by Person Id: " + personId, ex);
		}
	}


	public List findDeliveryPreferenceEditableStatusByPersonId(String personId) throws ServiceException
	{
		try
		{
			return mailQueueDAO.findDeliveryPreferenceEditableStatusByPersonId(personId);
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook by Person Id: " + personId, ex);
		}
	}
	public List findHandbookEntriesInSendSatusByPersonId(BigDecimal personId, String releaseCtl) throws ServiceException
	{
		try
		{
			HandBookReleaseControl handBookRelaseCtl=this.getHandBookReleaseControl(releaseCtl );
		   return mailQueueDAO.findHandbookSendStatusListByPersonId(personId,handBookRelaseCtl.getIdentifier());
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook by Person Id: " + personId, ex);
		}
	}

	/**
	 * Find a list of handbook entries in SEND_TO_CMS status,
	 * for the person_id provided, and the form template
	 *
	 * @param personId
	 * @param templId
	 * @return
	 * @throws ServiceException
	 */
	public List findHandbookEntriesInSendToCMSByPersonByTemp(Person person, ComLetterTemplateType template) throws ServiceException
	{
		try
		{
			if (person == null)
				return null;

			// get default release control number
			HandBookReleaseControl handBookRelaseCtl = this.getHandBookReleaseControl(null);

			// search for SEND_TO_CMS status
			HandBookMailStatusType sendToCmsType = (HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.SEND_TO_CMS);

			List handBookEntries = this.getMailQueueDAO().findHandBookEntryByPersonByTempOnSendStatus(new BigDecimal(person.getEntityKey().getKeyValueAsString()),template.getIdentifier(),sendToCmsType.getIdentifier(),handBookRelaseCtl.getIdentifier());

			return handBookEntries;
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook entries by Person Id: " + person.getEntityKey().getKeyValueAsString(), ex);
		}

	}


	public List lastHandbookReturnPostOffice(String personId) throws ServiceException
	{
		try
		{
			return mailQueueDAO.lastHandbookReturnPostOffice(personId);
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook by Person Id: " + personId, ex);
		}
	}

	public List getRawProfileData(String vpid, int receipt_id) throws ServiceException
	{
		try
		{
			return mailQueueDAO.getRawProfileData(vpid, receipt_id);
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Raw Profile Data: ", ex);
		}
	}


	public void triggerHandBookPFInsert(String personId) throws ServiceException {

		try {

			List handBookList =this.findHandbookEntriesInSendSatusByPersonId(new BigDecimal(personId),null);

			if (handBookList != null && handBookList.size() > 0) {
				ComLetterTemplateType type = this.getLookupService()
				.getComLetterTemplateTypeByCode(
						ComLetterTemplateType.FORM_NUMBER_400F
						.getCode());
				this.requestHandBook(personId, new LetterTriggerIdentity(type, LetterTrigger.CategoryType.VETERAN_LETTER));
			} else {
				SystemParameterService systemParameterService = (SystemParameterService) this.getComponent("systemParameterService");
				if(systemParameterService.isHandBookRollOutOver()){

				// no handbook is maild before  and rolle out is over so send the handbook400H
				ComLetterTemplateType type = this.getLookupService()
				.getComLetterTemplateTypeByCode(
						ComLetterTemplateType.FORM_NUMBER_400H
						.getCode());

				this.requestHandBook(personId, new LetterTriggerIdentity(type, LetterTrigger.CategoryType.VETERAN_LETTER));
				}
			}
		} catch (Exception e) {
			logger.error(" error in triggerHandBookPFInsert"
					+ e.getStackTrace());
		}

	}

	public CommsLetterRequestService getLetterRequestService() {
		return letterRequestService;
	}

	public void setLetterRequestService(
			CommsLetterRequestService letterRequestService) {
		this.letterRequestService = letterRequestService;
	}

	public List findHandbookTemplate() throws ServiceException
	{
		try
		{
			return mailQueueDAO.findHandbookTemplate();
		}
		catch (Exception ex)
		{
			throw new ServiceException("Failed to find Handbook Template", ex);
		}
	}


	/**
	 * Gets a specific CommsLogEntry based on an entity key.
	 *
	 * @param key
	 *            The key of the CommsLogEntry to retrieve.
	 *
	 * @return The CommsLogEntry based on the specified entity key.
	 * @throws ServiceException
	 *             if any problems were encountered.
	 */
	public HandBookMailQueue getHandbookMailQueueEntry(EntityKey key) throws ServiceException
	{
		try
		{
			return (HandBookMailQueue)mailQueueDAO.getByKey(key);
		}
		catch (DAOException ex)
		{
			throw new ServiceException("Error getting HandbookMailQueue using key: " + key, ex);
		}
	}

	public void updateRemarks(HandBookMailQueue handbookMailQueue) throws ServiceException {
		// kind of a misnomer, since we update the entire record here. but the
		// only field that user should be updating is the
		// remark column.
		try
		{
			mailQueueDAO.saveObject(handbookMailQueue);
		}
		catch (DAOException ex)
		{
			throw new ServiceException("Error updating handbook remarks", ex);
		}

	}

	public List findDocumentReceipts(String vpid) throws ServiceException {
		try {

			return documentReceiptDao.findDocumentReceipts(vpid);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
	}
	public boolean verifyDocumentReceipt(String vpid, String uid) throws ServiceException {
		boolean verified = false;
		try {
			List documentReceiptList = findDocumentReceipts(vpid);
			for (int i = 0; i < documentReceiptList.size(); i++) {
				DocumentReceipt receipt = (DocumentReceipt)documentReceiptList.get(i);
				// logger.debug("uid="+uid+" receipt "+i+"
				// receipt.getReceiptString()="+receipt.getReceiptString());
				BigDecimal UID = new BigDecimal(uid);
				BigDecimal receiptString = new BigDecimal(receipt.getReceiptString());
				// comparing as numbers instead of strings
				if (UID.equals(receiptString)) {
					Set docList = (Set)receipt.getDocuments();
					// look for 2 values means documents are stored
                    if (docList != null && docList.size() == 2) {
					  logger.info("Found verified receipt uid="+uid+" count="+i+" receipt.getReceiptString()="+receipt.getReceiptString());
					  verified = true;
					  break;
                    }
				}
			}
			return verified;

		} catch (NumberFormatException nex) {
			logger.error("fatal error in verifyDocumentReceipt : "+nex.getStackTrace());
			throw new ServiceException("fatal error in verifyDocumentReceipt : ",nex);
		}
	}
	public HandbookBatchRequestDAO getHandbookBatchRequestDAO() {
		return handbookBatchRequestDAO;
	}

	public void setHandbookBatchRequestDAO(
			HandbookBatchRequestDAO handbookBatchRequestDAO) {
		this.handbookBatchRequestDAO = handbookBatchRequestDAO;
	}

	public HandbookBatchStatisticsDAO getHandbookBatchStatisticsDAO() {
		return handbookBatchStatisticsDAO;
	}

	public void setHandbookBatchStatisticsDAO(
			HandbookBatchStatisticsDAO handbookBatchStatisticsDAO) {
		this.handbookBatchStatisticsDAO = handbookBatchStatisticsDAO;
	}

	public void addHandBookBatchRequest(HandBookBatchRequest handBookBatchRequest) throws ServiceException {

		try{
			String batchRequestId=this.getHandbookBatchRequestDAO().insertObject(handBookBatchRequest).getKeyValueAsString();//this.saveHandBookBatchRequest(handBookBatchRequest);
			List acquiredData=new ArrayList();
			if(batchRequestId !=null){
				acquiredData.add(handBookBatchRequest);
				this.getProcessInvoker().processEntityData(null,acquiredData);
			}
		} catch (Exception dex) {
			logger.error(
					"ERROR to insert a new handbookbatch request entry " ,dex);

			throw new ServiceException("Excption when inserting a batch request entry!"
					+ dex.getMessage(), dex);
		}

	}public void saveHandBookBatchRequest(HandBookBatchRequest handBookBatchRequest) throws ServiceException {

		try{
			this.getHandbookBatchRequestDAO().saveObject(handBookBatchRequest);

		} catch (Exception dex) {
			logger.error(
					"ERROR to insert a new handbookbatch request entry " ,dex);

			throw new ServiceException("Excption when inserting a batch request entry!"
					+ dex.getMessage(), dex);
		}

	}

	public List getHandBookBatchRequests() throws ServiceException {
		List batchRequestList=null;
		try {
			batchRequestList= this.getHandbookBatchRequestDAO().getHandBookBatchRequests();
			//CCR12955 - below call is no longer necessary
			//populateMailQueue(batchRequestList);
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:" ,daoEx );
		}
		return batchRequestList;
	}


	public List<HandbookBatchRequestStatistics> getHandbookBatchRequestStatistics(Date releaseDate) throws ServiceException {
		List batchRequestList=null;
		try {
			 batchRequestList = this.getHandbookBatchStatisticsDAO().getHandbookBatchRequestStatistics(releaseDate);
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:" ,daoEx );
		}
		return batchRequestList;
	}

	public List getHandbookBatchFileStatistics(Date startDate) throws ServiceException {

		return getHandbookBatchRequestStatistics(startDate);
	}

	public List<Date> getHandbookBatchFileProcessDateList() throws ServiceException {
		List<Date> hbfDateList=null;
		try {
			hbfDateList = this.getHandbookBatchFileProcessStatisticsDAO().getHandbookBatchFileProcessDateList();
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:" ,daoEx );
		}
		return hbfDateList;

	}

	public HandbookBatchFileProcessStatistics getHandbookBatchFileProcessStatistics(Date selectedDate, Date jobStartDate, Date jobEndDate) throws ServiceException {
		HandbookBatchFileProcessStatistics batchFileProcessStat=null;
		try {
			batchFileProcessStat = this.getHandbookBatchFileProcessStatisticsDAO().getHandbookBatchFileProcessStatistics(selectedDate, jobStartDate, jobEndDate);
		} catch ( DAOException daoEx) {
				throw new ServiceException("DAOException:" ,daoEx );
		}
		return batchFileProcessStat;
	}

	//Get the earlist job start date if there are more than one Handbook Batch File Processes run at the same given day
	public Date getHandbookBatchFileProcessMinJobStartDate(Date selectedDate) throws ServiceException {
		Date minJobStartDate = null;
		try {
			minJobStartDate = this.getHandbookBatchFileProcessStatisticsDAO().getHandbookBatchFileProcessMinJobStartDate(selectedDate);
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:" ,daoEx );
		}
		return minJobStartDate;

	}

	//Get the latest job end date if there are more than one Handbook Batch File Processes run at the same given day
	public Date getHandbookBatchFileProcessMaxJobEndDate(Date selectedDate) throws ServiceException {
		Date maxJobEndDate = null;
		try {
			maxJobEndDate = this.getHandbookBatchFileProcessStatisticsDAO().getHandbookBatchFileProcessMaxJobEndDate(selectedDate);
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:" ,daoEx );
		}
		return maxJobEndDate;

	}


	/**
	 * Returns a list of batch request Ids that are 'NEW' and not future dated.
	 * @return
	 */
	public List getNewHandBookBatchRequestIds() throws ServiceException {
		List newRequestIds=null;
		try {
			newRequestIds= this.getHandbookBatchRequestDAO().getNewHandBookBatchRequestIds();
		} catch ( DAOException daoEx) {
			throw new ServiceException("DAOException:", daoEx );
		}
		return newRequestIds;
	}

	private void pupulateEStRecordCount(List batchRequestList){
		if(batchRequestList !=null && batchRequestList.size()>0){
			for (int i = 0; i < batchRequestList.size(); i++) {
				HandBookBatchRequest batchRequest = (HandBookBatchRequest)batchRequestList.get(i);

				// if in new status and batchReleaseSize is null find out esitmated record count and store it in
				// batch release size. When the batch1 runs it will update this with actual size.
				if(HandBookRequestStatusType.NEW.getCode().equals(batchRequest.getHandBookRequestStatus().getCode()) && batchRequest.getBatchReleaseSize() ==null){
					int estCount=getEstRecordCountForBatch(batchRequest.getEntityKey().getKeyValueAsString());
				batchRequest.setBatchReleaseSize(String.valueOf(estCount));
				}

			}

		}
	}
	private void populateMailQueue(List batchRequestList){

		if(batchRequestList !=null && batchRequestList.size()>0){
			try{
				HandBookMailStatusType mailedCmsType=(HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.MAILED_BY_CMS);
				HandBookMailStatusType sentCmsType=(HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.SENT_TO_CMS);
				HandBookMailStatusType onlineType=(HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.ONLINE);

				for (int i = 0; i < batchRequestList.size(); i++) {
					try{
						HandBookBatchRequest batchRequest = (HandBookBatchRequest)batchRequestList.get(i);
						if(!HandBookRequestStatusType.NEW.getCode().equals(batchRequest.getHandBookRequestStatus().getCode()) &&
								!HandBookRequestStatusType.CANCELLED.getCode().equals(batchRequest.getHandBookRequestStatus().getCode())){
						List mailedCms=this.getMailQueueDAO().getHandBookMailQueueCountByBatchIdByStatus(new BigDecimal(batchRequest.getEntityKey().getKeyValueAsString()), mailedCmsType.getIdentifier());
						int mailedCmsCount=0;
						if (mailedCms !=null){
							mailedCmsCount=((Integer)mailedCms.iterator().next()).intValue();
						}
						batchRequest.setNumberOfRecordMailedByCMS(mailedCmsCount);

						List sentCMS=this.getMailQueueDAO().getHandBookMailQueueCountByBatchIdByStatus(new BigDecimal(batchRequest.getEntityKey().getKeyValueAsString()), sentCmsType.getIdentifier());
						int sentCms=0;
						if (sentCMS !=null){
							sentCms=((Integer)sentCMS.iterator().next()).intValue();
						}
						batchRequest.setNumberOfRecordSendToCMS(sentCms);

						List online=this.getMailQueueDAO().getHandBookMailQueueCountByBatchIdByStatus(new BigDecimal(batchRequest.getEntityKey().getKeyValueAsString()), onlineType.getIdentifier());
						int onlineCnt=0;
						if (online !=null){
							onlineCnt=((Integer)online.iterator().next()).intValue();
						}
						batchRequest.setNumberOfRecordOnline(onlineCnt);

						}
					}catch (Exception dex) {
						logger.error(
								"ERROR to finding count of record in mail queue " ,dex);
					}
				}
			}
			catch (Exception dex) {
				logger.error(
						"ERROR to finding count of record in mail queue",
						dex);
			}

		}

	}
	public void updateBatchRequestEstCountRecord(HandBookBatchRequest batchrequest){
		try{
		int noOfESTREcord=getEstRecordCountForBatch(batchrequest.getEntityKey().getKeyValueAsString());
		batchrequest.setBatchReleaseSize(String.valueOf(noOfESTREcord));
		this.getHandbookBatchRequestDAO().merge(batchrequest);
		}catch (Exception dex) {
			logger.error(
					"ERROR to update a new handbookbatch request release size " ,dex);
		}
	}

	public int getEstRecordCountForBatch(String BatchId){
		int noOfEstRecord=0;
		try{
		 noOfEstRecord=this.handbookBatchRequestDAO.getEstRecordCountForBatch(BatchId);
		}catch (Exception dex) {
			logger.error(
					"ERROR to insert a new handbookbatch request entry " ,dex);
		}
		return noOfEstRecord;

	}
	/**
	 * Gets a specific HandbookBatchRequest based on an entity key.
	 *
	 * @param key
	 *            The key of the HandbookBatchRequest to retrieve.
	 *
	 * @return The HandbookBatchRequest based on the specified entity key.
	 * @throws ServiceException
	 *             if any problems were encountered.
	 */
	public HandBookBatchRequest getHandbookBatchRequestEntry(EntityKey key) throws ServiceException
	{
		try
		{
			return (HandBookBatchRequest)this.getHandbookBatchRequestDAO().getByKey(key);
		}
		catch (DAOException ex)
		{
			throw new ServiceException("Error getting HandbookbatchRequest using key: " + key, ex);
		}
	}
	public void updateHandBookBatchRequestStatus(HandBookBatchRequest handBookBatchRequest,
			HandBookRequestStatusType newStatus) throws ServiceException {
		try
		{
			handBookBatchRequest.setHandBookRequestStatus(newStatus);
			handbookBatchRequestDAO.saveObject(handBookBatchRequest);
		}
		catch (DAOException ex)
		{
			throw new ServiceException("Error updating handbookbatchrequest status " +  ex);
		}
	}

	public void saveHandBookMailQueue(HandBookMailQueue mailQueue) throws ServiceException {

		try{
			this.getMailQueueDAO().saveObject(mailQueue);
		} catch (Exception dex) {
			logger.error(
					"ERROR saving handbookMailQueue entry " ,dex);

			throw new ServiceException("Excption saving a MailQueue entry!"
					+ dex.getMessage(), dex);
		}

	}


	public HandBookHistoryDAO getMailQueueHistoryDAO() {
		return mailQueueHistoryDAO;
	}

	public void setMailQueueHistoryDAO(HandBookHistoryDAO mailQueueHistoryDAO) {
		this.mailQueueHistoryDAO = mailQueueHistoryDAO;
	}

	public List getHandbookMailQueueHistory(BigDecimal key) throws ServiceException {
		try {
			return mailQueueHistoryDAO.getHandBookMailQueueHistory(key);
		} catch (DAOException daoEx) {
			throw new ServiceException("DAOException in getHandbookMailQueueHistory:" , daoEx );
		}
	}

	public List getHandbookMailQueueCommentHistory(BigDecimal key) throws ServiceException {
		try {
			return mailQueueHistoryDAO.getHandBookMailQueueCommentHistory(key);
		} catch (DAOException daoEx) {
			throw new ServiceException("DAOException in getHandbookMailQueueCommentHistory:" , daoEx );
		}
	}

//	public List getDeliveryPreferenceHistory(String personId) throws ServiceException {
//		try {
//			return  deliveryPreferenceHistoryDAO.getDeliveryPreferenceByPersonId(personId);
//
//		} catch (DAOException daoEx) {
//			throw new ServiceException("DAOException in getHandbookMailQueueHistory:" , daoEx );
//		}
//	}
	public List getHandBookMailStatusHistory(BigDecimal key) throws ServiceException {
		try {
			List statusList = mailQueueHistoryDAO.getHandBookMailStatusHistory(key);
			// do a liitle house keeping here...
			// 1) make sure that the records we return each have a different
			// status. In other words, if we saved any
			// records where the status type didn't change then remove the dups.
			// 2) the historyDAO has no knowlege of the HandBookMailStatusType
			// table so all we are going to get back is the foreign key
			// into that table. Load the associated HandBookMailStatusType
			// object at this time
			Iterator iter = statusList.iterator();
			String curStatusId = "";
			while (iter.hasNext()) {
				HandBookMailStatus hbms = (HandBookMailStatus)iter.next();
				if (hbms.getEntityKey().getKeyValueAsString().equals(curStatusId)) {
					iter.remove();
				} else {
					curStatusId = hbms.getEntityKey().getKeyValueAsString();
					// load the associated HandBookMailStatusType object at this
					// time
					EntityKey ek = CommonEntityKeyFactory.createHandBookMailStatusTypeEntityKey(hbms.getStatusTypeId().toString());

					HandBookMailStatusType statusType = (HandBookMailStatusType)mailQueueDAO.getByKey(ek);
					hbms.setStatusType(statusType);
				}
			}
			return mailQueueHistoryDAO.getHandBookMailStatusHistory(key);
		} catch (DAOException daoEx) {
			throw new ServiceException("DAOException in getHandBookMailStatusHistory:" , daoEx );
		}
	}

	public void changeHandbookMailingStatus(HandBookMailQueue handbookMailQueue, HandBookMailStatusType status) throws ServiceException {
		HandBookMailStatus hbms = handbookMailQueue.getHandBookMailStatus();
		hbms.setStatusType(status);
		try
		{
			mailQueueDAO.saveObject(hbms);
		}
		catch (DAOException ex)
		{
			throw new ServiceException("Error calling changeHandbookMailingStatus", ex);
		}
	}

	public HandBookMailQueue  findHandBookByIdentifier(String uid) throws ServiceException  {
		HandBookMailQueue mailQueue = null;
		try {
			BigDecimal UID = new BigDecimal(uid);
			mailQueue = (HandBookMailQueue )mailQueueDAO.findHandBookByIdentifier(UID);
			return mailQueue;
		} catch (DAOException e)  {
			throw new ServiceException(e);
		}
	}
	public List requestHandBook(String personId,	LetterTriggerIdentity letterType) throws ServiceException {

			// no releaseControl  get the default value.
			HandBookReleaseControl handBookReleaseControl=getHandBookReleaseControl(null);
			ComLetterTemplateType formNum = letterType.getDataType();

			if (formNum == null || formNum.getName() == null) {
				ServiceException ex = new ServiceException(
				"Can not send a handBook mail with an empty form number!!!");
				logger.error(
						"Error empty form number while requesting an handBook mail ",
						ex);
				throw ex;
			}
			requestHandBookMail(new BigDecimal(personId),formNum,null,null,handBookReleaseControl.getIdentifier());
			return null;
	}

	private void requestHandBookMail(BigDecimal personId,CommsTemplate templ,
			String remark,String  batchRequestId,
			BigDecimal  releaseCtl) throws ServiceException {

		// check if there is any pending handbook of the same
		// template for that person List
		try {
			HandBookMailStatusType statusType=(HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.SEND_TO_CMS.getCode());

			List handBookEntry=this.getMailQueueDAO().findHandBookEntryByPersonByTempOnSendStatus(personId,new BigDecimal(templ.getEntityKey().getKeyValueAsString()),statusType.getIdentifier(),releaseCtl);
			if(handBookEntry !=null &&handBookEntry.size()>0) {
				throw new DuplicatePrintRequestServiceException("Error there is a pending handbook of the same template for that person "+ personId, null);
			}
		} catch (DAOException dex) {
			throw new ServiceException("ERROR in findHandBookEntryByPersonByTempOnSendStatus for peronsonId = " + personId
					+ dex.getMessage(), dex);
		}
		// create a HandbookMailQueue
		HandBookMailQueue mailEntry = null;

		try {
			mailEntry = this.createMailQueue( personId,  templ,
					batchRequestId, releaseCtl, remark);
			// insert a new mailQueue entry
			mailQueueDAO.insert(mailEntry);
		} catch (Exception dex) {
			logger.error(
					"ERROR to insert a new mail queue entry with status \"Send to CMS\" while requesting an AAC letter",
					dex);
			throw new ServiceException("Excption when inserting a Mail queue entry!"
					+ dex.getMessage(), dex);
		}

	}


	public void requestHandBookMail(BigDecimal personId,ComLetterTemplateType formNum,
			String remark,String  batchRequestId,
			BigDecimal  releaseCtl) throws ServiceException {

		// get CommsTemplate from form number
		String formNumberStr = formNum.getCode();
		CommsTemplate templ = null;
		try {
			templ = (CommsTemplate) this.templDAO.findTemplateListByFormNumber(
					formNumberStr).get(0);

			requestHandBookMail(personId, templ, remark, batchRequestId, releaseCtl);

		} catch (DAOException dex) {
			logger.error("ERROR to find a Comms Template with form number ", dex);
			throw new ServiceException(
					"Exception when find a Comms Template with form number="
					+ formNumberStr + ". Error Message: "
					+ dex.getMessage(), dex);
		}
	}

	public void request400HHandBookMail(BigDecimal personId, String remark,String  batchRequestId,
			BigDecimal  releaseCtl) throws ServiceException {

		requestHandBookMail(personId, getCommsTemplate400H(), remark, batchRequestId, releaseCtl);
	}

	private CommsTemplate getCommsTemplate400H() throws ServiceException {
		if (this.commsTemplate400H == null) {
			String formNumberStr = ComLetterTemplateType.FORM_NUMBER_400H.getCode();
			try {
				this.commsTemplate400H = (CommsTemplate) this.templDAO.findTemplateListByFormNumber(
						formNumberStr).get(0);

			} catch (DAOException dex) {
				logger.error("ERROR to find a Comms Template with form number = "
						+ formNumberStr, dex);
				throw new ServiceException(
						"Excption when find a Comms Template with form number="
						+ formNumberStr + ". Error Message: "
						+ dex.getMessage(), dex);
			}
		}
		return this.commsTemplate400H;
	}

	public HandBookMailQueue  createMailQueue(BigDecimal  personId, CommsTemplate templ, String batchRequestId, BigDecimal releaseCtl,String remark)throws ServiceException{

		HandBookMailQueue mailQueue =new HandBookMailQueue ();

		if(batchRequestId !=null){
			mailQueue.setBatchRequestId(new BigDecimal(batchRequestId));
		}
		mailQueue.setPersonId(personId);
		mailQueue.setTemplate(templ);
		HandBookMailStatus handBookMailStatus=new HandBookMailStatus();
		handBookMailStatus.setHandBookMailQueue(mailQueue);
		try{
			HandBookMailStatusType statusType=(HandBookMailStatusType)this.getLookupService().getByCode(HandBookMailStatusType.class, HandBookMailStatusType.SEND_TO_CMS.getCode());
			handBookMailStatus.setStatusType(statusType);
			handBookMailStatus.setHandBookMailQueue(mailQueue);
		}catch (Exception dex) {
			logger.error(
					"ERROR lookup  HandBookMailStatusType \"Send to CMS\" ",
					dex);
			throw new ServiceException("Excption when lookup class HandBookMailStatusType !"
					+ dex.getMessage(), dex);
		}
		mailQueue.setHandBookMailStatus(handBookMailStatus);
		mailQueue.setReleaseControlId(releaseCtl);
		mailQueue.setActionComment(remark);


		return mailQueue;
	}

	public HistoryDAO getAddressHistoryDAO() {
		return addressHistoryDAO;
	}


	public void setAddressHistoryDAO(HistoryDAO addressHistoryDAO) {
		this.addressHistoryDAO = addressHistoryDAO;
	}

	public Address getHandBookMailingAddress(HandBookMailQueue handBookMailQueue) throws ServiceException {
		// given this HandBookMailQueue object, determine which address was in use at the time it was mailed.
		// default to the address on this object
		Address address = null;
		Address hdbkAddress = null;
		BigDecimal hdbkAddressId = handBookMailQueue.getAddressId();

		if (hdbkAddressId != null) {
			hdbkAddress = getHandbookAddress(handBookMailQueue.getAddressId());
			address = hdbkAddress;

			// get the address as of the date the handbook was generated by CMS
			if (handBookMailQueue.getHandBookMailStatus().getCmsFileGeneratedDate() != null) {
				try {
					PersonEntityKey personKey = CommonEntityKeyFactory.createPersonIdEntityKey(String.valueOf(handBookMailQueue.getPersonId()));
					DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					Timestamp ts = Timestamp.valueOf(df.format(handBookMailQueue.getHandBookMailStatus().getCmsFileGeneratedDate()));
					ChangeEvent ce = new ChangeEvent(ts, personKey);
					Person p = (Person) addressHistoryDAO.getHistoryByChangeTime(ce).getCurrentVersion();

					Iterator iter = p.getAddresses().iterator();
					Address nextAddr = null;

					while(iter.hasNext()) {
						nextAddr = (Address)iter.next();
						if (hdbkAddressId.toString().equals(nextAddr.getEntityKey().getKeyValueAsString())) {
							address = nextAddr;
							break;
						}
					}
				}	catch (Exception ex) {
					// do nothing - use default address
				}
			}
		}
		return address;
	}

	 public void saveHandbookMailStatus(HandBookMailQueue mailQueue, HandBookMailStatusType statusType) throws ServiceException {
			HandBookMailStatus status = mailQueue.getHandBookMailStatus();
			status.setStatusType(statusType);
			try
			{
				mailQueueDAO.saveObject(mailQueue);
			}
			catch (DAOException ex)
			{
				throw new ServiceException("DAOException in updateHandbookMailStatus", ex);
			}
	 }

	 /**
	  * Check to see if it is valid to mail a handbook to this person.  If this method returns an empty list then we can mail the handbook.
	  * If the list is not empty then the strings contained in the list will be the reasons why the handbook cannot be mailed.
	  */
	 public List checkHandbookMailValidation(Person person) throws ServiceException {
		 List errorList = new ArrayList(0);

		 // 1) Is this person Alive?
		 DeathRecord deathRecord = person.getDeathRecord();
		 if (deathRecord != null && deathRecord.getDeathDate() != null) {
			 errorList.add("This individual is deceased");
		 }
		 if (errorList.isEmpty()) {
			 // 2) Is this person enrolled?
			 boolean enrolled = false;
			 try {
				 if (person.getEnrollmentDetermination().getEnrollmentStatus().getCode().equals(EnrollmentStatus.CODE_VERIFIED.getName())) {
					 enrolled = true;
				 }
			 } catch (Exception ex) {
				 // do nothing - no enrolled
			 }
			 if (!enrolled) {
				 errorList.add("This individual is not currently enrolled");
			 }
		 }
		 // 3) check for preferred facility
		 if (errorList.isEmpty()) {
			 if (!hasPreferredFacility(person)) {
				 errorList.add("This individual does not have a preferred facility");
			 }
			 if (!hasPriority(person)) {
				 errorList.add("This individual does not have a enrollment priority");
			 }
		 }

		 if (errorList.isEmpty()) {
			 // 4) has this person already received the current version of the handbook?
			 SystemParameterService systemParameterService = (SystemParameterService) this.getComponent("systemParameterService");
			 String releaseCtl = systemParameterService.getHandBookReleaseCtl();
			 // go through the list of handbook records.  If any is in SENT_TO_CMS or SEND_TO_CMS status then check the associated
			 // release control number.  If the release control number on the handbook record is the same as the most current release number
			 // then this person has already received the handbook.
			 List handbookEntries = findHandbookEntriesByPersonId(person.getPersonEntityKey().getKeyValueAsString());
			 Iterator iter = handbookEntries.iterator();
			 while (iter.hasNext()) {
				 HandBookMailQueue hbmq = (HandBookMailQueue) iter.next();
				 // CCR 13092 republish handbook - allow the handbook to be republished
				 if (hbmq.isSendToCMS()) {
					 // check the release control number
					 if (hbmq.getHandBookReleaseControl().getCode().equals(releaseCtl)) {
						 errorList.add("This individual is already scheduled to received the current handbook");
						 break;
					 }
				 }
			 }
		 }
		 if (errorList.isEmpty()) {
			 // if we get here then we need to check the various fields associate with the person.
			 // 1) Get the address for mailing
			 Address mailingAddress = demographicService.getLetterAddress(person);
			 if (mailingAddress == null) {
				 errorList.add("No mailing address for this individual");
			 } else {
				 if (mailingAddress.getLine1() == null || mailingAddress.getLine1().equals("")) {
					 errorList.add("Bad mailing address: No information for Line 1");
				 }
				 if (mailingAddress.getCity() == null || mailingAddress.getCity().equals("")) {
					 errorList.add("Bad mailing address: No City specified");
				 }
				 if (mailingAddress.isUSAddress()) {
					 if (mailingAddress.getState() == null || mailingAddress.getState().equals("")) {
						 errorList.add("Bad mailing address: No State specified");
					 }
					 if (mailingAddress.getZipCode() == null || mailingAddress.getZipCode().equals("")) {
						 errorList.add("Bad mailing address: No Zip Code specified");
					 }
				 } else {
					 if (mailingAddress.getCountry() == null || mailingAddress.getCountry().equals("")) {
						 errorList.add("Bad mailing address: No Country Code specified");
					 }
				 }
			 }

			 // 2) Check PERSON attributes
			 Name name = person.getLegalName();
			 if (name == null) {
				 errorList.add("No Legal Name for this individual");
			 } else {
				 if (name.getFamilyName() == null || name.getFamilyName().equals("")) {
					 errorList.add("No Last Name specified for this individual");
				 }
			 }

			 BirthRecord birthRecord = person.getBirthRecord();
			 if (birthRecord == null || birthRecord.getBirthDate() == null) {
				 errorList.add("No Date of Birth specified for this individual");
			 }

			 if (person.getGender() == null) {
				 errorList.add("No Gender specified for this individual");
			 }

			 if (person.getVPIDValue() == null || person.getVPIDValue().equals("")) {
				 errorList.add("No VPID specified for this individual");
			 }


		 }

		 return errorList;
	 }


	public DemographicService getDemographicService() {
		return demographicService;
	}


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


	private boolean hasPriority(Person person) {
		boolean validPriority = false;

		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) {
					validPriority = true;
				}
			} else {
				validPriority = true;
			}
		}

		return validPriority;
	}

	private boolean hasPreferredFacility(Person person) {
		boolean hasFacility = false;
		Date currentDate = DateUtils.getCurrentDateTime();

		Set pfList = person.getPreferredFacilities();
		if (pfList != null) {
			for (Iterator iter = pfList.iterator(); iter.hasNext(); ) {
				PreferredFacility pf = (PreferredFacility)iter.next();
				if ((pf.getUnassignmentDate() == null || pf.getUnassignmentDate().after(currentDate))) {
					hasFacility = true;
					break;
				}
			}
		}
		return hasFacility;
	}
	public HandBookReleaseControl getHandBookReleaseControl(String releaseCtl )throws ServiceException{
		HandBookReleaseControl handBookReleaseControl=null;
		try{
			if(releaseCtl ==null){
				// get default value from system parameter.
				SystemParameterService systemParameterService = (SystemParameterService) this.getComponent("systemParameterService");
				releaseCtl=systemParameterService.getHandBookReleaseCtl();
			}
			if(releaseCtl!=null){

					handBookReleaseControl=(HandBookReleaseControl)this.getLookupService().getByCode(HandBookReleaseControl.class, releaseCtl);

				}

		}catch (Exception dex) {
			logger.error("ERROR lookup HandBookReleaseControl ",dex);
			throw new ServiceException("Excption in lookup HandBookReleaseControl !"+ dex.getMessage(), dex);
		}


       return handBookReleaseControl;


	}


	public AddressDAO getAddressDAO() {
		return addressDAO;
	}


	public void setAddressDAO(AddressDAO addressDAO) {
		this.addressDAO = addressDAO;
	}

	public Address getHandbookAddress(BigDecimal addressId) throws ServiceException {
		Address address = null;
		try {
			address = addressDAO.getAddressById(addressId);
		} catch (Exception ex) {
			logger.error("ERROR getHandbookAddress ",ex);
			throw new ServiceException("Exception in getHandbookAddress: "+ ex.getMessage(), ex);
		}
		return address;
	}

	public PersonHelperService getPersonHelperService() {
		return personHelperService;
	}

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

	public String getICNChecksumForVpid(String vpid) {
		return this.personHelperService.getICNChecksum(vpid);
	}

	/**
     * Processes the undeliverable handbook based on a HandbookMailQueue entry
     *
     * @param handbookMailQueue The HandbookMailQueue object to process.
     *
     * @throws ServiceException if any problems were encountered.
     */
    public void processUndeliverableHandbook(HandBookMailQueue handbookMailQueue)
        throws ServiceException
    {
        this.getCommunicationRuleService().handleUndeliverableHandbook(handbookMailQueue);
    }

    /*
     * (non-Javadoc)
     * @see gov.va.med.esr.service.HandBookService#handleMailingResponse(gov.va.med.esr.common.model.comms.HandBookMailQueue)
     */
    public void handleMailingResponse(HandBookMailQueue handbookMailQueue)
    	throws ServiceException
    {
    	this.getCommunicationRuleService().handleHandbookMailingResponse(handbookMailQueue);
    }
    public HandBookBatchRequestConsumerProcess getProcessInvoker() {
		return processInvoker;
	}


	public void setProcessInvoker(HandBookBatchRequestConsumerProcess processInvoker) {
		this.processInvoker = processInvoker;
	}

	public DeliveryPreference findDeliveryPreferenceByPersonId(String personId)
			throws ServiceException {
		try {
			return deliveryPreferenceDAO
					.findDeliveryPreferenceByPersonId(personId);
		} catch (Exception ex) {
			throw new ServiceException(
					"Failed to find delivery preference by Person Id: "
							+ personId, ex);
		}
	}

	public void saveDeliveryPreference(DeliveryPreference deliveryPreference)
			throws ServiceException {
		try {
			deliveryPreferenceDAO.saveObject(deliveryPreference);
		} catch (Exception ex) {
			throw new ServiceException("Failed to update delivery preference.",
					ex);
		}

	}

	public DeliveryPreferenceDAO getDeliveryPreferenceDAO() {
		return deliveryPreferenceDAO;
	}


	public void setDeliveryPreferenceDAO(DeliveryPreferenceDAO deliveryPreferenceDAO) {
		this.deliveryPreferenceDAO = deliveryPreferenceDAO;
	}


	public HistoryDAO getDeliveryPreferenceHistoryDAO() {
		return deliveryPreferenceHistoryDAO;
	}


	public void setDeliveryPreferenceHistoryDAO(
			HistoryDAO deliveryPreferenceHistoryDAO) {
		this.deliveryPreferenceHistoryDAO = deliveryPreferenceHistoryDAO;
	}

    /**
     *
     */
    public HistoricalInfo getDeliveryPreferencesHistoryByChangeTime(ChangeEvent event) throws ServiceException
    {
        try
        {
            return deliveryPreferenceHistoryDAO.getHistoryByChangeTime(event);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /*
      *
      *
      */
    public Set getDeliveryPreferencesChangeTimes(EntityKey personID)
        throws ServiceException
    {
        try
        {
            return deliveryPreferenceHistoryDAO.getHistoryChangeTimes(personID);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    public void buildDeliveryPreference(DeliveryPreferenceInfo info, DeliveryPreference dp) throws ServiceException{

		if(info != null){
			DeliveryPreferenceType dtp = dp.getDeliveryPreferenceType();
	        dtp = (DeliveryPreferenceType)this.getLookupService().getByCode(DeliveryPreferenceType.class, DeliveryPreferenceType.CODE_MAIL.getCode());
			if(info.getDeliveryPreference().equalsIgnoreCase("MAIL")){
				dtp = (DeliveryPreferenceType)this.getLookupService().getByCode(DeliveryPreferenceType.class, DeliveryPreferenceType.CODE_MAIL.getCode());
		         dp.setDeliveryPreferenceType(dtp);
			}
			if(info.getDeliveryPreference().equalsIgnoreCase("ONLINE")){
				dtp = (DeliveryPreferenceType)getLookupService().getByCode(DeliveryPreferenceType.class, DeliveryPreferenceType.CODE_ONLINE.getCode());
				dp.setDeliveryPreferenceType(dtp);
			}
//		Note: In common service, it requires the inputs of the Source of Change, User Name and last update date.
//    	1.	Source of change = “Veteran Self Service”.
//    	2.	User name = “Veteran Self Service”.
//    	3.	Last update date = system time.
		 DeliveryPreferenceSourceOfChange dsc = dp.getSourceOfChange();
		dsc = (DeliveryPreferenceSourceOfChange)this.getLookupService().getByCode(DeliveryPreferenceSourceOfChange.class, DeliveryPreferenceSourceOfChange.CODE_VSS.getCode());
		dp.setSourceOfChange(dsc);
		dp.setModifiedBy(USER_SERVICE_DP);
		dp.setChangeDate(new Date());
		if (info.getEmailAddress() != null) {
			DeliveryPreferenceEmail email = dp.getEmail();
				if(email == null){
					email = new DeliveryPreferenceEmail(); //new email
				}
			email.setAddress(info.getEmailAddress());
			EmailType etp = email.getType();
			if(info.getEmailType().equalsIgnoreCase("BUSINESS")){
			etp = (EmailType)this.getLookupService().getByCode(EmailType.class, EmailType.CODE_BUSINESS.getCode());

				email.setType(etp);
			}
			if(info.getEmailType().equalsIgnoreCase("PRIVATE")){
				etp = (EmailType)this.getLookupService().getByCode(EmailType.class, EmailType.CODE_PRIVATE.getCode());

				email.setType(etp);
			}
		dp.setEmail(email);
		}

		}
	}

    public FileInfo getFileInfoById(BigDecimal id) throws ServiceException
    {
    	try{
    		return this.getFileInfoDAO().getFileInfoById(id);
    	} catch (DAOException ex)
    	{
    		throw new ServiceException(ex);
    	}

    }

	@Override
	public ByteArrayInputStream convertXmlHandBookToPDF(File file) throws ServiceException {
		if(file == null) throw new ServiceException("Illegal Parameter.  Expected to receive an XML file; but no file received.");
		if(!file.getName().endsWith("xml")) throw new ServiceException("Illegal Parameter.  Expected to receive an XML file.");

		try{
			URL url = new URL(getVcgWsdlLocation());
	        QName qname = new QName(getVcgWsdlServiceNamespace(), getVcgWsdlServiceName());

	        Service service = Service.create(url, qname);
	        HandbookServicePortType proxy = service.getPort(HandbookServicePortType.class);
	        GetHandbookRequest request = new GetHandbookRequest();
			byte[] requestPayload = FileUtils.readFileToByteArray(file);
			request.setXmlData(Base64.encodeBase64(requestPayload));
			GetHandbookResponse response = proxy.getHandbook(request);
			byte[] responsePayload = response.getPdfData();
			byte[] decodedResponsePayload = Base64.decodeBase64(responsePayload);
	        ByteArrayInputStream bais = new ByteArrayInputStream(decodedResponsePayload);
	        return bais;
		} catch (Exception e){
			logger.error("PDF version of the Handbook / Benefits At a Glance could not be retrieved from Virtual Content Generator", e);
			throw new ServiceException("PDF version of the Handbook / Benefits At a Glance could not be retrieved from Virtual Content Generator");
		}
	}

	public void saveOnlineDocumentReceipt(DocumentReceipt documentReceipt)
	throws ServiceException {
		try {
			documentReceipt.setReceiptDate(new Date());
			Set doc = documentReceipt.getDocuments();

			if (doc != null) {
				for (Iterator iter = doc.iterator(); iter.hasNext(); ) {
						Document dt = (Document)iter.next();
						dt.setCreationDate(new Date());
				}
			}
			saveDocumentReceipt(documentReceipt);
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}


	public String getVcgWsdlServiceName() {
		return this.vcgWsdlServiceName;
	}

	public void setVcgWsdlServiceName(String vcgWsdlServiceName) {
		this.vcgWsdlServiceName = vcgWsdlServiceName;
	}

	public String getVcgWsdlServiceNamespace() {
		return this.vcgWsdlServiceNamespace;
	}

	public void setVcgWsdlServiceNamespace(String vcgWsdlServiceNamespace) {
		this.vcgWsdlServiceNamespace = vcgWsdlServiceNamespace;
	}

	public String getVcgWsdlLocation() {
		return this.vcgWsdlLocation;
	}

	public void setVcgWsdlLocation(String vcgWsdlLocation) {
		this.vcgWsdlLocation = vcgWsdlLocation;
	}

	public HandbookBatchFileProcessStatisticsDAO getHandbookBatchFileProcessStatisticsDAO() {
		return handbookBatchFileProcessStatisticsDAO;
	}

	public void setHandbookBatchFileProcessStatisticsDAO(
			HandbookBatchFileProcessStatisticsDAO handbookBatchFileProcessStatisticsDAO) {
		this.handbookBatchFileProcessStatisticsDAO = handbookBatchFileProcessStatisticsDAO;
	}
}