package gov.va.med.esr.service;



// Java classes
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;

// Library classes

// Framework classes

// ESR classes
import gov.va.med.esr.service.CommsLogService;
import gov.va.med.esr.common.model.lookup.AddressType;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType.Code;
import gov.va.med.esr.common.model.lookup.ComMailingStatusType;
import gov.va.med.esr.common.model.lookup.CorrespondenceStatus;
import gov.va.med.esr.common.model.lookup.CorrespondenceType;
import gov.va.med.esr.common.model.lookup.TransmissionStatus;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.clock.Clock;
import gov.va.med.esr.common.util.RuleAbstractTestCase;
import gov.va.med.esr.common.model.comms.CommsLogEntry;
import gov.va.med.esr.common.model.comms.Correspondence;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.persistent.comms.CommsLogEntryDAO;
import gov.va.med.esr.common.rule.service.RuleValidationService;

/**
 * @author DNS   RUIZC
 * @version 1.0
 */
public class CommsLogServiceTest extends RuleAbstractTestCase {
    private CommsLogService commsLogService = null;
    private CorrespondenceService correspondenceService = null;
    private CommsLogEntryDAO commsLogEntryDAO = null;
    private RuleValidationService ruleValidationService = null;

    public CommsLogServiceTest(String testName) {
        super(testName);
    }

    public void testInsertNewCorrespondence() throws Exception {
    	/*Person onFile = this.buildSimplePerson();
    	Correspondence c = new Correspondence(onFile);

    	//c.setAddress(onFile.getPermanentAddress());
    	c.setCorrespondenceStatus((CorrespondenceStatus)this.getLookupService().getByCode(
    			CorrespondenceStatus.class, CorrespondenceStatus.MAILED_BY_CMS.getCode()));
    	c.setCorrespondenceType((CorrespondenceType)this.getLookupService().getByCode(
    			CorrespondenceType.class, CorrespondenceType.CMS_MAILING.getCode()));
    	c.setErrorDescription("i said so");
    	c.setStatusDate(new Date());
    	c.setEffectiveDate(new Date());


    	Code type = ComLetterTemplateType.FORM_NUMBER_800D;*/

    	//this.getCorrespondenceService().insertNewCorrespondence(c, type);

    }

    public void testGetCommsLogEntries() throws Exception {
    	String form = ComLetterTemplateType.FORM_NUMBER_455.getCode();
    	List<CommsLogEntry> list = this.getCommsLogEntryDAO().findCommsLogListByPersonId("377125257");
    	CommsLogEntry entry = this.getMostRecentCommsLogByFormWithCompleteIvmData(form, list);
    	if (entry != null)
    		System.out.println("most recent modified date="+entry.getModifiedOn());
    	else
    		System.out.println("no entry for the form type");
    }

    public void testGetMostRecentStatus() throws Exception {

    	CommsLogEntry entry = this.getCommsLogEntryDAO().findCommsLogEntryByBarcode("I14218");
    	System.out.println("status=" + entry.getLatestMailingStatus().getMailingStatus().getDescription());
    	System.out.println("remail=" + entry.isEligibleForRemail());

    }

    private CommsLogEntry getMostRecentCommsLogByFormWithCompleteIvmData(String form, List<CommsLogEntry> list) {
    	if (form == null || list == null || list.size() == 0) {
    		return null;
    	}
       	List<CommsLogEntry> filteredList = new ArrayList<CommsLogEntry>();
    	for (CommsLogEntry entry : list) {
    		if (form.equals(entry.getFormNumber()) &&
    				entry.getIvmCaseClosureDate() != null &&
    				entry.getIvmCaseNumber() != null) {
    			filteredList.add(entry);
    		}
    	}
    	Comparator comparator = new Comparator() {
    		public int compare(Object pObject1, Object pObject2)
    		{
    			CommsLogEntry entry1 = (CommsLogEntry)pObject1;
    			CommsLogEntry entry2 = (CommsLogEntry)pObject2;
    			if (entry1 == null || entry1.getModifiedOn() == null) return -1;
    			if (entry2 == null || entry2.getModifiedOn() == null) return 1;
    			return (entry2.getModifiedOn().compareTo(entry1.getModifiedOn()));
    		}
    	};

    	List<CommsLogEntry> orderedEntries = new ArrayList<CommsLogEntry>(filteredList);

    	Collections.sort(orderedEntries, comparator);
//    	for (CommsLogEntry entry : orderedEntries) {
//    		System.out.println("\n entry="+entry.getFormNumber());
//    		System.out.println("\n modified date="+entry.getModifiedOn());
//    	}
    	CommsLogEntry recent = null;
    	if (orderedEntries.size() > 0) {
    		recent = (CommsLogEntry)orderedEntries.get(0);
//    		System.out.println("\n most recent modified date=" + recent.getModifiedOn());
    	}
    	return recent;
    }

    public void testProcessAutomaticLetters_293() throws Exception {
        testProcessAutomaticLetters_290series(Clock.Type.SSN_30_DAY_PSEUDO_SSN_VERIFICATION_CLOCK);
    }

