/**
 *
 */
package gov.va.med.esr.voa.webservice.impl;

import gov.va.med.esr.common.model.ee.VoaFileAttachment;
import gov.va.med.esr.common.model.ee.VoaFileAttachmentDetail;
import gov.va.med.esr.common.model.ee.VoaFileAttachmentImage;
import gov.va.med.esr.common.model.lookup.DischargeType;
import gov.va.med.esr.common.model.lookup.ServiceBranch;
import gov.va.med.esr.common.model.lookup.VOAApplicationStatus;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.VOAApplication;
import gov.va.med.esr.common.model.person.VOAApplicationData;
import gov.va.med.esr.service.EnvironmentParamService;
import gov.va.med.esr.service.VOAApplicationService;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.esr.voa.validator.FormValidator;
import gov.va.med.esr.voa.webservice.AddressInfo;
import gov.va.med.esr.voa.webservice.AuthenticationLevel;
import gov.va.med.esr.voa.webservice.DemographicInfo;
import gov.va.med.esr.voa.webservice.DependentFinancialsInfo;
import gov.va.med.esr.voa.webservice.DependentInfo;
import gov.va.med.esr.voa.webservice.Document;
import gov.va.med.esr.voa.webservice.EeSummary;
import gov.va.med.esr.voa.webservice.EmailInfo;
import gov.va.med.esr.voa.webservice.ExpenseInfo;
import gov.va.med.esr.voa.webservice.FinancialsInfo;
import gov.va.med.esr.voa.webservice.Form;
import gov.va.med.esr.voa.webservice.IncomeInfo;
import gov.va.med.esr.voa.webservice.InsuranceCollection;
import gov.va.med.esr.voa.webservice.InsuranceInfo;
import gov.va.med.esr.voa.webservice.Message;
import gov.va.med.esr.voa.webservice.MilitaryServiceEpisodeInfo;
import gov.va.med.esr.voa.webservice.MilitaryServiceInfo;
import gov.va.med.esr.voa.webservice.MilitaryServiceSiteRecordInfo;
import gov.va.med.esr.voa.webservice.ObjectFactory;
import gov.va.med.esr.voa.webservice.PersonInfo;
import gov.va.med.esr.voa.webservice.PhoneInfo;
import gov.va.med.esr.voa.webservice.RetrieveFormSubmissionStatusRequest;
import gov.va.med.esr.voa.webservice.RetrieveFormSubmissionStatusResponse;
import gov.va.med.esr.voa.webservice.SpouseFinancialsInfo;
import gov.va.med.esr.voa.webservice.SpouseInfo;
import gov.va.med.esr.voa.webservice.SubmitFormRequest;
import gov.va.med.esr.voa.webservice.SubmitFormResponse;
import gov.va.med.esr.voa.webservice.VeteranIdentifier;
import gov.va.med.esr.voa.webservice.VoaFault;
import gov.va.med.esr.voa.webservice.VoaFaultException;
import gov.va.med.esr.voa.webservice.builder.DemographicsBuilderFactory;
import gov.va.med.esr.voa.webservice.builder.MilitaryServiceBuilderFactory;
import gov.va.med.esr.voa.webservice.builder.impl.BuildHelper;
import gov.va.med.esr.voa.webservice.builder.impl.DemographicsBuilderFactoryImpl;
import gov.va.med.esr.voa.webservice.builder.impl.EnrollmentDeterminationBuilderFactoryImpl;
import gov.va.med.esr.voa.webservice.builder.impl.FinancialsBuilderFactoryImpl;
import gov.va.med.esr.voa.webservice.builder.impl.MilitaryServiceBuilderFactoryImpl;
import gov.va.med.esr.voa.webservice.builder.impl.TypesHelper;
import gov.va.med.fw.security.LoginManager;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.security.UserCredentials;
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.config.SingletonApplicationContext;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.security.auth.login.LoginException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;
import org.jdom2.Element;
import org.jdom2.output.XMLOutputter;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;

/**
 * @author DNS   CHINNR
 *
 */
public class VOAESRServiceImpl extends AbstractComponent implements VOAESRService {

	private VOAApplicationService voaApplicationService = null;
	//An instance of systemParameterService
	private SystemParameterService systemParameterService = null;

	private EnvironmentParamService environmentParamService = null;

	public static final String VOA_MESSAGE_INITIATER = "VOA event";
	private static final String REDIRECT_URL_DEV = "http://DNS  1010ez.webdeve.DNS   /sec/vha/1010ez/submitXML.asp";
	private static final String REDIRECT_URL_PROD = "https://www.1010ez.med.DNS   /sec/vha/1010ez/submitPost.asp";

	private LoginManager loginManager;

	private TypesHelper typesHelper = new TypesHelper();

	private boolean acceptProcessing = false;

	//private static final String FORM_1010EZ = "100";
	private static final String TYPE_21526EZ = "105";
	private static final String VOA_FACILITIES = "VOA_FACILITIES";


	public void saveVOAForm(SubmitFormRequest submitFormRequest,
			SubmitFormResponse response) throws VoaFault {

		try {
			processAuthenticate(VOA_MESSAGE_INITIATER);
		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("VOA Form authentication exception: "
					+ ex.getMessage());
			 }
		}

		String sid = generateSid();
		 boolean accept = false;

		//existing param for anonymous used to flip all to the 1010 redirect without messing with the site list
		try {
			Boolean voaInd = getSystemParameterService().getVOAAnonymousLevel1ProcessIndicator();
			if (voaInd == null || !voaInd.booleanValue()) {


				BigDecimal applicationId = saveApplicationData(submitFormRequest, response, sid);

				//RTC WI 360133
				//Redirect all online submissions to legacy 1010
				this.redirectToLegacy1010(submitFormRequest, applicationId, sid);
				return;
			}
		} catch (Exception ex) {
			logger.error("Exception lookin up VOA Anonymous Indicator",ex);
			return;
		}

		//check site list for facilities we are accepting
		//values are comma delim station numbers, or ALL or NONE
		String[] siteList = null;
		BigDecimal applicationId = saveApplicationData(submitFormRequest, response, null);

		try {
			   siteList = this.getSystemParameterService().getByName(VOA_FACILITIES).getValue().split(",");
		   } catch (Exception ex) {
			   logger.error("Unknown exception retrieving VOA site list parameter during saveVOAForm:" + ex.getMessage());
		   }



		 if (siteList != null) {
			if (siteList[0].trim().equalsIgnoreCase("ALL")) {
				accept = true;
			} else {
				try {
					String facilityNumber = submitFormRequest.getForm().getSummary().getDemographics().getPreferredFacility();

					for (int i = 0; i < siteList.length; i++) {

					   if (siteList[i].trim().equalsIgnoreCase(facilityNumber)) {
						   accept = true;
					   }
				   }
				} catch (Exception ex) {
					logger.error("VOA site list lookup failed:", ex);
					accept = false;
				}

			}
		 }

		 if (!accept) {
			 this.redirectToLegacy1010(submitFormRequest, applicationId, sid);
			 return;
		 }

		 acceptProcessing = accept;

		// validate the form

		if(submitFormRequest.getForm() != null){
			Form submittedForm = submitFormRequest.getForm();
			validate(submittedForm, applicationId);
		}

		//CCR13857 - only for the 526
		if (submitFormRequest.getForm().getFormIdentifier().getType().equalsIgnoreCase(TYPE_21526EZ)) {
			updateApplicationFacility(applicationId, submitFormRequest.getForm().getSummary().getDemographics().getPreferredFacility());
		}

