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

// Java classes
import java.util.Calendar;
import java.util.Set;
import java.util.Date;

// ESR classes
import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.lookup.AddressType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.util.RuleAbstractTestCase;


/**
 * @author VHAIVMNgVS (refactored by Carlos Ruiz)
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public class ProcessAddressTest extends RuleAbstractTestCase {

    private Person onFilePerson = null;
    
    public ProcessAddressTest(String testName) {
        super(testName);
    }
    
    protected void customSetUp() throws Exception {
        super.customSetUp();
        onFilePerson = this.buildSimplePerson();
        this.getPersonService().save(onFilePerson);
    }    

    /**
     * 1. Rule Name: AddressIsDeleted If an incoming message’s address is
     * deleted and a veteran has a matching address record then set a veteran’s
     * matching address’s end date to today.
     */
    public void testAddressIsDeleted() throws Exception {
        addTwoAddresses(onFilePerson, this.getDate(1975, 3, 1));        
        this.getPersonService().save(onFilePerson);
        Person incomingPerson = (Person)onFilePerson.clone();
        incomingPerson.removeAllAddresses();
        
        // Add expired address
        Address delete = (Address)(Address.getAddressOfType(onFilePerson.getAddresses(), AddressType.CODE_PERMANENT_ADDRESS.getName())).clone();
        delete.setEndDate(ImpreciseDateUtils.createImpreciseDate(2005, 8, 20));
        incomingPerson.addAddress(delete);

        assertEquals(onFilePerson.getAddresses().size(), 2);

        // Run the rules
        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);

        // Check the results.  The end date should be set
        this.assessExpiredAddressResults(AddressType.CODE_PERMANENT_ADDRESS.getName(), incomingPerson, onFilePerson);
    }

    /**
     * 2. Rule Name: AddressIsNew if an incoming message’s address type and date
     * are valid and a veteran doesn’t have a matching address then create a
     * veteran’s address with data coming from an incoming message’s address
     */
    public void testAddressIsNew() throws Exception {
        Person incomingPerson = (Person) onFilePerson.clone();

        this.addPermanentAddress(incomingPerson, Calendar.getInstance()
                .getTime(), null);

        assertEquals(onFilePerson.getAddresses().size(), 0);

        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);

        assertEquals(onFilePerson.getAddresses().size(), 1);

        this.assessAddressResults(AddressType.CODE_PERMANENT_ADDRESS.getName(), incomingPerson, onFilePerson);

    }

    /**
     * Rule Name: AddressIsMoreRecent if an incoming message’s address’s updated
     * date is more recent than a veteran’s address’s updated date then update a
     * veteran’s address with data coming from an incoming message’s address
     */
    public void testTemporaryAddressIsMoreRecent() throws Exception {
        addTwoAddresses(onFilePerson, this.getDate(1975, 3, 1));        
        this.getPersonService().save(onFilePerson);
        Person incomingPerson = (Person)onFilePerson.clone();

        incomingPerson.removeAllAddresses();
        AddressType addressType = this.getLookupService().getAddressTypeByCode(AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName());
        Address incoming = this.createAddress(addressType);
        incoming.setChangeDate(this.getDate(2005, 3, 1));
        incomingPerson.addAddress(incoming);

        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);

        assertEquals(onFilePerson.getAddresses().size(), 3);
        
        this.assessAddressResults(AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName(), incomingPerson, onFilePerson);
    }


    //testTemporaryAddressIsEmptyInactiveAndNoMatching
    public void testTemporaryAddressIsEmptyInactiveAndNoMatching() throws Exception {
        //addTwoAddresses(onFilePerson, this.getDate(1975, 3, 1));        
        //this.getPersonService().save(onFilePerson);
    	PersonEntityKey personId = CommonEntityKeyFactory.createPersonIdEntityKey("5850");
    	Person onFilePerson = getPersonService().getPerson(personId);
        Person incomingPerson = (Person)onFilePerson.clone();

        //incomingPerson.removeAllAddresses();
        AddressType addressType = this.getLookupService().getAddressTypeByCode(AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName());
        Address incoming = this.createAddress(addressType);
        //incoming.setType();
        //incoming.setChangeDate(this.getDate(2005, 3, 1));
        incoming.setChangeDate(null);
        incoming.setStartDate(new ImpreciseDate("19850101"));
        incoming.setEndDate(new ImpreciseDate("19851001"));
        incoming.setActive(false);
        incomingPerson.addAddress(incoming);

        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);

        assertEquals(onFilePerson.getAddresses().size(), 2);
        
        this.assessAddressResults(AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName(), incomingPerson, onFilePerson);
    }
    
    
    
    /**
     * 4. Rule Name: AddressIsNull if an incoming message’s address’s updated
     * date is NULL and a veteran’s address updated date is NULL then update a
     * veteran’s address with data coming from an incoming message’s address
     */
    public void testAddressIsNull() throws Exception
    {
        Address address = createAddress("Cobb Parkway", "Windy Hill", "GA",
				"30338", this.getDate(1975, 3, 1), AddressType.CODE_PRIMARY_RESIDENCE.getName());
        address.setChangeDate(null);
		Address secondAddress = createAddress("Coca Cola Museum", "Five points",
				"GA", "30339", this.getDate(1975, 3, 1), AddressType.CODE_PERMANENT_ADDRESS.getName());
		secondAddress.setChangeDate(null);
		
		onFilePerson.addAddress(address);
		onFilePerson.addAddress(secondAddress);
        
        this.getPersonService().save(onFilePerson);
        
        Person incomingPerson = (Person)onFilePerson.clone();
        incomingPerson.removeAllAddresses();
        
        // Add expired address
        Address delete = (Address)(Address.getAddressOfType(onFilePerson.getAddresses(), AddressType.CODE_PERMANENT_ADDRESS.getName())).clone();
        //delete.setEndDate(this.createImpreciseDate(2005, 8, 20));
        delete.setChangeDate(null);
        incomingPerson.addAddress(delete);

        assertEquals(onFilePerson.getAddresses().size(), 2);

        // Run the rules
        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);
    }

    /**
     * Rule Name: AdddressTypeIsPermanentAndActive: if an in coming message’s
     * address type is permanent and an in coming message’s last updated date is
     * more recent than a veteran’s address’s last updated date then update a
     * veteran’s spouse and dependent’s address with data coming from an in
     * coming message’s address and update a veteran’s address with data coming
     * from a message.
     */
    public void testAdddressTypeIsPermanentAndActive() throws Exception {
        addTwoAddresses(onFilePerson, this.getDate(1975, 3, 1));        
        this.getPersonService().save(onFilePerson);        
        Person incomingPerson = (Person) onFilePerson.clone();

        this.addPermanentAddress(incomingPerson, Calendar.getInstance()
                .getTime(), null);

        assertEquals(onFilePerson.getAddresses().size(), 1);

        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);

        assertEquals(onFilePerson.getAddresses().size(), 2);

        this.assessAddressResults(AddressType.CODE_PERMANENT_ADDRESS.getName(), incomingPerson, onFilePerson);
    }

    /**
     * 5. Rule Name: AddressIsUSA if an incoming message’s address’s state code
     * is valid (a valid US state code) then set a veteran’s address’s state
     * code to an incoming message’s address’s state code and set a veteran’s
     * address’s zip code to an incoming message’s address’s zip code else set a
     * veteran’s province to an in coming message’s address’s state code and set
     * a veteran’s postal code to an in coming’s address’s zip code
     * 
     */
    public void testAddressIsUSA() {
    // NOT needed
    }
    
    public void testAddressTypeTemp() {
        
    }
    
    public void testAddressTypeConfidentialExisting() throws Exception {
    	Person onFilePerson = this.buildSimplePerson();
        Address address = createAddress("Cobb Parkway", "Windy Hill", "GA",
				"30338", this.getDate(1975, 3, 1), AddressType.CODE_CONFIDENTIAL_ADDRESS.getName());
        address.setChangeDate(this.getDate(2001, 3, 1));
        address.setStartDate(ImpreciseDateUtils.createImpreciseDate(2001, 3, 1));
		Address secondAddress = createAddress("Coca Cola Museum", "Five points",
				"GA", "30339", this.getDate(1975, 3, 1), AddressType.CODE_PERMANENT_ADDRESS.getName());
		secondAddress.setChangeDate(this.getDate(1975, 3, 1));
		secondAddress.setStartDate(ImpreciseDateUtils.createImpreciseDate(1975, 3, 1));
		onFilePerson.addAddress(address);
		onFilePerson.addAddress(secondAddress);
        
        this.getPersonService().save(onFilePerson);
        
        Person incomingPerson = (Person)onFilePerson.clone();
        incomingPerson.removeAllAddresses();
        Address modify = (Address)address.clone();
        String newLine1 = "NEW INFO"; //gets made upper case by the setter
        modify.setLine1(newLine1);
		modify.setStartDate(ImpreciseDateUtils.createImpreciseDate(2009, 6, 20));
        modify.setChangeDate(new Date());
        incomingPerson.addAddress(modify);
        
        // Run the case where Edit an existing Confidential Address
        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);
        assertEquals("size should be 2",onFilePerson.getAddresses().size(), 2);        
        Address result = (Address.getAddressOfType(onFilePerson.getAddresses(), AddressType.CODE_CONFIDENTIAL_ADDRESS.getName()));
        assertTrue("line1 should be updated to new value",newLine1.equals(result.getLine1()));
        assertNull("end date of updated address should be null",result.getEndDate());
        
        // Run the case where delete the Confidential Address
        incomingPerson.removeAllAddresses();
        modify = (Address)address.clone();
		modify.setStartDate(null);
		modify.setEndDate(null);
        modify.setChangeDate(new Date());
        incomingPerson.addAddress(modify);
        
        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);
        assertEquals("size should be 2",onFilePerson.getAddresses().size(), 2);        
        result = (Address.getAddressOfType(onFilePerson.getAddresses(), AddressType.CODE_CONFIDENTIAL_ADDRESS.getName()));
        assertNotNull("result should be null", result);
        assertNotNull("end date of updated address should not be null", result.getEndDate());
    }
    
    public void testAddressTypeConfidentialNew() throws Exception {
    	Person onFilePerson = this.buildSimplePerson();
		Address secondAddress = createAddress("Coca Cola Museum", "Five points",
				"GA", "30339", this.getDate(1975, 3, 1), AddressType.CODE_PERMANENT_ADDRESS.getName());
		secondAddress.setChangeDate(this.getDate(1975, 3, 1));
		secondAddress.setStartDate(ImpreciseDateUtils.createImpreciseDate(1975, 3, 1));
		onFilePerson.addAddress(secondAddress);
        
        this.getPersonService().save(onFilePerson);
        
        Person incomingPerson = (Person)onFilePerson.clone();
        incomingPerson.removeAllAddresses();
        Address conf = createAddress("Cobb Parkway", "Windy Hill", "GA",
				"30338", this.getDate(1975, 3, 1), AddressType.CODE_CONFIDENTIAL_ADDRESS.getName());
		conf.setStartDate(ImpreciseDateUtils.createImpreciseDate(2009, 6, 20));
        conf.setChangeDate(new Date());
        incomingPerson.addAddress(conf);
        
        // Run the rules
        this.executeProcessAddress(incomingPerson.getAddresses(), onFilePerson);
        assertEquals("size should be 2",onFilePerson.getAddresses().size(), 2);        
        Address result = (Address.getAddressOfType(onFilePerson.getAddresses(), AddressType.CODE_CONFIDENTIAL_ADDRESS.getName()));
        assertNull("end date of updated address should be null",result.getEndDate());
    }
    
 
    protected void executeProcessAddress(Set addresses, Person resultPerson)
            throws Exception {
        this.getContactInfoRuleService().processAddresses(addresses,
                resultPerson, getLookupService().getVaFacilityByCode(VAFacility.CODE_ALBUQUERQUE.getCode()));
    }
}