package gov.va.med.esr.common.rule.service;




// Java classes
import java.math.BigDecimal;
import java.util.Date;

import org.quartz.Trigger;
import org.quartz.TriggerUtils;

import gov.va.med.esr.common.clock.Clock;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.comms.AacLetterRequest;
import gov.va.med.esr.common.model.lookup.DecorationStatus;
import gov.va.med.esr.common.model.lookup.EligibilityVerificationSource;
import gov.va.med.esr.common.model.lookup.MilitaryServiceQueryStatus;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.common.util.RuleAbstractTestCase;
import gov.va.med.esr.service.ScheduledTaskService;
import gov.va.med.fw.scheduling.ScheduledProcess;
import gov.va.med.fw.scheduling.ScheduledProcessInvocationContext;
import gov.va.med.fw.scheduling.SchedulingService;

public class ClocksTest extends RuleAbstractTestCase {
   public static final String PH_CLOCK_JOB_BEAN_NAME = "scheduledJob.phClockProcess";
   public static final String SSN_CLOCK_JOB_BEAN_NAME = "scheduledJob.ssnClockProcess";
   public static final String WF_CLOCK_JOB_BEAN_NAME = "scheduledJob.wfClockProcess";   
   
    private ScheduledTaskService scheduledTaskService = null;
    
    public ClocksTest(String testName) {
        super(testName);
    }
    