		//update the response time in the table.
		BuildHelper bh = new BuildHelper();
		response.setTimeStamp(bh.getDateJavatoXML(new Date()));

	}

	public void processVOAForm(SubmitFormRequest submitFormRequest, BigInteger applicationId) {

		if (acceptProcessing) {
			try {
				processAuthenticate(VOA_MESSAGE_INITIATER);
			} catch (Exception ex) {
				logger.error("VOA Form authentication exception: "	+ ex.getMessage());
			}

			// convert from to person domain object
			Person person = null;
			try {
				 person = buildPerson(submitFormRequest);
			} catch (Exception ex) {
				updateApplicationFormSubmitStatus(new BigDecimal(applicationId), ex.getMessage(), person);
				return;
			}

			try {
				this.getVoaApplicationService().processVoaApplication(new BigDecimal(applicationId), person);
			}
			catch (Exception e) {
				logger.error("Unknown error in process VOA Application:" + e.getStackTrace());
				updateApplicationFormSubmitStatus(new BigDecimal(applicationId), e.getMessage(), person);

			}
		}

	}

	public void getVOAFormSubmissionStatus(
			RetrieveFormSubmissionStatusRequest retrieveFormSubmissionStatusRequest,
			RetrieveFormSubmissionStatusResponse response) throws VoaFault {
		VOAApplication voaApp = new VOAApplication();
		Message msg = new Message();
		try {
			voaApp = this.getVoaApplicationService()
					.findVoaApplicationByApplicationId(
							new BigDecimal(retrieveFormSubmissionStatusRequest
									.getFormSubmissionId()));
			response.setStatus(voaApp.getApplicationStatus().getCode());
			if (voaApp.getErrorText() != null)
				msg.setDetail(voaApp.getErrorText());
			response.setFormSubmissionId(new BigInteger(voaApp.getEntityKey()
					.getKeyValue().toString()));
		} catch (Exception ex) {
			msg.setDetail(ex.getMessage());
			response.setMessage(msg);
		}
		// response.setStatus("Form Submitted");
		BuildHelper bh = new BuildHelper();
		response.setFormSubmissionId(retrieveFormSubmissionStatusRequest
				.getFormSubmissionId());
		response.setTimeStamp(bh.getDateJavatoXML(new Date()));
	}

	//legacy format
	//getSubmitID = secs & mins & "-" & hours & dd & mm & "-" & yyyy
	private String makeSid(Calendar now)
	{
		return String.format("%02d", now.get(Calendar.SECOND)) +
				String.format("%02d", now.get(Calendar.MINUTE)) + "-" +
				String.format("%02d", now.get(Calendar.HOUR_OF_DAY)) +
				String.format("%02d", now.get(Calendar.DAY_OF_MONTH)) +
				String.format("%02d", now.get(Calendar.MONTH) + 1) + "-" +
				String.format("%04d", now.get(Calendar.YEAR));
	}

	//SID must always be unique
	//for temp solution we are storing in the fQID
	@SuppressWarnings("rawtypes")
	private String generateSid() {
		String sid = "";
		Calendar now = Calendar.getInstance();

		List res = null;

		do  {
				sid = makeSid(now);

				try {
					 res = this.getVoaApplicationService().findByFQID(sid);
				} catch (ServiceException e) {
					logger.error(e);
				}

				if (res == null || res.isEmpty()) break;

				now.add(Calendar.SECOND, 1);

		} while (res != null && res.size() > 0);

		return sid;
	}

	private BigDecimal saveApplicationData(SubmitFormRequest submitFormRequest,
			SubmitFormResponse response, String sid) throws VoaFault {
		//
		// processAuthenticate(VOA_MESSAGE_INITIATER);
		TypesHelper typesHelper = new TypesHelper();
		BuildHelper bh = new BuildHelper();
		BigDecimal applicationId = null;
		VOAApplication voaApp = new VOAApplication();

		if(submitFormRequest.getForm() != null &&
				submitFormRequest.getForm().getSummary() != null &&
				submitFormRequest.getForm().getSummary().getPersonInfo() != null){
			PersonInfo personInfo = submitFormRequest.getForm().getSummary().getPersonInfo();
			if (personInfo != null) {

				if (personInfo.getFirstName() != null)
					voaApp.setFirstName(personInfo.getFirstName());
				if (personInfo.getLastName() != null)
					voaApp.setLastName(personInfo.getLastName());
				if (personInfo.getMiddleName() != null)
					voaApp.setMiddleName(personInfo.getMiddleName());
				if (personInfo.getDob() != null)
					voaApp.setDateOfBirth(bh.stringToDate(personInfo.getDob()));
				if (personInfo.getGender() != null)
					voaApp.setGender(typesHelper.getGender(personInfo.getGender()));
				if (personInfo.getSsnText() != null)
					voaApp.setSsn(personInfo.getSsnText());
			}
		}

		//set PREFERRED_FACILITY_ID
		if(submitFormRequest.getForm().getSummary().getDemographics() != null && submitFormRequest.getForm().getSummary().getDemographics().getPreferredFacility() != null){
			voaApp.setPreferredFacility(typesHelper.getVAFacility(submitFormRequest.getForm().getSummary().getDemographics().getPreferredFacility()));
		}

		if(submitFormRequest.getIdentity() != null && submitFormRequest.getIdentity().getAuthenticationLevel() != null){
			AuthenticationLevel auth = submitFormRequest.getIdentity()
					.getAuthenticationLevel();
			if (auth != null && auth.getType() != null) {
				voaApp.setAuthenticationLevel(typesHelper
						.getAuthenticationLevel(auth.getType()));
			}
		}

		// // Veteran Identifier
		if(submitFormRequest.getIdentity() != null && submitFormRequest.getIdentity()
					.getVeteranIdentifier() != null){
			VeteranIdentifier vid = submitFormRequest.getIdentity()
					.getVeteranIdentifier();
			if (vid != null && vid.getType() != null) {

				voaApp.setFullQualifiedId(vid.getValue());
				voaApp.setIdentityType(typesHelper.getVeteranIdentifierType(vid
						.getType()));
			}
		}

		// Form type
		if (submitFormRequest.getForm() != null &&
				submitFormRequest.getForm().getFormIdentifier() != null &&
				submitFormRequest.getForm().getFormIdentifier().getType() != null) {
			voaApp.setFormType(typesHelper.getVOAFormType(submitFormRequest
					.getForm().getFormIdentifier().getType()));

		}

		voaApp.setReceiveTimeStamp(new Date());
		voaApp.setResponseTimeStamp(new Date());

		if (sid != null) {
			voaApp.setFullQualifiedId(sid);
		}


		// Documents
		if (submitFormRequest.getForm().getAttachments() != null
				&& submitFormRequest.getForm().getAttachments().getDocument() != null) {
			List<gov.va.med.esr.voa.webservice.Document> documentList = submitFormRequest
					.getForm().getAttachments().getDocument();

			for (Document document : documentList) {
				voaApp.addFileAttachment(createFileAttachment(document));
			}
		}
		// Serialize only data not the file attachament
		voaApp.setVOAApplicationData(createApplicationData(submitFormRequest));
		// Set the application status to form submitted
		/*
		 * Form submission status 100 -- Form Submitted, 101 -- Form Submission
		 * Failed, 102 -- Form Processing In Progress, 103 -- Form Processing
		 * Pending, 104 -- Form Processed Successfully,
		 */
		// save application
		Message msg = new Message();
		voaApp.setApplicationStatus(typesHelper
				.getVOAApplicationStatus(VOAApplicationStatus.FORM_SUBMITTED
						.getCode()));
		VOAApplication newVoaApp = null;
		try {

			// voaApp.setApplicationStatus(typesHelper.getLookupService().getVOAApplicationStatusByCode(VOAApplicationStatus.FORM_SUBMITTED.getCode()));
			 newVoaApp = this.getVoaApplicationService().save(
					voaApp);
			applicationId = (BigDecimal) newVoaApp.getEntityKey().getKeyValue();

			response.setStatus(voaApp.getApplicationStatus().getCode());
			response.setFormSubmissionId(applicationId.toBigInteger());
			msg.setType("Form successfully received for EE processing");
			response.setMessage(msg);
		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("Form Save exception: " + ex.getMessage());
			 }
//			 Save data error.
			ObjectFactory factory = new ObjectFactory();
			VoaFaultException voaFaultException = factory
					.createVoaFaultException();
			VoaFaultException.FaultExceptions faultExceptions = factory
					.createVoaFaultExceptionFaultExceptions();
			VoaFaultException.FaultExceptions.FaultException faultException = factory
					.createVoaFaultExceptionFaultExceptionsFaultException();
			faultException.setCode("VOA_0240");
			faultException.setMessage("Form data is failed to save in the system");
			faultExceptions.getFaultException().add(faultException);
			voaFaultException.setFaultExceptions(faultExceptions);
			throw new VoaFault("formSubmissionException", voaFaultException);

		}

		return applicationId;
	}

	private Person buildPerson(SubmitFormRequest submitFormRequest) throws Exception {

		Person person = new Person();
		if(submitFormRequest.getForm() != null && submitFormRequest.getForm().getSummary() != null){

			DemographicsBuilderFactory demographicBuilderFactory = new DemographicsBuilderFactoryImpl();

			FinancialsBuilderFactoryImpl financialsBuildFactory = new FinancialsBuilderFactoryImpl();

			EnrollmentDeterminationBuilderFactoryImpl enrollmentDeterminationBuilderFactory = new EnrollmentDeterminationBuilderFactoryImpl();

			MilitaryServiceBuilderFactory militaryServiceBuilderFactory = new MilitaryServiceBuilderFactoryImpl();

			enrollmentDeterminationBuilderFactory
					.buildEntrollmentDeterminationServices(person,
							submitFormRequest);

			demographicBuilderFactory.buildDemographics(person, submitFormRequest);

			/**
			 * RTC Task 236652  - Fix for VOA Financial non-disclosure
			 * VOAApplciation service was added as a parameter
			 */

			financialsBuildFactory.buildFinancialServices(person, submitFormRequest, voaApplicationService);


			militaryServiceBuilderFactory.buildMilitaryServices(person,
					submitFormRequest);
		}
		return person;
	}

	private String convertToXML(Form form) {
		String xml = null;
		try {

			JAXBContext jaxbContext = JAXBContext.newInstance(Form.class);
			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			StringWriter sw = new StringWriter();
			// jaxbMarshaller.marshal(arg0, arg1)
			jaxbMarshaller.marshal(form, sw);
			xml = sw.toString();
		} catch (JAXBException ex) {
			 if (logger.isDebugEnabled()){
				logger.debug("Form Save exception: " + ex.getMessage()
						+ ex.getErrorCode());
			 }

		}
		return xml;

	}

	private VOAApplicationData createApplicationData(SubmitFormRequest submitFormRequest) {
		// Serialize only data not the file attachament
		Form form = new Form();
		if(submitFormRequest.getForm() != null && submitFormRequest.getForm().getSummary() != null){
		form.setSummary(submitFormRequest.getForm().getSummary());
		}
		if(submitFormRequest.getForm() != null && submitFormRequest.getForm().getFormIdentifier() != null){
		form.setFormIdentifier(submitFormRequest.getForm().getFormIdentifier());
		}
		if(submitFormRequest.getForm() != null && submitFormRequest.getForm().getApplications() != null){
		form.setApplications(submitFormRequest.getForm().getApplications());
		}
		VOAApplicationData appdata = new VOAApplicationData();
		appdata.setApplicationData(convertToXML(form));
		return appdata;
	}

	private VoaFileAttachment createFileAttachment(Document doc) {
		VoaFileAttachment attachment = new VoaFileAttachment();
		if (doc != null) {
			attachment.addVoaAttachmentDetail(createAttachmentDetail(doc));
			attachment.setAttachmentImage(createAttachmentImage(doc));
			if (doc.getName() != null)
				attachment.setFileName(doc.getName());
			if (doc.getFormat() != null)
				attachment.setFileMimeType(doc.getFormat().value());
		}
		return attachment;
	}

	private VoaFileAttachmentImage createAttachmentImage(Document doc) {
		VoaFileAttachmentImage image = new VoaFileAttachmentImage();
		try {
			if (doc.getContent() != null && doc.getContent().length > 0)
				// CCR 12095..
			   image.setFileImage(doc.getContent());
		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("createAttachmentImage error : " + ex.getMessage());
			 }

		}
		return image;
	}

	private VoaFileAttachmentDetail createAttachmentDetail(Document doc) {
		VoaFileAttachmentDetail detail = new VoaFileAttachmentDetail();
		if (doc.getType() != null)
			detail.setEligibilityDocType(new TypesHelper()
					.getEligibilityDocType(doc.getType()));
		return detail;
	}

	/**
	 * Validate the submitted form data. If form is not valid, throw fault
	 * exception.
	 *
	 * Form is a required field in schema, no NULL check here.
	 *
	 * @param submittedForm
	 * @throws VoaFault
	 */
	private void validate(Form submittedForm, BigDecimal applicationId)
			throws VoaFault {
		logger.debug("validate form data.");

		//CCR12789 add the flag for the new OMB approved form (1010EZ only, EZR not revised yet)
		//CCR 13311 for 2014 OMB approved forms, 1010EZR sync up with 1010EZ, so set it to be true
		boolean isNewOMBApprovedForm = true;

		BindException errors = new BindException(submittedForm, "form");

		FormValidator validator = new FormValidator();
		validator.setNewOMBApprovedForm(isNewOMBApprovedForm); //set the new OMB approved flag for other validator to use
		validator.validate(submittedForm, errors);

		processError(errors, applicationId);
	}

	private void processError(BindException errors, BigDecimal applicationId) throws VoaFault {
		if (errors.hasErrors()) {
			 if (logger.isDebugEnabled()){
				 logger.debug("form has errors.");
			 }
			StringBuffer errCode = new StringBuffer();
			ObjectFactory factory = new ObjectFactory();
			VoaFaultException voaFaultException = factory
					.createVoaFaultException();
			VoaFaultException.FaultExceptions faultExceptions = factory
					.createVoaFaultExceptionFaultExceptions();

			for (Object iter : errors.getAllErrors()) {
				ObjectError error = (ObjectError) iter;
				String code = error.getCode();
				String msg = error.getDefaultMessage();
				 if (logger.isDebugEnabled()){
					 logger.debug("error code = " + code + " message = " + msg);
				 }
				if(errCode.toString().length() <= 0 || errCode.toString().isEmpty()) {
					errCode.append(code );
				}else{
					errCode.append(","+ code);
				}
				VoaFaultException.FaultExceptions.FaultException faultException = factory
						.createVoaFaultExceptionFaultExceptionsFaultException();
				faultException.setCode(code);
				faultException.setMessage(msg);
				faultExceptions.getFaultException().add(faultException);
			}

			// validation failure update the status to submission failed
			if (applicationId != null) {
				updateApplicationFormSubmitStatus(applicationId,errCode.toString(), null);
			}
			voaFaultException.setFaultExceptions(faultExceptions);

			throw new VoaFault("formSubmissionException", voaFaultException);
		}

		 if (logger.isDebugEnabled()){
			 logger.debug("validate form data - Done.");
		 }
	}

	public VOAApplicationService getVoaApplicationService() {
		if (voaApplicationService == null) {
			voaApplicationService = (VOAApplicationService) SingletonApplicationContext
					.getInstance().getSingletonContext()
					.getBean("voaApplicationService");
		}
		return voaApplicationService;
	}

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

	public EnvironmentParamService getEnvironmentParamService() {
		if (environmentParamService == null) {
			environmentParamService = (EnvironmentParamService) SingletonApplicationContext
					.getInstance().getSingletonContext()
					.getBean("common.environmentParamService");
		}
		return environmentParamService;
	}

	public void setEnvironmentParamService(
			EnvironmentParamService environmentParamService) {
		this.environmentParamService = environmentParamService;
	}

	public SystemParameterService getSystemParameterService() {
		if (systemParameterService == null) {
			systemParameterService = (SystemParameterService) SingletonApplicationContext
					.getInstance().getSingletonContext()
					.getBean("systemParameterService");
		}
		return systemParameterService;
	}

	public void setSystemParameterService(
			SystemParameterService systemParameterService) {
		this.systemParameterService = systemParameterService;
	}

	private void processAuthenticate(String logicalID) throws LoginException {
		UserCredentials creds = new UserCredentials();
		creds.setAnonymous(true);
		creds.setLogicalID(logicalID);

		SecurityContextHelper.initSecurityContextOnThread(getLoginManager(),
				creds);
	}

	private void updateApplicationFormSubmitStatus(BigDecimal applicationId,String errTxt, Person incoming) {
		try {
			VOAApplication voaAppErr = this.getVoaApplicationService()
					.findVoaApplicationByApplicationId(applicationId);
			TypesHelper typesHelper = new TypesHelper();
			voaAppErr.setApplicationStatus(typesHelper
					.getVOAApplicationStatus(VOAApplicationStatus.FORM_SUBMISSION_FAILED
							.getCode()));
			if(errTxt != null) voaAppErr.setErrorText(errTxt);

			voaAppErr.setResponseTimeStamp(new Date());
			this.getVoaApplicationService().setVOAFormFailed(voaAppErr, incoming);


			//this.getVoaApplicationService().updateVOAApplication(voaAppErr);
		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("Update VOA application status exception: "
						 + ex.getStackTrace());
			 }
		}

	}

	private void updateApplicationForRedirect(BigDecimal applicationId,String errTxt, String sid) {
		try {
			VOAApplication voaAppErr = this.getVoaApplicationService()
					.findVoaApplicationByApplicationId(applicationId);
			TypesHelper typesHelper = new TypesHelper();
			voaAppErr.setApplicationStatus(typesHelper
					.getVOAApplicationStatus(VOAApplicationStatus.FORM_RESUBMITTED
							.getCode()));
			if(errTxt != null) voaAppErr.setErrorText(errTxt);
			voaAppErr.setResponseTimeStamp(new Date());
			voaAppErr.setFullQualifiedId(sid);
			this.getVoaApplicationService().updateVOAApplication(voaAppErr);
		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("Update VOA application status exception: "
						 + ex.getStackTrace());
			 }
		}

	}

	//CCR 13857
	private void updateApplicationFacility(BigDecimal applicationId,String facility) {
		try {

			VOAApplication voaApp = this.getVoaApplicationService()
					.findVoaApplicationByApplicationId(applicationId);
			TypesHelper typesHelper = new TypesHelper();

			voaApp.setPreferredFacility(typesHelper.getVAFacility(facility));
			this.getVoaApplicationService().updateVOAApplication(voaApp);

		} catch (Exception ex) {
			 if (logger.isDebugEnabled()){
				 logger.debug("Update VOA application facility exception: "
						 + ex.getStackTrace());
			 }
		}

	}


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

		return loginManager;
	}

	//RTC WI 360133
	//Redirect all online submissions to legacy 1010
	private void redirectToLegacy1010(SubmitFormRequest submitFormRequest, BigDecimal applicationId, String sid) throws VoaFault {

		try {
			boolean isProd = this.getEnvironmentParamService().isProdEnv();

			Element root = new Element("form1");

			//exceptions are eaten and logged for each section
			//form will still be forwarded if one section fails

			//id traits
			setPersonInfo(root, submitFormRequest.getForm().getSummary().getPersonInfo());

			//address, phone, race and ethnicity
			setDemographics(root, submitFormRequest.getForm().getSummary().getDemographics(), isProd);

			//military service
			setMilitaryService(root, submitFormRequest.getForm().getSummary().getMilitaryServiceInfo());

			//special factors
			setSpecialFactors(root, submitFormRequest.getForm().getSummary());

			//insurance
			setInsurance(root, submitFormRequest.getForm().getSummary().getInsuranceList());

			//go through financials only if disclosed
			if (submitFormRequest.getForm().getSummary().getFinancialsInfo() != null &&
					submitFormRequest.getForm().getSummary().getFinancialsInfo().getIncomeTest() != null &&
					submitFormRequest.getForm().getSummary().getFinancialsInfo().getIncomeTest().isDiscloseFinancialInformation() != null) {

				Boolean disclose = submitFormRequest.getForm().getSummary().getFinancialsInfo().getIncomeTest().isDiscloseFinancialInformation();
				if (disclose) {
					//spouse financials
					setSpouseFinancials(root, submitFormRequest.getForm().getSummary().getFinancialsInfo());

					//child financials
					setChildFinancials(root, submitFormRequest.getForm().getSummary().getFinancialsInfo());

					//vet income and expenses
					setVetIncomeAndExpenses(root, submitFormRequest.getForm().getSummary().getFinancialsInfo());

					Element discloseDetails = new Element("ProvideDetails");
					discloseDetails.addContent("Y");
					root.addContent(discloseDetails);

				} else {
					Element discloseDetails = new Element("ProvideDetails");
					discloseDetails.addContent("N");
					root.addContent(discloseDetails);
				}
			} else {
				Element discloseDetails = new Element("ProvideDetails");
				discloseDetails.addContent("N");
				root.addContent(discloseDetails);
			}

			//sid and resend flag
			setSid(root, sid);

			org.jdom2.Document convertedDoc = new org.jdom2.Document();

			convertedDoc.setRootElement(root);

			//write out the xml doc for dev and test env for troubleshooting
			if (!isProd) {
				XMLOutputter outter=new XMLOutputter();
				outter.setFormat(org.jdom2.output.Format.getPrettyFormat());
				FileOutputStream fstream = null;
				try {
					fstream = new FileOutputStream(new File("forwardedXML_"+ sid + ".xml"));
					outter.output(convertedDoc, fstream);
				} catch (FileNotFoundException e) {
					logger.error("Cannot write output xml file" + e);
				} catch (IOException e) {
					logger.error("Cannot write output xml file" +e);
				} finally {
					IOUtils.closeQuietly(fstream);
				}
			}

			postConvertedSubmission(convertedDoc, isProd);

			//update as status Form Resubmitted, populate error text with redirect message and SID
			this.updateApplicationForRedirect(applicationId, "Application Not Processed by ES. Forwarded to legacy 1010 with SID:" + sid, sid);

		} catch (Exception ex) {

			logger.error("Unknown Exception Forwarding to online1010 for application id:" + applicationId, ex);

			//update as Failed status
			this.updateApplicationFormSubmitStatus(applicationId, ex.getMessage(), null);
		}

	}

	//execute the post of the converted xml doc to the legacy 1010 site
	private void postConvertedSubmission(org.jdom2.Document document, boolean isProd) throws Exception {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        //write the xml doc to the stream
        XMLOutputter outputter = new XMLOutputter();
        outputter.output(document, outputStream);
        byte[] docBytes = outputStream.toByteArray();
        InputStream inputStream = new ByteArrayInputStream(docBytes);
        PostMethod post = null;

        if (isProd) {
        	post = new PostMethod(REDIRECT_URL_PROD);
        }	else {
        	post = new PostMethod(REDIRECT_URL_DEV);
        }

        try {

	        post.setRequestEntity(new InputStreamRequestEntity(inputStream, docBytes.length));
	        post.setRequestHeader("Content-type", "text/xml; charset=ISO-8859-1");
	        HttpClient httpclient = new HttpClient();
	        //20 second timeout for now
	        httpclient.getParams().setSoTimeout(20000);
	        httpclient.getParams().setConnectionManagerTimeout(20000);

	        //execute post
        	int result = httpclient.executeMethod(post);

        	logger.warn("VOA Redirect Status Response:" + post.getResponseBodyAsString());

            if (result >= 400) {
            	logger.error("Failed Response from 1010 Redirect:" + post.getResponseBodyAsString());
            	throw new Exception ("HTTP Status Response: " + result);
            }


        } finally {
    		post.releaseConnection();
    		IOUtils.closeQuietly(outputStream);
    		IOUtils.closeQuietly(inputStream);
        }
	}

	//convert expenses to flat individual elements
	private void setVetIncomeAndExpenses(Element root, FinancialsInfo fin) {

		if (fin == null || fin.getFinancialStatement() == null) return;

		try {

			//Incomes
			if (fin.getFinancialStatement().getIncomes() != null && fin.getFinancialStatement().getIncomes().getIncome() != null) {
				List<IncomeInfo> incomes = fin.getFinancialStatement().getIncomes().getIncome();

				Iterator<IncomeInfo> incomeIter = incomes.iterator();
				boolean grossAdded = false;
				boolean propAdded = false;
				boolean otherAdded = false;
				while (incomeIter.hasNext()) {
					IncomeInfo income = incomeIter.next();


					//gross income
					if (income != null && income.getType().equalsIgnoreCase("7")) {
						Element vetGrossIncome = new Element("VetGrossIncome");
						vetGrossIncome.addContent(income.getAmount().toString());
						root.addContent(vetGrossIncome);
						grossAdded = true;
					}
					//property
					if (income != null && income.getType().equalsIgnoreCase("13")) {
						Element vetPropIncome = new Element("VetPropertyIncome");
						vetPropIncome.addContent(income.getAmount().toString());
						root.addContent(vetPropIncome);
						propAdded = true;
					}
					//other
					if (income != null && income.getType().equalsIgnoreCase("10")) {
						Element vetOtherIncome = new Element("VetOtherIncome");
						vetOtherIncome.addContent(income.getAmount().toString());
						root.addContent(vetOtherIncome);
						otherAdded = true;
					}


				if (!grossAdded) {
					Element vetGrossIncome = new Element("VetGrossIncome");
					vetGrossIncome.addContent("0");
					root.addContent(vetGrossIncome);
				}
				if (!propAdded) {
					Element vetPropIncome = new Element("VetPropertyIncome");
					vetPropIncome.addContent("0");
					root.addContent(vetPropIncome);
				}
				if (!otherAdded) {
					Element vetOtherIncome = new Element("VetOtherIncome");
					vetOtherIncome.addContent("0");
					root.addContent(vetOtherIncome);
				}

			}
			}// end Incomes


			//Expenses
			if (fin.getFinancialStatement().getExpenses() != null && fin.getFinancialStatement().getExpenses().getExpense() != null) {
				List<ExpenseInfo> expenses = fin.getFinancialStatement().getExpenses().getExpense();

				Iterator<ExpenseInfo> expenseIter = expenses.iterator();

				while (expenseIter.hasNext()) {
					ExpenseInfo expense = expenseIter.next();
					//medical
					if (expense != null && expense.getExpenseType() != null &&
							expense.getExpenseType().equalsIgnoreCase("18")) {

						Element med = new Element("MedicalExpenses");
						med.addContent(expense.getAmount().toString());
						root.addContent(med);
					}
					//education
					if (expense != null && expense.getExpenseType() != null &&
							expense.getExpenseType().equalsIgnoreCase("3")) {

						Element school = new Element("VetSelfSchool");
						school.addContent(expense.getAmount().toString());
						root.addContent(school);
					}
					//funeral
					if (expense != null && expense.getExpenseType() != null &&
							expense.getExpenseType().equalsIgnoreCase("19")) {

						Element funeral = new Element("FuneralExpenses");
						funeral.addContent(expense.getAmount().toString());
						root.addContent(funeral);
					}
				}
			}

		} catch (Exception ex) {
			logger.error("Unknown error translating VOA vet expenses", ex);
		}
	}

	//convert child financials infor to flat individual elemements
	private void setChildFinancials(Element root, FinancialsInfo fin) {

		if (fin == null || fin.getFinancialStatement() == null) return;

		try {
			if (fin.getFinancialStatement().getDependentFinancialsList() != null &&
					fin.getFinancialStatement().getDependentFinancialsList().getDependentFinancials() != null) {

				List<DependentFinancialsInfo> dependents = fin.getFinancialStatement().getDependentFinancialsList().getDependentFinancials();
				Iterator<DependentFinancialsInfo> dependIter = dependents.iterator();

				int count = 0;


				while(dependIter.hasNext()) {
					count++;
					DependentFinancialsInfo dependent = dependIter.next();

					//dependent info
					if (dependent.getDependentInfo() != null) {

						DependentInfo dependentInfo = dependent.getDependentInfo();
						//child last name
						Element depname = new Element("ChildNameLast");
						depname.addContent(dependentInfo.getFamilyName());
						root.addContent(depname);

						//child first name
						Element depFname = new Element("ChildNameFirst");
						depFname.addContent(dependentInfo.getGivenName());
						root.addContent(depFname);

						//child middle name
						if (dependentInfo.getMiddleName() != null) {
							Element depMname = new Element("ChildNameMiddle");
							depMname.addContent(dependentInfo.getMiddleName());
							root.addContent(depMname);
						} else {
							Element depMname = new Element("ChildNameMiddle");
							depMname.addContent("");
							root.addContent(depMname);
						}

						//child suffix
						if (dependentInfo.getSuffix() != null) {
							Element depSuf= new Element("ChildNameSuffix");
							depSuf.addContent(dependentInfo.getSuffix());
							root.addContent(depSuf);
						} else {
							Element depSuf= new Element("ChildNameSuffix");
							depSuf.addContent("");
							root.addContent(depSuf);
						}

						//child DOB
						Element depDob= new Element("ChildDateOfBirth");
						depDob.addContent(dependentInfo.getDob());
						root.addContent(depDob);

						//child SSN
						if (dependentInfo.getSsns() != null && dependentInfo.getSsns().getSsn() != null &&
								dependentInfo.getSsns().getSsn().get(0) != null) {

							String ssnText = dependentInfo.getSsns().getSsn().get(0).getSsnText();
							String formattedSSN = String.format("%s-%s-%s", ssnText.substring(0, 3), ssnText.substring(3, 5),
									ssnText.substring(5, 9));
							Element depSsn= new Element("ChildSocialSecurityNumber");
							depSsn.addContent(formattedSSN);
							root.addContent(depSsn);
						}

						//start date
						Element depStart= new Element("ChildDependentDate");
						depStart.addContent(dependentInfo.getStartDate());
						root.addContent(depStart);

						//relationship
						String relationship = dependentInfo.getRelationship();
						if (relationship != null) {

							Element rel= new Element("ChildRelationshipSon");
								if (relationship.equalsIgnoreCase("3")) {
									rel.addContent("1");
								} else {
									rel.addContent("0");
								}
								root.addContent(rel);



								Element rel2= new Element("ChildRelationshipDaughter");
								if (relationship.equalsIgnoreCase("4")) {
									rel2.addContent("1");
								} else {
									rel2.addContent("0");
								}
								root.addContent(rel2);



								Element rel3= new Element("ChildRelationshipStepson");
								if (relationship.equalsIgnoreCase("5")) {
									rel3.addContent("1");
								} else {
									rel3.addContent("0");
								}
								root.addContent(rel3);



								Element rel4= new Element("ChildRelationshipStepdaughter");
								if (relationship.equalsIgnoreCase("6")) {
									rel4.addContent("1");
								} else {
									rel4.addContent("0");
								}
								root.addContent(rel4);

						}

					} // end dependent info

					//contributed to support
					if (dependent.isContributedToSupport() != null) {
						Boolean isContrib = dependent.isContributedToSupport();
						if (isContrib) {
							Element contrib = new Element("ChildSupportAmount");
							contrib.addContent("600.00");
							root.addContent(contrib);
						} else {
							Element contrib = new Element("ChildSupportAmount");
							contrib.addContent("0");
							root.addContent(contrib);
						}
					}

					//self school
					if (dependent.getExpenses() != null && dependent.getExpenses().getExpense() != null) {
						List<ExpenseInfo> expenses = dependent.getExpenses().getExpense();

						Iterator<ExpenseInfo> expenseIter = expenses.iterator();
						while (expenseIter.hasNext()) {
							ExpenseInfo expense = expenseIter.next();


								Element college = new Element("ChildSelfSchool");
								if (expense.getExpenseType().equalsIgnoreCase("16")) {
									college.addContent(expense.getAmount().toString());
								} else {
									college.addContent("0");
								}
								root.addContent(college);
							}

					} else {
						Element college = new Element("ChildSelfSchool");
						college.addContent("0");
						root.addContent(college);
					}



					//attend school
					if (dependent.isAttendedSchool() != null) {
						Boolean didAttend = dependent.isAttendedSchool();
						if (didAttend) {
							Element att = new Element("ChildAttendSchoolYes");
							att.addContent("1");
							root.addContent(att);

							Element att2 = new Element("ChildAttendSchoolNo");
							att2.addContent("0");
							root.addContent(att2);

						} else {
							Element att = new Element("ChildAttendSchoolNo");
							att.addContent("1");
							root.addContent(att);

							Element att2 = new Element("ChildAttendSchoolYes");
							att2.addContent("0");
							root.addContent(att2);
						}
					}

					//disabled
					if (dependent.isIncapableOfSelfSupport() != null) {
						Boolean disabled = dependent.isIncapableOfSelfSupport();
						if (disabled) {
							Element dis = new Element("ChildTotalDisabledYes");
							dis.addContent("1");
							root.addContent(dis);

							Element dis2 = new Element("ChildTotalDisabledNo");
							dis2.addContent("0");
							root.addContent(dis2);
						} else {
							Element dis = new Element("ChildTotalDisabledNo");
							dis.addContent("1");
							root.addContent(dis);

							Element dis2 = new Element("ChildTotalDisabledYes");
							dis2.addContent("0");
							root.addContent(dis2);
						}
					}

					//Incomes
					if (dependent.getIncomes() != null && dependent.getIncomes().getIncome() != null) {
						List<IncomeInfo> incomes = dependent.getIncomes().getIncome();

						boolean grossAdded = false;
						boolean propAdded = false;
						boolean otherAdded = false;

						Iterator<IncomeInfo> incomeIter = incomes.iterator();
						while (incomeIter.hasNext()) {
							IncomeInfo income = incomeIter.next();
							//gross
							if (income != null && income.getType().equalsIgnoreCase("7")) {
								if (count == 1) {
									Element gross = new Element("Child1GrossIncome");
									gross.addContent(income.getAmount().toString());
									root.addContent(gross);
									grossAdded = true;
								} else {
									Element gross = new Element("ChildGrossIncome");
									gross.addContent(income.getAmount().toString());
									root.addContent(gross);
									grossAdded = true;
								}
							}
							//property
							if (income != null && income.getType().equalsIgnoreCase("13")) {
								if (count == 1) {
									Element prop = new Element("Child1PropertyIncome");
									prop.addContent(income.getAmount().toString());
									root.addContent(prop);
									propAdded = true;
								} else {
									Element prop = new Element("ChildPropertyIncome");
									prop.addContent(income.getAmount().toString());
									root.addContent(prop);
									propAdded = true;
								}
							}
							//other
							if (income != null && income.getType().equalsIgnoreCase("10")) {
								if (count == 1) {
									Element other = new Element("Child1OtherIncome");
									other.addContent(income.getAmount().toString());
									root.addContent(other);
									otherAdded = true;
								} else {
									Element other = new Element("ChildOtherIncome");
									other.addContent(income.getAmount().toString());
									root.addContent(other);
									otherAdded = true;
								}
							}

						} // end income iter

						if (!grossAdded) {

								if (count == 1) {
									Element gross = new Element("Child1GrossIncome");
									gross.addContent("0");
									root.addContent(gross);
								} else {
									Element gross = new Element("ChildGrossIncome");
									gross.addContent("0");
									root.addContent(gross);
								}

						}

						if (!propAdded) {

								if (count == 1) {
									Element prop = new Element("Child1PropertyIncome");
									prop.addContent("0");
									root.addContent(prop);
								} else {
									Element prop = new Element("ChildPropertyIncome");
									prop.addContent("0");
									root.addContent(prop);
								}

						}

						if (!otherAdded) {

								if (count == 1) {
									Element other = new Element("Child1OtherIncome");
									other.addContent("0");
									root.addContent(other);
								} else {
									Element other = new Element("ChildOtherIncome");
									other.addContent("0");
									root.addContent(other);
								}

						}

					} // end child incomes
				} // end dependent iterator
		}

		} catch (Exception ex) {
			logger.error("Unknown error translating VOA child financials", ex);
		}
	}

	//convert spouse financials info to flat individual elements
	private void setSpouseFinancials(Element root, FinancialsInfo fin) {

		if (fin == null || fin.getFinancialStatement() == null) return;

		try {


			//start spouse financials
			if (fin.getFinancialStatement().getSpouseFinancialsList() != null &&
					fin.getFinancialStatement().getSpouseFinancialsList().getSpouseFinancials() != null &&
					fin.getFinancialStatement().getSpouseFinancialsList().getSpouseFinancials().get(0) != null) {

				SpouseInfo spouseInfo = fin.getFinancialStatement().getSpouseFinancialsList().getSpouseFinancials().get(0).getSpouse();
				SpouseFinancialsInfo spouseFins = fin.getFinancialStatement().getSpouseFinancialsList().getSpouseFinancials().get(0);

				if (spouseInfo != null) {
					//spouse last name
					Element spLname = new Element("SpouseNameLast");
					spLname.addContent(spouseInfo.getFamilyName());
					root.addContent(spLname);

					//spouse first name
					Element spFname = new Element("SpouseNameFirst");
					spFname.addContent(spouseInfo.getGivenName());
					root.addContent(spFname);

					//spouse middle name
					if (spouseInfo.getMiddleName() != null) {
						Element spMname = new Element("SpouseNameMiddle");
						spMname.addContent(spouseInfo.getMiddleName());
						root.addContent(spMname);
					}

					//spouse suffix
					if (spouseInfo.getSuffix() != null) {
						Element spSuf= new Element("SpouseNameSuffix");
						spSuf.addContent(spouseInfo.getSuffix());
						root.addContent(spSuf);
					}

					//spouse maiden name
					if (spouseInfo.getMaidenName() != null) {
						Element spMn= new Element("SpouseMaidenName");
						spMn.addContent(spouseInfo.getMaidenName());
						root.addContent(spMn);
					}

					//spouse ssn
					if (spouseInfo.getSsns() != null && spouseInfo.getSsns().getSsn() != null &&
							spouseInfo.getSsns().getSsn().get(0) != null ) {

						String ssnText = spouseInfo.getSsns().getSsn().get(0).getSsnText();
						String formattedSSN = String.format("%s-%s-%s", ssnText.substring(0, 3), ssnText.substring(3, 5),
								ssnText.substring(5, 9));
						Element spSsn= new Element("SpouseSocialSecurityNumber");
						spSsn.addContent(formattedSSN);
						root.addContent(spSsn);
					}

					//spouse dob
					Element spDob = new Element("SpouseDateOfBirth");
					spDob.addContent(spouseInfo.getDob());
					root.addContent(spDob);

					//spouse address
					AddressInfo spAddress = spouseInfo.getAddress();
					Element line1 = new Element("SpouseAddress");
					line1.addContent(spAddress.getLine1());
					root.addContent(line1);


					Element cityCountry = new Element("SpouseCity");
					String city ="";
					if (spAddress.getCountry().equalsIgnoreCase("USA")) {
						city = spAddress.getCity();
					} else {
						city = spAddress.getCity() + ", " + spAddress.getCountry();
					}
					if (city.length() > 30) city = city.substring(0, 30);
					cityCountry.addContent(city);
					root.addContent(cityCountry);

					Element state = new Element("SpouseState");
					if (spAddress.getCountry().equalsIgnoreCase("USA")) {
						String st = spAddress.getState();
						if (st != null && st.length() > 2) st = st.substring(0, 2);
						state.addContent(st);
					} else {
						state.addContent("FG");
					}
					root.addContent(state);

					Element zip = new Element("SpouseZip");
					if (spAddress.getCountry().equalsIgnoreCase("USA")) {
						zip.addContent(spAddress.getZipCode());
					} else {
						zip.addContent(spAddress.getPostalCode());
					}
					root.addContent(zip);


					if (spAddress.getPhoneNumber() != null) {
						Element spPhone = new Element("SpousePhone");
						String num = String.format("(%s) %s-%s", spAddress.getPhoneNumber().substring(0, 3), spAddress.getPhoneNumber().substring(3, 6),
								spAddress.getPhoneNumber().substring(6, 10));

						spPhone.addContent(num);
						root.addContent(spPhone);
					}


					//marriage date
					Element marrDate = new Element("MarraigeDate");
					marrDate.addContent(spouseInfo.getStartDate());
					root.addContent(marrDate);


				} // end spouse info

				//spouse incomes
				if (spouseFins != null) {

					if (spouseFins.getIncomes() != null && spouseFins.getIncomes().getIncome() != null) {
						List<IncomeInfo> spouseIncomes = spouseFins.getIncomes().getIncome();
						Iterator<IncomeInfo> finsIter = spouseIncomes.iterator();

						boolean grossAdded = false;
						boolean propAdded = false;
						boolean otherAdded = false;

						while (finsIter.hasNext()) {
							IncomeInfo income = finsIter.next();

							//gross
							if (income.getType().equalsIgnoreCase("7")) {
								Element spGrossIncome = new Element("SpouseGrossIncome");
								spGrossIncome.addContent(income.getAmount().toString());
								root.addContent(spGrossIncome);
								grossAdded = true;
							}
							//property
							if (income.getType().equalsIgnoreCase("13")) {
								Element spPropIncome = new Element("SpousePropertyIncome");
								spPropIncome.addContent(income.getAmount().toString());
								root.addContent(spPropIncome);
								propAdded = true;
							}
							//all other
							if (income.getType().equalsIgnoreCase("10")) {
								Element spOtherIncome = new Element("SpouseOtherIncome");
								spOtherIncome.addContent(income.getAmount().toString());
								root.addContent(spOtherIncome);
								otherAdded = true;
							}

						}

						if (!grossAdded) {

								Element spGrossIncome = new Element("SpouseGrossIncome");
								spGrossIncome.addContent("0");
								root.addContent(spGrossIncome);

						}

						if (!propAdded) {

								Element spPropIncome = new Element("SpousePropertyIncome");
								spPropIncome.addContent("0");
								root.addContent(spPropIncome);

						}

						if (!otherAdded) {

								Element spOtherIncome = new Element("SpouseOtherIncome");
								spOtherIncome.addContent("0");
								root.addContent(spOtherIncome);

						}
					}


				} // end spouse incomes

				//contrib to spousal support
				if (spouseFins.isContributedToSpousalSupport() != null) {

					Boolean isContrib = spouseFins.isContributedToSpousalSupport();
					if (isContrib) {
						Element contrib = new Element("SpouseSupportAmount");
						contrib.addContent("600.00");
						root.addContent(contrib);
					}
				}

			} // end spouse financials


		}
		catch (Exception ex) {
			logger.error("Unknown error translating VOA financials", ex);
		}
	}


	//convert insurance to flat individual elements
	private void setInsurance(Element root, InsuranceCollection insurance) {
		try {
			if (insurance != null) {
				List<InsuranceInfo> insList = insurance.getInsurance();
				if (insList != null) {

					Iterator<InsuranceInfo> insIter = insList.iterator();

					while (insIter.hasNext()) {
						InsuranceInfo ins = insIter.next();

						if (ins != null) {

							if (ins.getInsuranceMappingTypeName().equalsIgnoreCase("MDCR")) {

								if (ins.isEnrolledInPartA() != null) {
									Boolean isEnrolledInPartA = ins.isEnrolledInPartA();

									if (isEnrolledInPartA) {
										Element medA = new Element("MedicareEnrolledA");
										medA.addContent("Y");
										root.addContent(medA);

										Element medADate = new Element("DateMedicarePartA");
										medADate.addContent(ins.getPartAEffectiveDate());
										root.addContent(medADate);
									}
								}
							}

							Element vetIns = new Element("VetHealthInsurance");
							vetIns.addContent("Y");
							root.addContent(vetIns);

							Element vetInsCo = new Element("VetHealthInsureCompany");
							vetInsCo.addContent(ins.getCompanyName());
							root.addContent(vetInsCo);

							Element vetInsHolder = new Element("VetHealthPolicyHolder");
							vetInsHolder.addContent(ins.getPolicyHolderName());
							root.addContent(vetInsHolder);

							Element vetInsNumber = new Element("VetHealthPolicyNumber");
							vetInsNumber.addContent(ins.getPolicyNumber());
							root.addContent(vetInsNumber);

							Element vetInsGroup = new Element("VetHealthGroupCode");
							vetInsGroup.addContent(ins.getGroupNumber());
							root.addContent(vetInsGroup);

							if (ins.getInsAddress() != null) {
								Element vetInsLine1 = new Element("VetHealthInsureAddress");
								vetInsLine1.addContent(ins.getInsAddress().getLine1());
								root.addContent(vetInsLine1);

								Element vetInsCity = new Element("VetHealthInsureCity");
								String insCity = "";
								if (ins.getInsAddress().getCountry().equalsIgnoreCase("USA")) {
									insCity = ins.getInsAddress().getCity();
								} else {
									insCity = ins.getInsAddress().getCity() + ", " + ins.getInsAddress().getCountry();
								}
								vetInsCity.addContent(insCity);
								root.addContent(vetInsCity);

								Element vetInsState = new Element("VetHealthInsureState");
								if (ins.getInsAddress().getCountry().equalsIgnoreCase("USA")) {
									vetInsState.addContent(ins.getInsAddress().getState());
								} else {
									vetInsState.addContent("FG");
								}

								root.addContent(vetInsState);

								Element vetInsZip = new Element("VetHealthInsureZip");
								if (ins.getInsAddress().getCountry().equalsIgnoreCase("USA")) {
									vetInsZip.addContent(ins.getInsAddress().getZipCode());
								} else {
									vetInsZip.addContent(ins.getInsAddress().getPostalCode());
								}

								root.addContent(vetInsZip);
							}

							Element vetInsPhone = new Element("VetHealthInsurePhone");
							if (ins.getInsurancePhones() != null && ins.getInsurancePhones().getPhone() != null &&
									ins.getInsurancePhones().getPhone().get(0) != null) {
							vetInsPhone.addContent(ins.getInsurancePhones().getPhone().get(0).getPhoneNumber());
							root.addContent(vetInsPhone);
							}
						}
					}
				}
			}
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA Insurance", ex);
		}
	}

	//convert special factors to flat individual elements
	private void setSpecialFactors(Element root, EeSummary summary) {

		try {
			//purple heart
			if (summary.getPurpleHeart() != null && summary.getPurpleHeart().isIndicator() != null) {
				Boolean isPh = summary.getPurpleHeart().isIndicator();
				if (isPh) {
					Element ph = new Element("PurpleHeart");
					ph.addContent("Y");
					root.addContent(ph);
				}
			}

			//POW
			if (summary.getPrisonerOfWarInfo() != null) {
				Element pow = new Element("FormerPOW");
				if (summary.getPrisonerOfWarInfo().getPowIndicator().equalsIgnoreCase("True")) {
					pow.addContent("Y");
				} else {
					pow.addContent("N");
				}
				root.addContent(pow);
			}


			//gulf war contaminant
			if (summary.getEnrollmentDeterminationInfo().getSpecialFactors().isEnvContaminantsInd()) {
				Element toxin = new Element("GulfWarToxinExposure");
				toxin.addContent("Y");
				root.addContent(toxin);
			}

			//agent orange exposure
			if (summary.getEnrollmentDeterminationInfo().getSpecialFactors().isAgentOrangeInd()) {
				Element aoe = new Element("AgentOrangeExposure");
				aoe.addContent("Y");
				root.addContent(aoe);
			}

			//radiation exposure
			if (summary.getEnrollmentDeterminationInfo().getSpecialFactors().isRadiationExposureInd()) {
				Element rad = new Element("RadiationExposure");
				rad.addContent("Y");
				root.addContent(rad);
			}

			//radium
			if (summary.getEnrollmentDeterminationInfo().getNoseThroatRadiumInfo() != null) {
				if (summary.getEnrollmentDeterminationInfo().getNoseThroatRadiumInfo().getReceivingTreatment().equalsIgnoreCase("True")) {
					Element radium = new Element("MilitaryRadiumTreatments");
					radium.addContent("Y");
					root.addContent(radium);
				}

			}

			//medicaid eligible
			if (summary.getEnrollmentDeterminationInfo().isEligibleForMedicaid()) {
				Element medicaid = new Element("MedicaidEligible");
				medicaid.addContent("Y");
				root.addContent(medicaid);
			}

			//CL-V --CampLejeune
			if (summary.getEnrollmentDeterminationInfo().getSpecialFactors().isCampLejeuneInd()) {
				Element clv = new Element("CampLejeune");
				clv.addContent("Y");
				root.addContent(clv);
			}
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA special factors", ex);
		}

	}

	//convert military service to flat individual elements
	private void setMilitaryService(Element root, MilitaryServiceInfo milSvc) {
		try {

			if (milSvc != null && milSvc.isDischargeDueToDisability() != null) {
				Boolean dis = milSvc.isDischargeDueToDisability();
				if (dis) {
					Element sca = new Element("RetiredMilitaryDisability");
					sca.addContent("Y");
					root.addContent(sca);
				}
			}

			if (milSvc.getMilitaryServiceSiteRecords() != null && milSvc.getMilitaryServiceSiteRecords().getMilitaryServiceSiteRecord() != null
				&& milSvc.getMilitaryServiceSiteRecords().getMilitaryServiceSiteRecord().get(0) != null) {

					MilitaryServiceSiteRecordInfo lastEpisode = milSvc.getMilitaryServiceSiteRecords().getMilitaryServiceSiteRecord().get(0);


					if (lastEpisode.getMilitaryServiceEpisodes() != null && lastEpisode.getMilitaryServiceEpisodes().getMilitaryServiceEpisode() != null &&
							lastEpisode.getMilitaryServiceEpisodes().getMilitaryServiceEpisode().get(0) != null) {

						MilitaryServiceEpisodeInfo episode = lastEpisode.getMilitaryServiceEpisodes().getMilitaryServiceEpisode().get(0);

						//service branch
						if(episode.getServiceBranch() != null) {
							ServiceBranch sb = typesHelper.getServiceBranch(episode.getServiceBranch());
							Element branch = new Element("LastServiceBranch");
							branch.addContent(sb.getDescription());
							root.addContent(branch);
						}

						//entry date
						Element start = new Element("LastEntryDate");
						start.addContent(episode.getStartDate());
						root.addContent(start);

						//discharge date
						Element end = new Element("LastDischargeDate");
						end.addContent(episode.getEndDate());
						root.addContent(end);

						//discharge type
						if (episode.getDischargeType() != null) {
							DischargeType dt = typesHelper.getDischargeType(episode.getDischargeType());
							Element type = new Element("DischargeType");
							type.addContent(dt.getDescription());
							root.addContent(type);
						}
					}
				}
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA Military Service", ex);
		}
	}

	//convert demographics to flat individual elements
	private void setDemographics(Element root, DemographicInfo demoInfo, boolean isProd) {
		try {
			//Spanish -- hispanic, latino question
			Element spanish = new Element("Spanish");
			if (demoInfo.getEthnicity() != null) {
				if(demoInfo.getEthnicity().equalsIgnoreCase("2135-2")){
					spanish.addContent("Y");
				} else if (demoInfo.getEthnicity().equalsIgnoreCase("2186-5")){
					spanish.addContent("N");
				} else {
					spanish.addContent("U");
				}
			} else {
				spanish.addContent("U");
			}
			root.addContent(spanish);

			//races, all 5 are required, each one is specific to a type
			boolean hasRaces = false;
			List<String> races = null;
			if (demoInfo.getRaces() != null && demoInfo.getRaces().getRace() != null
					&& demoInfo.getRaces().getRace().size() > 0) {
				hasRaces = true;
				races = demoInfo.getRaces().getRace();
			}


			//indian
			Element race1 = new Element("Race1");
			if (hasRaces && isRace("1002-5", races)) {
				race1.addContent("1");
			} else {
				race1.addContent("0");
			}
			root.addContent(race1);

			//black
			Element race2 = new Element("Race2");
			if (hasRaces && isRace("2054-5", races)) {
				race2.addContent("1");
			} else {
				race2.addContent("0");
			}
			root.addContent(race2);

			//asian
			Element race3 = new Element("Race3");
			if (hasRaces && isRace("2028-9", races)) {
				race3.addContent("1");
			} else {
				race3.addContent("0");
			}
			root.addContent(race3);

			//white
			Element race4 = new Element("Race4");
			if (hasRaces && isRace("2106-3", races)) {
				race4.addContent("1");
			} else {
				race4.addContent("0");
			}
			root.addContent(race4);

			//Hawaiian
			Element race5 = new Element("Race5");
			if (hasRaces && isRace("2076-8", races)) {
				race5.addContent("1");
			} else {
				race5.addContent("0");
			}
			root.addContent(race5);

			//Address
			if (demoInfo.getContactInfo() != null && demoInfo.getContactInfo().getAddresses() != null &&
					demoInfo.getContactInfo().getAddresses().getAddress() != null &&
					demoInfo.getContactInfo().getAddresses().getAddress().get(0) != null) {

				AddressInfo address = demoInfo.getContactInfo().getAddresses().getAddress().get(0);
				//line 1
				Element line1 = new Element("CurrentAddress");
				line1.addContent(address.getLine1());
				root.addContent(line1);

				//city, country
				Element cityCountry = new Element("CurrentCity");
				String city ="";
				if (address.getCountry().equalsIgnoreCase("USA")) {
					city = address.getCity();
				} else {
					city = address.getCity() + ", " + address.getCountry();
				}
				if (city.length() > 30) city = city.substring(0, 30);
				cityCountry.addContent(city);
				root.addContent(cityCountry);

				//state
				Element state = new Element("CurrentState");
				if (address.getCountry().equalsIgnoreCase("USA")) {
					String st = address.getState();
					if (st != null && st.length() > 2) st = st.substring(0, 2);
					state.addContent(st);
				} else {
					state.addContent("FG");
				}
				root.addContent(state);

				//zip
				Element zip = new Element("CurrentZip");
				if (address.getCountry().equalsIgnoreCase("USA")) {
					zip.addContent(address.getZipCode());
				} else {
					zip.addContent(address.getPostalCode());
				}
				root.addContent(zip);

				if (address.getCounty() != null) {
					//county
					Element county = new Element("CurrentCounty");
					county.addContent(address.getCounty());
					root.addContent(county);
				}
			}//end address


			//phones
			if (demoInfo.getContactInfo() != null && demoInfo.getContactInfo().getPhones() != null &&
					demoInfo.getContactInfo().getPhones().getPhone() != null)  {

				List<PhoneInfo> phones = demoInfo.getContactInfo().getPhones().getPhone();
				Iterator<PhoneInfo> phoneIter = phones.iterator();

				//only one of each allowed
				boolean homeSet = false;
				boolean cellSet = false;
				while (phoneIter.hasNext()) {
					PhoneInfo pi = phoneIter.next();

					if (!homeSet && pi.getType().equalsIgnoreCase("1")) {
						Element homePhone = new Element("CurrentHomePhone");
						String num = String.format("(%s) %s-%s", pi.getPhoneNumber().substring(0, 3), pi.getPhoneNumber().substring(3, 6),
						          pi.getPhoneNumber().substring(6, 10));
						homePhone.addContent(num);
						root.addContent(homePhone);
						homeSet = true;
					}

					if (!cellSet && pi.getType().equalsIgnoreCase("4")) {
						Element cellPhone = new Element("CellPhone");
						String num = String.format("(%s) %s-%s", pi.getPhoneNumber().substring(0, 3), pi.getPhoneNumber().substring(3, 6),
						          pi.getPhoneNumber().substring(6, 10));
						cellPhone.addContent(num);
						root.addContent(cellPhone);
						cellSet = true;
					}
				}
			} //end phones


			//email, only one accepted, pick the first.
			if (demoInfo.getContactInfo() != null && demoInfo.getContactInfo().getEmails() != null &&
					demoInfo.getContactInfo().getEmails().getEmail() != null && demoInfo.getContactInfo().getEmails().getEmail().get(0) != null) {

				EmailInfo emailInfo = demoInfo.getContactInfo().getEmails().getEmail().get(0);
				Element email = new Element("Email");
				email.addContent(emailInfo.getAddress());
				root.addContent(email);

			}

			//appointment
			if (demoInfo.isAppointmentRequestResponse() != null) {
				Boolean isAppt = demoInfo.isAppointmentRequestResponse();

				if (isAppt) {
					Element appt = new Element("Appointment");
					appt.addContent("Y");
					root.addContent(appt);
				}
			}

			//ACA
			Element aca = new Element("ACA");
			if (demoInfo.isAcaIndicator() != null) {
				Boolean isACA = demoInfo.isAcaIndicator();
				if (isACA) {
					aca.addContent("Y");
				} else {
					aca.addContent("N");
				}
			} else {
				aca.addContent("N");
			}
			root.addContent(aca);

			//marital status
			if (demoInfo.getMaritalStatus() !=null) {
				Element marStatus = new Element("CurrentMaritalStatus");

				if (demoInfo.getMaritalStatus().equalsIgnoreCase("M")) {
					marStatus.addContent("MARRIED");
				} else if (demoInfo.getMaritalStatus().equalsIgnoreCase("S")) {
					marStatus.addContent("NEVER MARRIED");
				} else if (demoInfo.getMaritalStatus().equalsIgnoreCase("L")) {
					marStatus.addContent("SEPARATED");
				} else if (demoInfo.getMaritalStatus().equalsIgnoreCase("W")) {
					marStatus.addContent("WIDOWED");
				} else if (demoInfo.getMaritalStatus().equalsIgnoreCase("D")) {
					marStatus.addContent("DIVORCED");
				}

				root.addContent(marStatus);
			} //end marital status

			//PF
			Element facility = new Element("MedCenter");
			if (!isProd) {
				facility.addContent("999");
			} else {
				facility.addContent(demoInfo.getPreferredFacility());
			}
			root.addContent(facility);
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA Demographics", ex);
		}

	}

	private boolean isRace(String race, List<String> races) {
		Iterator<String> raceIter = races.iterator();

		while (raceIter.hasNext()) {
			String racestring = raceIter.next();
			if (racestring.equalsIgnoreCase(race)) {
				return true;
			}

		}
		return false;
	}

	//submission id - SID
	private void setSid(Element root, String sid) {
		try {
			Element submitId = new Element("SID");
			submitId.addContent(sid);
			root.addContent(submitId);

			Element resendId = new Element("Resend");
			resendId.addContent("N");
			root.addContent(resendId);

			Element confirm = new Element("Confirm");
			confirm.addContent("VAToPrint");
			root.addContent(confirm);

			Element version = new Element("formVersion");
			version.addContent("19");
			root.addContent(version);
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA SID", ex);
		}

	}

	//Convert PersonInfo traits to flat individual elements
	private void setPersonInfo(Element root, PersonInfo personInfo) {

		try {
			//last name
			Element lName = new Element("VetNameLast");
			lName.addContent(personInfo.getLastName());
			root.addContent(lName);

			//first name
			Element fName = new Element("VetNameFirst");
			fName.addContent(personInfo.getFirstName());
			root.addContent(fName);

			//middle name
			Element mName = new Element("VetNameMiddle");
			mName.addContent(personInfo.getMiddleName());
			root.addContent(mName);

			//suffix
			if (personInfo.getSuffix() != null) {
				Element nameSuffix = new Element("VetNameSuffix");
				nameSuffix.addContent(personInfo.getSuffix());
				root.addContent(nameSuffix);
			}

			//MotherMaidenName
			Element maidenName = new Element("MotherMaidenName");
			String mmn = personInfo.getMothersMaidenName();
			if (mmn != null && mmn.length() > 35) mmn = mmn.substring(0, 35);
			maidenName.addContent(mmn);
			root.addContent(maidenName);

			//Gender
			Element gender = new Element("Gender");
			gender.addContent(personInfo.getGender());
			root.addContent(gender);

			//VetSocialSecurityNumber
			Element ssn = new Element("VetSocialSecurityNumber");
			String vetSSN = String.format("%s-%s-%s", personInfo.getSsnText().substring(0, 3), personInfo.getSsnText().substring(3, 5),
					         personInfo.getSsnText().substring(5, 9));
			ssn.addContent(vetSSN);
			root.addContent(ssn);

			//DateOfBirth
			Element dob = new Element("DateOfBirth");
			dob.addContent(personInfo.getDob());
			root.addContent(dob);

			//birth city
			Element birthCity = new Element("PlaceOfBirthCity");
			String pobCity = personInfo.getPlaceOfBirthCity();
			if (pobCity != null && pobCity.length() > 20) pobCity = pobCity.substring(0, 20);
			birthCity.addContent(pobCity);
			root.addContent(birthCity);

			//bith state
			Element birthState = new Element("PlaceOfBirthState");
			String pobState = personInfo.getPlaceOfBirthState();
			if (pobState != null && pobState.length() > 2) pobState = pobState.substring(0,2);
			birthState.addContent(pobState);
			root.addContent(birthState);
		} catch (Exception ex) {
			logger.error("Unknown error translating VOA PersonInfo", ex);
		}


	}


}
