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

// Java classes

// Library classes
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang.Validate;

// Framework classes
import gov.va.med.fw.validation.ValidationFieldMessage;
import gov.va.med.fw.validation.ValidationMessage;
import gov.va.med.fw.validation.ValidationMessages;

// ESR classes
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.util.RuleAbstractTestCase;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.ee.Eligibility;
import gov.va.med.esr.common.model.ee.MilitaryService;
import gov.va.med.esr.common.model.ee.MilitaryServiceEpisode;
import gov.va.med.esr.common.model.ee.MilitaryServiceSiteRecord;
import gov.va.med.esr.common.model.lookup.EligibilityType;
import gov.va.med.esr.common.model.lookup.ServiceBranch;
import gov.va.med.esr.common.rule.service.impl.RuleValidationMessage;
import gov.va.med.esr.common.model.lookup.ServicePeriod;
import gov.va.med.esr.common.model.lookup.VAFacility;

/**
 * Provides methods to test rules in MSEValidation.irl
 *
 * Project: Common</br>
 * Created on: 4:44:12 PM </br>
 *
 * @author DNS   LEV
 */
public class MSEValidationServiceTest extends RuleAbstractTestCase {

	/**
	 * An instance of onFile
	 */
	private Person onFile = null;

	/**
	 * constructor
	 */
	public MSEValidationServiceTest(String testName) throws Exception {
		super(testName);
	}