    public void testStartClock() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachEligibilityVerification(onFile, EligibilityVerificationSource.CODE_CEV.getName()); 
        this.attachMeansTestWithMtCopayExempt(onFile);
        this.attachVerifiedEnrollment(onFile);        
        SSN ssn = this.createSSN(); 
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);
        onFile.getOfficialSsn().setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));            
        Person incoming = this.getPersonService().save(onFile);

        double hours = 2.0 /60.0;
        this.getScheduledTaskService().startClock(incoming, hours, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP, SSN_CLOCK_JOB_BEAN_NAME );
        String triggerName = incoming.getEntityKey().getKeyValueAsString() + Clock.Type.SSN_30_DAY_VALIDATION_CLOCK.getName();
        
        Trigger trigger = this.getSchedulingService().getTrigger( triggerName,  Clock.Group.SSN_CLOCK_GROUP.getName() );
        System.out.println("start="+trigger.getStartTime().toString());
  
        try {
            // wait 90 seconds to show jobs
            Thread.sleep(60L * 1000L); 
            // executing...
        } 
        catch (Exception e) {}        
    }
    
    public void testLoadClocks() throws Exception {
    	PersonEntityKey key = null;
    	for(int i=0; i<5; i++) {
	    	key = CommonEntityKeyFactory.createPersonIdEntityKey(Integer.toString(i));
	    	this.getScheduledTaskService().startClock(key, 5.0, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP,
	    			SSN_CLOCK_JOB_BEAN_NAME, "gsb");
    	}
    	super.setComplete();
    }
    
    
    public void testStartClockMultipleTimes() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachEligibilityVerification(onFile, EligibilityVerificationSource.CODE_CEV.getName()); 
        this.attachMeansTestWithMtCopayExempt(onFile);
        this.attachVerifiedEnrollment(onFile);        
        SSN ssn = this.createSSN(); 
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);
        onFile.getOfficialSsn().setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));            
        Person incoming = this.getPersonService().save(onFile);

        double hours = 2.0 /60.0;
        String triggerName = incoming.getEntityKey().getKeyValueAsString() + Clock.Type.SSN_30_DAY_VALIDATION_CLOCK.getName();
        Trigger trigger = this.getSchedulingService().getTrigger( triggerName,  Clock.Group.SSN_CLOCK_GROUP.getName() );        
        this.getScheduledTaskService().startClock(incoming, hours, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP, SSN_CLOCK_JOB_BEAN_NAME );
        trigger = this.getSchedulingService().getTrigger( triggerName,  Clock.Group.SSN_CLOCK_GROUP.getName() );
        this.getScheduledTaskService().startClock(incoming, hours, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP, SSN_CLOCK_JOB_BEAN_NAME );        

        System.out.println("start="+trigger.getStartTime().toString());
    }    
    
    public void rescheduletClock() throws Exception {

        Date clock = TriggerUtils.getNextGivenMinuteDate( new Date(), 3 );
        String triggerName = "290676PH_14_DAY_CLOCK";
        Trigger trigger =    this.getSchedulingService().getTrigger( triggerName,  Clock.Group.PH_CLOCK_GROUP.getName() );
        trigger.setStartTime(clock);

        this.getSchedulingService().reschedule(triggerName,  Clock.Group.PH_CLOCK_GROUP.getName(), trigger );
        System.out.println("start="+trigger.getStartTime().toString());
        System.out.println("next="+trigger.getNextFireTime().toString());
        this.setComplete();
  

     
    }    
    
    public void testStartSSN30DayClock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("20750873"));        
        Person incoming = this.getPersonService().getPerson(personKey);        

        this.getScheduledTaskService().startSSNInvalidLetterClock(incoming, AacLetterRequest.VETERAN_LETTER);
        this.waitForClock(incoming.getEntityKey().getKeyValueAsString(),
                Clock.Type.SSN_30_DAY_VALIDATION_CLOCK.getName(),
                Clock.Group.SSN_CLOCK_GROUP.getName());  
    }
    
    public void testStart292Clock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        
        Person incoming = this.getPersonService().getPerson(personKey);        

        this.getScheduledTaskService().startPseudoSSNReasonClock(incoming, AacLetterRequest.VETERAN_LETTER);
        this.waitForClock(incoming.getEntityKey().getKeyValueAsString(),
                Clock.Type.SSN_30_DAY_PSEUDO_SSN_REASON_CLOCK.getName(),
                Clock.Group.SSN_CLOCK_GROUP.getName(), AacLetterRequest.VETERAN_LETTER);  
    }    
    
    
    public void testToDate() throws Exception {
    	System.out.println("triggered clock"+ (new Date(System.currentTimeMillis() )));
    }     
    public void testStartWorkflowClock() throws Exception {
    	/*
    	 * 
    	 */
    	
    	System.out.println("triggered clock"+ (new Date(1290202200000L)));
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        

        Person incoming = this.getPersonService().getPerson(personKey);        
      
        this.getScheduledTaskService().startMilServiceQueryClock(incoming);
        System.out.println("triggered clock");    
     //   this.waitForWFClock("779", Clock.Type.WF_72_HOUR_CLOCK.getName(), Clock.Group.WF_CLOCK_GROUP.getName() );
        this.setComplete();
    }     
    public void testWaitForClock() throws Exception{
        String triggerName = "779"+Clock.Type.WF_72_HOUR_CLOCK.getName();
        Trigger trigger =    this.getSchedulingService().getTrigger( triggerName, Clock.Group.WF_CLOCK_GROUP.getName() );
        System.out.println("Person id=" + trigger);        
    	
    }
    
    private void waitForWFClock(String id, String typeName, String group) throws Exception {
        Date clock = TriggerUtils.getNextGivenMinuteDate( new Date(), 1 );
        String triggerName = id+typeName;
        Trigger trigger =    this.getSchedulingService().getTrigger( triggerName, group );
        trigger.setStartTime(clock);

        this.getSchedulingService().reschedule(triggerName,  group, trigger );
        System.out.println("start="+trigger.getStartTime().toString());
        System.out.println("next="+trigger.getNextFireTime().toString());        

        System.out.println("Person id=" + id);        
        System.out.println("start wait");        
        try {
            // wait 90 seconds to show jobs
            Thread.sleep(300L * 1000L); 
            // executing...
        } 
        catch (Exception e) {}                
        System.out.println("done waiting");        
    }    
    public void testCancelWorkflowClock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        
        Person incoming = this.getPersonService().getPerson(personKey);        
    	this.getScheduledTaskService().cancelClock(
				incoming,
				Clock.Type.WF_72_HOUR_CLOCK,
				Clock.Group.WF_CLOCK_GROUP);
        System.out.println("cancel clock");    
        this.setComplete();
    }    
    
    public void testStart293Clock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("20005429"));        
        Person incoming = this.getPersonService().getPerson(personKey);        

        this.getScheduledTaskService().startPseudoSSNVerificationClock(incoming, AacLetterRequest.VETERAN_LETTER);
        this.waitForClock(incoming.getEntityKey().getKeyValueAsString(),
                Clock.Type.SSN_30_DAY_PSEUDO_SSN_VERIFICATION_CLOCK.getName(),
                Clock.Group.SSN_CLOCK_GROUP.getName(), AacLetterRequest.VETERAN_LETTER);  
    }        
    
    public void testStartPHPendingClock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("291067"));        
        Person incoming = this.getPersonService().getPerson(personKey);        
        this.getScheduledTaskService().startPHPendingClock(incoming);
        this.waitForClock(incoming.getEntityKey().getKeyValueAsString(),
                Clock.Type.PH_14_DAY_CLOCK.getName(),
                Clock.Group.PH_CLOCK_GROUP.getName());
    }
    
    public void testStartPHLetterClock() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        
        Person incoming = this.getPersonService().getPerson(personKey);        
        this.getScheduledTaskService().startPHLetterClock(incoming);
        this.setComplete();
        /*
        this.waitForClock(incoming.getEntityKey().getKeyValueAsString(),
                Clock.Type.PH_37_DAY_CLOCK.getName(),
                Clock.Group.PH_CLOCK_GROUP.getName());
                */
    }            
    
    private void waitForClock(String id, String typeName, String group) throws Exception {
        waitForClock(id, typeName, group, null);
    }
   
    private void waitForClock(String id, String typeName, String group, String subject) throws Exception {
        Date clock = TriggerUtils.getNextGivenMinuteDate( new Date(), 1 );
        String triggerName = "225128PH_37_DAY_CLOCK";
        if (subject != null) {
            triggerName = triggerName + subject;
        }
        Trigger trigger =    this.getSchedulingService().getTrigger( triggerName, group );
        trigger.setStartTime(clock);

        this.getSchedulingService().reschedule(triggerName,  group, trigger );
        System.out.println("start="+trigger.getStartTime().toString());
        System.out.println("next="+trigger.getNextFireTime().toString());        
        this.setComplete();
        System.out.println("Person id=" + id);        
        System.out.println("start wait");        
        try {
            // wait 90 seconds to show jobs
            Thread.sleep(300L * 1000L); 
            // executing...
        } 
        catch (Exception e) {}                
        System.out.println("done waiting");        
    }
    
    public void testExecuteClockProcessForPH() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachPurpleHeartWithPHStatusPending(onFile);
        attachFacilityToPurpleHeart(onFile,VAFacility.CODE_HEC.getName());
        Person incoming = this.getPersonService().save(onFile);
        Object list[] = {incoming.getEntityKey().getKeyValueAsString(),Clock.Type.PH_14_DAY_CLOCK.getName()};
        ScheduledProcess clockProcess = this.getPHClockProcess();
        ScheduledProcessInvocationContext context = new ScheduledProcessInvocationContext();
        context.setInvocationArguments(list);
        context.setExecutionContext("JUnit");
        clockProcess.invoke(context);        
        this.setComplete();
    }
    
    public void testExecuteClockProcessForWorkflow() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        
        Person onFile = this.getPersonService().getPerson(personKey);
        onFile.getMilitaryService().setMilitaryServiceQueryStatus(this.getLookupService().getMilitaryServiceQueryStatusByCode(MilitaryServiceQueryStatus.QUERIED_PENDING_RESPONSE.getCode()));
        Person incoming = onFile;
        Object list[] = {incoming.getEntityKey().getKeyValueAsString(),Clock.Type.WF_72_HOUR_CLOCK.getName()};
        ScheduledProcess clockProcess = this.getWfClockProcess();
        ScheduledProcessInvocationContext context = new ScheduledProcessInvocationContext();
        context.setInvocationArguments(list);
        context.setExecutionContext("JUnit");
        clockProcess.invoke(context);        
       //this.setComplete();
    }    
    public void testAddMilService() throws Exception {
        PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("779"));        
        Person onFile = this.getPersonService().getPerson(personKey);
        this.attachMilitaryService(onFile);

        this.getPersonService().save(onFile);
       this.setComplete();
    }        
    
    public void testExecuteClockProcessForSSN() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachEligibilityVerification(onFile, EligibilityVerificationSource.CODE_CEV.getName()); 
        this.attachMeansTestWithMtCopayExempt(onFile);
        this.attachVerifiedEnrollment(onFile);        
        SSN ssn = this.createSSN(); 
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);
        onFile.getOfficialSsn().setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));            
        Person incoming = this.getPersonService().save(onFile);
        Object list[] = {incoming.getEntityKey().getKeyValueAsString(), Clock.Type.SSN_30_DAY_VALIDATION_CLOCK.getName()};
        ScheduledProcess clockProcess = this.getSSNClockProcess();
        ScheduledProcessInvocationContext context = new ScheduledProcessInvocationContext();
        context.setInvocationArguments(list);
        context.setExecutionContext("JUnit");        
        clockProcess.invoke(context);        
        this.setComplete();
    }         
    
    public void testCancelClock() throws Exception {
        final String triggerName = "270762PH_14_DAY_CLOCK";
        final String triggerGroup = "PH_CLOCK_GROUP";

        this.getSchedulingService().unschedule(triggerName, triggerGroup);
        this.setComplete();
    }

    public void testCancelClockTriggerPresent() throws Exception
    {
        Person onFile = buildSimplePerson();
        this.attachEligibilityVerification(onFile, EligibilityVerificationSource.CODE_CEV.getName());
        this.attachMeansTestWithMtCopayExempt(onFile);
        this.attachVerifiedEnrollment(onFile);
        SSN ssn = this.createSSN();
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);
        onFile.getOfficialSsn().setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));
        Person incoming = this.getPersonService().save(onFile);

        double hours = 2.0;
        this.getScheduledTaskService().startClock(incoming, hours, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP, SSN_CLOCK_JOB_BEAN_NAME );
        this.getScheduledTaskService().cancelClock(incoming, Clock.Type.SSN_30_DAY_VALIDATION_CLOCK, Clock.Group.SSN_CLOCK_GROUP);
        this.setComplete();
    }

    public void testRun() throws Exception {

        // Query
        String jobs [] = this.getSchedulingService().getJobGroupNames();        
        String names [] = this.getSchedulingService().getTriggerNames(Clock.Group.PH_CLOCK_GROUP.getName()); 
        
        for (int i = 0; i < jobs.length;i++) {
            System.out.println("job:" + jobs[i]);
        }
        for (int i = 0; i < names.length;i++) {
            System.out.println("name:" + names[i]);
            Trigger trigger =  this.getSchedulingService().getTrigger(names[i],Clock.Group.PH_CLOCK_GROUP.getName());
            System.out.println("start time:" + trigger.getStartTime());
            System.out.println("next fire time:" + trigger.getNextFireTime());            
            String listeners [] = trigger.getTriggerListenerNames();
            for (int j = 0; j < listeners.length;j++) {
                System.out.println("listener:" + listeners[j]);                
            }
                        
        }
        this.setComplete();
        try {
            Thread.sleep(20L * 1000L); 
        } 
        catch (Exception e) {}           
        this.setComplete();
    }    
  /*  
    public void testCancelAllPHClocks() throws Exception {
        cancelClocks(Clock.Group.PH_CLOCK_GROUP.getName());        
        this.setComplete();        
    }               
 
    public void testCancelAllSSNClocks() throws Exception {
        cancelClocks(Clock.Group.SSN_CLOCK_GROUP.getName());
        this.setComplete();        
    }                   
   */ 