    public void testProcessAutomaticLetters_292() throws Exception {
        testProcessAutomaticLetters_290series(Clock.Type.SSN_30_DAY_PSEUDO_SSN_REASON_CLOCK);
    }

    public void testProcessAutomaticLetters_291() throws Exception {
        testProcessAutomaticLetters_290series(Clock.Type.SSN_30_DAY_VALIDATION_CLOCK);
    }

    private void testProcessAutomaticLetters_290series(Clock.Type type) throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        address.setChangeDate(this.getDate(2005,1,1));
        onFile.addAddress(address);
        Person incoming = savePerson(onFile);
        this.getCommsLogService().processAutomaticLetterRequests(incoming, type, "V");
    }

    public void testMailingResponse() throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        address.setChangeDate(this.getDate(2005,1,1));
        onFile.addAddress(address);
        Person incoming = savePerson(onFile);
        List  al = new ArrayList();
        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming,ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.setMailingDate(new Date());
        this.getCommsLogEntryDAO().insert(commsLogEntry);
        // Need to disconnect the object
        CommsLogEntry incomingEntry = (CommsLogEntry)commsLogEntry.clone();
        al.add(incomingEntry);
        this.getCommsLogService().handleMailingResponses(al);
    }

    public void testMailingResponseWithExistinPerson() throws Exception {
        List  al = new ArrayList();
        //20453230 comm id  20453227 pid
        CommsLogEntry commsLogEntry = (CommsLogEntry)this.getCommsLogEntryDAO().getByKey(
            CommonEntityKeyFactory.createCommsLogEntryEntityKey("20453230"));
        CommsLogEntry incomingEntry = (CommsLogEntry)commsLogEntry.clone();
        al.add(incomingEntry);

        this.getCommsLogService().handleMailingResponses(al);
    }


    public void createDataForMailingResponse() throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        address.setChangeDate(this.getDate(2005,1,1));
        onFile.addAddress(address);
        Person incoming = this.savePerson(onFile);
        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming,ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.setMailingDate(new Date());
        this.getCommsLogEntryDAO().insert(commsLogEntry);
        this.setComplete();
        System.out.println("person id=" + incoming.getEntityKey().getKeyValueAsString());
    }

    public void testUndeliverable_BadAddress() throws Exception {
        Person onFile = getPersonService().getPerson(
                CommonEntityKeyFactory.createPersonIdEntityKey("21336887"));
        List  al = new ArrayList();
        CommsLogEntry commsLogEntry = this.createCommsLogEntry(onFile,ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.setMailingDate(new Date());
        this.getCommsLogEntryDAO().insert(commsLogEntry);
        // Need to disconnect the object
        //CommsLogEntry incomingEntry = (CommsLogEntry)commsLogEntry.clone();
        //al.add(incomingEntry);
        al.add(commsLogEntry);
        //this.getCommsLogService().processUndeliverableMail(al);
        this.getCommunicationRuleService().handleUndeliverableMail(al);
    }
    public void testManageCommsLog_Permanent() throws Exception {
        Person onFile = this.buildSimplePerson();

        Address address = this.createPermanentAddress();
        onFile.addAddress(address);

        Person incoming = this.getPersonService().save(onFile);

        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming, ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.SEND_TO_AAC.getName()));
        this.getCommsLogEntryDAO().insert(commsLogEntry);

        // Simulate UI, which sends disconnected objects... use clone
        CommsLogEntry updated = (CommsLogEntry)commsLogEntry.clone();
        CommsLogEntry result = this.getCommsLogService().updateCommunicationLog(updated);
        assertNotNull(result);
    }

    public void testManageCommsLog_Cancel() throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        onFile.addAddress(address);

        Person incoming = this.getPersonService().save(onFile);

        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming, ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.SEND_TO_AAC.getName()));
        this.getCommsLogEntryDAO().insert(commsLogEntry);

        // Simulate UI, which sends disconnected objects... use clone
        CommsLogEntry updated = (CommsLogEntry)commsLogEntry.clone();
        updated.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.CANCEL_BY_HEC.getName()));
        this.getCommsLogService().updateCommunicationLog(updated);
        System.out.println("Log id=" + commsLogEntry.getCommsLogIdString());
    }

    public void testManageCommsLog_455_Cancel() throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        onFile.addAddress(address);

        Person incoming = this.getPersonService().save(onFile);

        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming, ComLetterTemplateType.FORM_NUMBER_455.getName());
        commsLogEntry.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.SEND_TO_CMS.getName()));
        this.getCommsLogEntryDAO().insert(commsLogEntry);

        CommsLogEntry log = getCommsLogService().getCommsLogEntry(CommonEntityKeyFactory.createCommsLogEntryEntityKey(
                commsLogEntry.getCommsLogIdString()));

        // Simulate UI, which sends disconnected objects... use clone [not really after looking at UI code]
        CommsLogEntry updated = log;//(CommsLogEntry)commsLogEntry.clone();
        updated.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.CANCEL_BY_HEC.getName()));
        CommsLogEntry result = this.getCommsLogService().updateCommunicationLog(updated);
        System.out.println("Log id=" + commsLogEntry.getCommsLogIdString());
        assertTrue(ComMailingStatusType.CANCEL_BY_HEC.getCode().equals(result.getLatestMailingStatus().getMailingStatus().getCode()));
    }
    public void testManageCommsLog_683A_Cancel() throws Exception {
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        onFile.addAddress(address);

        Person incoming = this.getPersonService().save(onFile);

        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming, ComLetterTemplateType.FORM_NUMBER_683A.getName());
        commsLogEntry.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.SEND_TO_CMS.getName()));
        this.getCommsLogEntryDAO().insert(commsLogEntry);

        CommsLogEntry log = getCommsLogService().getCommsLogEntry(CommonEntityKeyFactory.createCommsLogEntryEntityKey(
                commsLogEntry.getCommsLogIdString()));

        // Simulate UI, which sends disconnected objects... use clone [not really after looking at UI code]
        CommsLogEntry updated = log;//(CommsLogEntry)commsLogEntry.clone();
        updated.addMailingStatus(this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.CANCEL_BY_HEC.getName()));
        CommsLogEntry result = this.getCommsLogService().updateCommunicationLog(updated);
        System.out.println("Log id=" + commsLogEntry.getCommsLogIdString());
        assertTrue(ComMailingStatusType.CANCEL_BY_HEC.getCode().equals(result.getLatestMailingStatus().getMailingStatus().getCode()));
    }

    public void testUndeliverable_ReturnedByPo() throws Exception{
        Person onFile = this.buildSimplePerson();
        Address address = this.createPermanentAddress();
        onFile.addAddress(address);
        Person incoming = this.getPersonService().save(onFile);
        List  al = new ArrayList();
        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming,ComLetterTemplateType.FORM_NUMBER_600C.getName());

        ComMailingStatusType status = this.getLookupService().getComMailingStatusTypeByCode(ComMailingStatusType.RETURN_BY_POST_OFFICE.getName());
        this.getCommsLogEntryDAO().insert(commsLogEntry);
        commsLogEntry.addMailingStatus(status); // with no key or modified date
        al.add(commsLogEntry);

        this.getCommsLogService().processUndeliverableMail(al);
    }

    public void testUndeliverable_TempAddress() throws Exception{
        this.doUndeliverableTest(AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName());
        this.setComplete();
    }

    public void testUndeliverable_ConfAddress() throws Exception{
        this.doUndeliverableTest(AddressType.CODE_CONFIDENTIAL_ADDRESS.getName());
        this.setComplete();
    }

    /**
     * @return Returns the commsLogService.
     */
    public CommsLogService getCommsLogService() {
        return commsLogService;
    }

    /**
     * @param commsLogService The commsLogService to set.
     */
    public void setCommsLogService(CommsLogService commsLogService) {
        this.commsLogService = commsLogService;
    }
    /**
     * @return Returns the commsLogEntryDAO.
     */
    public CommsLogEntryDAO getCommsLogEntryDAO() {
        return commsLogEntryDAO;
    }

    /**
     * @param commsLogEntryDAO The commsLogEntryDAO to set.
     */
    public void setCommsLogEntryDAO(CommsLogEntryDAO commsLogEntryDAO) {
        this.commsLogEntryDAO = commsLogEntryDAO;
    }

    private void doUndeliverableTest(String addressType) throws Exception{
        Person onFile = this.buildSimplePerson();
        Address address = this.createAddress(this.getLookupService().getAddressTypeByCode(addressType));
        address.setChangeDate(this.getDate(2005,1,1));
        onFile.addAddress(address);
        Person incoming = this.getPersonService().save(onFile);
        List  al = new ArrayList();
        CommsLogEntry commsLogEntry = this.createCommsLogEntry(incoming,ComLetterTemplateType.FORM_NUMBER_600C.getName());
        commsLogEntry.setMailingDate(this.getDate(2005,2,1));
        this.getCommsLogEntryDAO().insert(commsLogEntry);
        al.add(commsLogEntry);

        this.getCommsLogService().processUndeliverableMail(al);
    }

    private Address createPermanentAddress() throws Exception {
        Address address = this.createAddress(this.getLookupService().getAddressTypeByCode(AddressType.CODE_PERMANENT_ADDRESS.getName()));
        return address;
    }

    /**
     * @return Returns the ruleValidationService.
     */
    public RuleValidationService getRuleValidationService() {
        return ruleValidationService;
    }

    /**
     * @param ruleValidationService The ruleValidationService to set.
     */
    public void setRuleValidationService(RuleValidationService ruleValidationService) {
        this.ruleValidationService = ruleValidationService;
    }

	public CorrespondenceService getCorrespondenceService() {
		return correspondenceService;
	}

	public void setCorrespondenceService(CorrespondenceService correspondenceService) {
		this.correspondenceService = correspondenceService;
	}
}