	/** Tests IsBOSInvalidForWWII BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testIsBOSInvalidForWWII() throws Exception {
		
		/**
		 * IF the received Branch Of Service for the veteran is provided 
		 * AND ( The received Branch Of Service for the veteran is equal to F.Commonwealth OR 
		 * The received Branch of Service for the veteran is equal to F.Guerilla OR 
		 * The received Branch of Service for the veteran is equal to F.Scouts New OR 
		 * The received Branch of Service for the veteran is equal to F.Scouts Old ) 
		 * AND The received service entry date for the veteran is provided 
		 * AND The received service separate date for the veteran is provided 
		 * AND ( The received service entry date for the veteran is less than the Start date of  WWII service period OR 
		 * The received  service separation date for the veteran is greater than the end date of the WWII service period )
		 * THEN 
		 * Generate Error message “Branch of service selections of F. Commonwealth, F. Guerilla F. Scout New, F Scout Old 
		 * require SED and SSD that fall within the World War II Period.” 
		 * 
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
	
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working, 
														  this.getServiceBranch( ServiceBranch.CODE_F_COMMONWEALTH ) );
		
		// Set separation date - Set end date to be after 12/31/1946
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 1948, 2, 1 ) );
		
		// Set entry date - Set start date to be before 12/7/1941
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1938, 2, 1 ) );
		
		// World War II – 12/7/1941- 12/31/1946
		ServicePeriod period = this.getLookupService().getServicePeriodByCode( ServicePeriod.CODE_WORLD_WAR_II.getName() );
		mse.getMilitaryServiceSiteRecord().setServicePeriod( period );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  			RuleValidationMessage.BRANCH_OF_SERVICE_REQUIRES_WWII_SERVICE_PERIOD.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isServiceDischargeTypeNotProvided BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisServiceDischargeTypeNotProvided() throws Exception {

		/**
		 * IF It is not true that 
		 * The received service discharge type for the veteran is provided 
		 * THEN Generate Erorr message 
		 * “Service Discharge Type is required information for the Military Episode.” 
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Expect a validation exception to throw
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setDischargeType( null );
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  			RuleValidationMessage.SERVICE_DISCHARGE_TYPE_REQUIRED.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSEDNotProvided BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSEDNotProvided() throws Exception {
	
		/**
		 * IF It is not true that 
		 * The received service entry date for the veteran is provided 
		 * THEN Generate AE "Service Entry Date is required information for the Military Service Episode."
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( null );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
								RuleValidationMessage.SERVICE_ENTRY_DATE_REQUIRED.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSSDInTheFuture BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSSDInTheFuture() throws Exception {
	
		/** 3199[UC23.14.4] 
		 * The Service Separation Date cannot be a future date. 
		 * 
		 * 3200[UC23.14.4.1] 
		 * If the actor enters an incorrect date the system displays this message: 
		 * "Service Separation Date cannot be a future date."
		 * 
		 * =================== 
		 * IF The received service separation date for the veteran is provided 
		 * AND The received service separation date for the veteran is in the future 
		 * THEN Generate Error Message "Service Separation Date cannot be a future date." 
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2000, 9, 23 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2006, 9, 23 ) );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
								RuleValidationMessage.INVALID_FUTURE_SEPARATION_DATE.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSSDGreaterThanDateofDeath BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSSDGreaterThanDateofDeath() throws Exception {
		
		/** 3197[UC23.14.3] 
		 * The Service Separation Date must be prior to or equal to the Date of Death.
		 * 
		 * 3198[UC23.14.3.1] 
		 * If the actor enters an incorrect date the system displays this message: 
		 * "Service Separation Date must be prior to the Date of Death."
		 * 
		 * =========== 
		 * IF The received service separation date for the veteran is provided 
		 * AND The veteran has date of death information is TRUE 
		 * AND The received service separation date for the veteran is greater than the veteran’s date of death 
		 * THEN Generate Error message "Service Separation Date must be prior to the Date of Death."
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Create a start date after a date of death
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1998, 9, 23 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 9, 23 ) );
		working.setDeathRecord( this.createDeathRecord() ); // Death record is in 2000
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.INVALID_SERVICE_SEPARATION_DATE_AFTER_ON_DOD.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSSDGreaterThanDateofDeath BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSEDNotGreaterThan15BirthDate() throws Exception {
		
		/** isSEDNotGreaterThan15BirthDate
		 * 3185[UC23.13.2]  
		 * Service Entry Date must be greater than or equal to the veteran’s birth date + 15 years. 
		 *
		 * 3186[UC23.13.3]
		 * If the actor enters an incorrect date the system displays this message:
		 * "The Service Entry Date must be greater than or equal to the veteran’s birth date + 15 years." 
		 * =========
		 * IF The received service entry date is provided
		 * AND The received service entry date for the veteran is less than 
		 * the veteran’s date of birth plus 15 years
		 * THEN 	Generate AE "The Service Entry Date must be greater than or 
		 * equal to the veteran’s birth date + 15 years."
		 */

		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		working.setBirthRecord( this.createBirthRecord( ImpreciseDateUtils.createImpreciseDate( 1980, 9, 23 ) ) );
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Create a start date after a date of death
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1992, 9, 23 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 9, 23 ) );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.INVALID_SERVICE_ENTRY_DATE_LESS_THAN_15TH_BIRTHDAY.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSEDInTheFuture BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSEDInTheFuture() throws Exception {
		
		/** 
		 * isSEDInTheFuture - 
		 * 
		 * 3191[UC23.13.6] 
		 * The Service Entry Date cannot be a future date. 
		 * 
		 * 3192[UC23.13.6.1] 
		 * If the actor enters an incorrect date the system displays this message: 
		 * "Service Entry Date cannot be a future date."
		 * 
		 * ====== 
		 * IF The received service entry date is provided 
		 * AND The received service entry date is in the future 
		 * THEN Generate Error Message "Service Entry Date cannot be a future date."
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Create a start date after a date of death
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2009, 9, 23 ) );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2006, 9, 23 ) );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  			RuleValidationMessage.INVALID_FUTURE_SERVICE_ENTRY_DATE.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSEDGreaterThanSSD BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSEDGreaterThanSSD() throws Exception {

		/** 
		 * 3187[UC23.13.4] 
		 * The Service Entry Date must be prior to or equal to the Service 
		 * Separation Date (SSD) for the Military Service Episode (MSE).
		 * 
		 * 3188[UC23.13.4.1] 
		 * If the actor enters a date that falls after the SSD the system displays this message: 
		 * "The Service Entry Date must be prior to the Service Separation Date for the Military Service Episode."
		 * 
		 * ================ 
		 * IF The received service entry date for the veteran is provided 
		 * AND The received service separation date for the veteran is provided 
		 * AND The received service entry date for the veteran is greater than 
		 * the received service separation date for the veteran 
		 * THEN Generate AE "The Service Entry Date must be prior to the Service Separation 
		 * Date for the Military Service Episode."
		 */		
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();

		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Create a start date after a date of death
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2002, 9, 23 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2001, 9, 23 ) );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.INVALD_SERVICE_ENTRY_DATE_AFTER_SEPARATION_DATE.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSEDGreaterThanDateOfDeath BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSEDGreaterThanDateOfDeath() throws Exception {
	
		/** 3189[UC23.13.5] 
		 * The Service Entry Date must be prior to or equal to the Date of Death 
		 * 
		 * 3190[UC23.13.5.1] 
		 * if the actor enters an incorrect date the system displays this message: 
		 * "Service Entry Date must be prior to the Date of Death."
		 * 
		 * ======= 
		 * IF The received service entry date is provided 
		 * AND The veteran has date of death information is TRUE 
		 * AND The received service entry date is greater than the veteran’s date of death 
		 * THEN Generate Error Message "Service Entry Date must be prior to the Date of Death."
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();

		// Create a military service record
		MilitaryServiceEpisode mse = 
			this.attachMilitaryServiceEpisode( working ); 

		// Create a start date after a date of death
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 9, 23 ) );

		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 9, 23 ) );
		working.setDeathRecord( this.createDeathRecord() ); // Death record is in 2000
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
								RuleValidationMessage.INVALID_SERVICE_ENTRY_DATE_ON_AFTER_DOD.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isOverlappingMSE BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisOverlappingMSE() throws Exception {
		
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();

		// Create a military service
		MilitaryService ms = new MilitaryService();
		
		MilitaryServiceSiteRecord mssr = new MilitaryServiceSiteRecord();
		mssr.setSite( this.getVaFacility( VAFacility.CODE_HEC ) );
		
		// Create 2 mes for a period from 02/20/1968 to 04/30/1990
		MilitaryServiceEpisode mse = new MilitaryServiceEpisode();
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1968,2,20) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 1975,4,30) );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setServiceBranch( this.getRandomServiceBranch() );
		mssr.addMilitaryServiceEpisode( mse );
		
		mse = new MilitaryServiceEpisode();
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1978,2,20) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 1990,4,30) );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setServiceBranch( this.getRandomServiceBranch() );
		mssr.addMilitaryServiceEpisode( mse );

		// Create an overlapping mse here 02/20/1970 to 04/30/1980
		mse = new MilitaryServiceEpisode();
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 1974,2,20) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 1980,4,30) );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setServiceBranch( this.getRandomServiceBranch() );
		mssr.addMilitaryServiceEpisode( mse );

		ms.addMilitaryServiceSiteRecord( mssr );
		working.setMilitaryService( ms );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
							  RuleValidationMessage.INVALID_CURRENT_MSE_OVERLAPS_MSE.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isMilDisabilityRetireSCLessThan10 BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisMilDisabilityRetireSCLessThan10() throws Exception {
		/** 
		 * 4081[UC23.28] 
		 * Military Disability Retirement cannot be YES unless the SC% is 10% or greater. 
		 * If the criteria for Military Disability Retirement are not met the system displays this message:
		 * "Military Disability Retirement cannot be YES unless the SC% is 10% or greater."
		 * 
		 *  IF The received military disability retirement indicator is YES
		 *  AND The service connected percent for the veteran is less than 10 %
		 *  THEN Generate Error Message 
		 *  "Military Disability Retirement cannot be YES unless SC% is 10% or greater"
		 **/
		// Persist a person so we will have a record on file
		// Create a service connection award less than 10
		this.attachServiceConnectionAward( onFile, new Integer(5) );
		
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();

		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );
		working.getMilitaryService().setDisabilityRetirementIndicator( Boolean.TRUE );

		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.INVALID_MILITARY_DISABILITY_RETIREMENT_SC_LESS_10.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isMilDisabilityRetireNSC BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisMilDisabilityRetireNSC() throws Exception {
		
		/** 
		 * 4041[UC23.27]
		 * The system must prohibit the saving a record 
		 * when the actor sets the Military Disability Retirement to YES 
		 * when the Veteran has NSC as the Primary Eligibility Code.  
		 * A Warning Message shall be displayed to the user. 
		 * 
		 * IF the received military disability retirement indicator is YES 
		 * AND The primary eligibility code for the veteran is NSC 
		 * THEN Generate Error Message 
		 * "Military Disability Retirement cannot be YES with Primary Eligibility Code of NSC."
		 **/
		
		// Persist a person so we will have a record on file
		EnrollmentDetermination enrollment = this.createEnrollmentDetermination();
		Eligibility primary = new Eligibility();
		primary.setType( this.getLookupService().getEligibilityTypeByCode( EligibilityType.NSC.getName() ) );
		enrollment.setPrimaryEligiblity( primary );
		onFile.setEnrollmentDetermination( enrollment );
		
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );

		working.getMilitaryService().setDisabilityRetirementIndicator( Boolean.TRUE );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.INVALID_MILITARY_DISABILITY_RETIREMENT_WITH_NSC.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests IsFilipinoProofRequired BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testIsFilipinoProofRequired() throws Exception {
		
		/**  
		 * 3247[UC23.18] Filipino Veteran Proof 
		 * 
		 * The actor must enter the Filipino Veteran Proof if the veteran Branch of Service 
		 * is any of the following:
		 * F. Commonwealth
		 * F. Guerilla
		 * F. Scouts New
		 * 
		 * 3248[UC23.18.1]
		 * If the actor does not enter the Filipino Veteran Proof the system displays this message: 
		 * "The Filipino Veteran Proof is required information for these Branches of Service: 
		 * F. Commonwealth, F. Guerilla, and F. Scouts New."
		 * 
		 * ==============
		 * IF the received branch of service is provided 
		 * AND 
		 * ( The received branch of service for the veteran is F.Commonwealth OR 
		 * The received branch of service for the veteran is F.Guerilla OR 
		 * The received branch of service for the veteran is  F.Scouts New ) 
		 * AND It is not true that the The received Filipino Veteran Proof for the veteran is provided 
		 * 
		 * THEN Generate AE "The Filipino Veteran Proof is required information for these Branches of Service: 
		 * F. Commonwealth, F. Guerilla, and F. Scouts New."
		 */	
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
	
		// Create a military service record
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working, 
													  this.getServiceBranch( ServiceBranch.CODE_F_COMMONWEALTH ) );
		
		// There is only one site record so there is no need to check
		MilitaryServiceSiteRecord mssr = mse.getMilitaryServiceSiteRecord(); 
		
		// Set Filipino proof to null
		mssr.setFilipinoVeteranProof( null );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.FILIPINO_VETERAN_PROOF_REQUIRED.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isBranchOfServiceNotProvided BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisBranchOfServiceNotProvided() throws Exception {
		
		/** 3201[UC23.15] Branch Of Service 
		 * Branch of Service is a required entry for each military service episode. 
		 * 
		 * 3202[UC23.15.1] 
		 * If the actor does not enter the Branch of Service the system displays this message: 
		 * "Branch of Service is required information for the Military Episode." 
		 * 
		 * =============== 
		 * IF the received branch of service for the veteran is not provided 
		 * THEN generate an AE with the description that "branch of service is a required field"
		 **/
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
	
		// Create a military service record
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setServiceBranch( null );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
					  RuleValidationMessage.BRANCH_OF_SERVICE_REQUIRED.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests isSSDLessThanSED BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSSDLessThanSED() throws Exception {
		
		/** 3195[UC23.14.2] 
		 * Service Separation Date must be later than the Service Entry Date 
		 * 
		 * 3196[UC23.14.2.1] 
		 * If the actor enters an incorrect date the system displays this message: 
		 * "Service Separation Date must be later than the Service Entry Date."
		 * 
		 * ========== 
		 * IF The received service separation date is provided 
		 * AND The received service entry date is provided 
		 * AND The received service separation date for the veteran is less than 
		 * the received service entry date for the veteran
		 * THEN Generate Error Message "Service Separation Date must be later than the Service Entry Date."
		 */
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
		
		// Create a military service record
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setDischargeType( this.getRandomDischargeType() );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2002, 10, 10 ) );
		
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
							  RuleValidationMessage.INVALD_SERVICE_ENTRY_DATE_AFTER_SEPARATION_DATE.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}

	/** Tests isSSDNotProvided BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testisSSDNotProvided() throws Exception {
		
		/** 3193[UC23.14] 
		 * Service Separation Date (SSD) 
		 * Service Separation Date is a required entry for each military service episode. 
		 * 
		 * 3194[UC23.14.1] 
		 * If the actor does not enter the Service Separation Date the system displays this message: 
		 * "Service Separation Date is required information for the Military Service Episode."
		 * 
		 * IF It is not true that the received service separate date of the veteran is provided
		 * THEN generate an AE message with the description that SSD is required
		 **/	
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );

		// Create a military service record
		Person working = (Person)pristine.clone();
		
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setEndDate( null );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 1) );
			assertEquals( ((ValidationFieldMessage)messages.get().next()).getKey(), 
							  RuleValidationMessage.SERVICE_SEPARATION_DATE_REQUIRED.getName() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests SEDIsNotPrecise BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testSEDIsNotPrecise() throws Exception {
		
		/** SEDIsNotPrecise
		 * 
		 * 3179[UC23.12.3] 
		 * All dates in the Military Service Episodes must be precise. 
		 * 
		 * 3182[UC23.12.4] 
		 * If the Military Episode Dates entered do not meet the date requirement 
		 * the system displays this message: "Military Service Episode Dates must be precise."
		 * 
		 * IF the received service entry date for the veteran is provided
		 * AND It is not true that the received service entry date for the veteran is precise 
		 * THEN Generate AE "Military Service Episode Dates must be precise."
		 **/		
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );

		// Create a military service record
		Person working = (Person)pristine.clone();

		// Create a military service record
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( messages.isEmpty() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/** Tests SSDisNotPrecise BAL rule in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testSSDisNotPrecise() throws Exception {
		
		/** SSDisNotPrecise - 
		 * 3179[UC23.12.3] 
		 * All dates in the Military Service Episodes must be precise. 
		 * 
		 * 3182[UC23.12.4] 
		 * If the Military Episode Dates entered do not meet the date requirement 
		 * the system displays this message: "Military Service Episode Dates must be precise."
		 * 
		 * IF the received service separate date for the veteran is provided
		 * AND It is not true that the received service separate date for the veteran is precise 
		 * THEN Generate AE "Military Service Episode Dates must be precise."
		 **/		
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );

		// Create a military service record
		Person working = (Person)pristine.clone();

		// Create a military service record
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		mse.setStartDate( ImpreciseDateUtils.createImpreciseDate( 2001, 10, 10 ) );
		mse.setEndDate( ImpreciseDateUtils.createImpreciseDate( 2003, 10, 10 ) );
		mse.setDischargeType( this.getRandomDischargeType() );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, false );
			
			assertTrue( messages.isEmpty() );
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}

	/** Tests multiple validation error messages (for UI) in MSEValidation.irl
	 * @throws Exception Thrown in case of errors
	 */
	public void testMSEValidation() throws Exception {
	    /**
	     * This is to test multiple validation error messages.
	     * 
	     * Create an empty MSE without populating any fields and call the RuleValidationService. It should return
	     * back the following 3 validation error messages.
	     * SERVICE_ENTRY_DATE_REQUIRED
	     * SERVICE_SEPARATION_DATE_REQUIRED
	     * SERVICE_DISCHARGE_TYPE_REQUIRED
	     */
		// Persist a person so we will have a record on file
		Person pristine = this.getPersonService().save( onFile );
		
		// Create a military service record
		Person working = (Person)pristine.clone();
	
		// Create a military service record with a random branch of service.
		MilitaryServiceEpisode mse = this.attachMilitaryServiceEpisode( working );
		
		try {
			ValidationMessages messages = 
				this.getRuleValidationService().validateMSE( mse, working, pristine, true );
			
			assertTrue( !messages.isEmpty() );
			assertTrue( (messages.getCount() == 3) );
			
			//Put all the message keys in a set
			Set msgKey = new HashSet();
			for(Iterator iter=messages.get(); iter.hasNext();)
			    msgKey.add(((ValidationMessage)iter.next()).getKey());
			
			//Service Entry Date is required
			assertTrue(msgKey.contains(RuleValidationMessage.SERVICE_ENTRY_DATE_REQUIRED.getName()));
			
			//Service Separation Date is required
			assertTrue(msgKey.contains(RuleValidationMessage.SERVICE_SEPARATION_DATE_REQUIRED.getName()));
			
			//Service Discharge type is required
			assertTrue(msgKey.contains(RuleValidationMessage.SERVICE_DISCHARGE_TYPE_REQUIRED.getName()));
			
		}
		catch( Exception e ) {
			if( logger.isDebugEnabled() ) {
				logger.debug( "Got an un-expected validation exception ", e );
			}
			this.fail( "Got an un-expected validation exception", e );
		}
	}
	
	/**
	 * @see gov.va.med.fw.util.AbstractTestCase#customSetUp()
	 */
	protected void customSetUp() throws Exception {
		super.customSetUp();
		onFile = this.buildSimplePerson();
	}

	/**
	 * @see gov.va.med.fw.util.AbstractTestCase#customTearDown()
	 */
	protected void customTearDown() throws Exception {
		super.customTearDown();
		onFile = null;
	}

	/**
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull(this.getRuleValidationService(), "A rule validation service is required");
	}
}