//    private void cancelClocks(String group) throws Exception {
//    String names [] = this.getSchedulingService().getTriggerNames(group); 
//        
//        for (int i = 0; i < names.length;i++) {
//            System.out.println("name:" + names[i]);
//            Trigger trigger =  this.getSchedulingService().getTrigger(names[i],group);
//            this.getSchedulingService().unschedule(trigger.getJobName(),trigger.getGroup());                        
//        }
//                
//    }
    
    /**
     * Gets the scheduling service.
     * @return Returns the schedulingService.
     * @throws Exception if a problem was encountered.
     */
    public SchedulingService getSchedulingService() throws Exception {
        return (SchedulingService)applicationContext.getBean("common.schedulingService");
    }
    
    /**
     * @return Returns the scheduledTaskService.
     */
    public ScheduledTaskService getScheduledTaskService() {
        return scheduledTaskService;
    }

    /**
     * @param scheduledTaskService The scheduledTaskService to set.
     */
    public void setScheduledTaskService(ScheduledTaskService scheduledTaskService) {
        this.scheduledTaskService = scheduledTaskService;
    }       
    
    public ScheduledProcess getPHClockProcess() throws Exception {
        return (ScheduledProcess)applicationContext.getBean("common.batchprocess.processPHClock");
    }
    
    public ScheduledProcess getSSNClockProcess() throws Exception {
        return (ScheduledProcess)applicationContext.getBean("common.batchprocess.processSSNClock");
    }      
    
    
    public ScheduledProcess getWfClockProcess() throws Exception {
        return (ScheduledProcess)applicationContext.getBean("common.batchprocess.processWorkflowClock");
    }    
    
    public void createPHPendingPerson() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachPurpleHeartWithPHStatusPending(onFile);
//        onFile.getPurpleHeart().addDocument(this.createPHDocument());
        attachFacilityToPurpleHeart(onFile,VAFacility.CODE_HEC.getName());
        Person incoming = this.getPersonService().save(onFile);
        this.setComplete();
        System.out.println("Person id=" + incoming.getPersonEntityKey().getKeyValueAsString());        
    }
    
    public void createPHLetterPerson() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachPurpleHeartWithPHStatusPending(onFile);
        attachFacilityToPurpleHeart(onFile,VAFacility.CODE_HEC.getName());
        onFile.getPurpleHeart().setStatus(this.getLookupService().getDecorationStatusByCode(DecorationStatus.CODE_INITIAL_LETTER_SENT.getCode()));
        Person incoming = this.getPersonService().save(onFile);
        this.setComplete();
        System.out.println("Person id=" + incoming.getPersonEntityKey().getKeyValueAsString());        
    }
    
    public void createSSN30DayPerson() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachEligibilityVerification(onFile, EligibilityVerificationSource.CODE_CEV.getName()); 
        this.attachMeansTestWithMtCopayExempt(onFile);
        this.attachVerifiedEnrollment(onFile);        
        SSN ssn = this.createSSN(); 
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);
        onFile.getOfficialSsn().setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));            
        Person incoming = this.getPersonService().save(onFile);
        this.setComplete();
        System.out.println("Person id=" + incoming.getPersonEntityKey().getKeyValueAsString());        
    }        
}
