/********************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ********************************************************************/


package gov.va.med.esr.common.batchprocess;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.Validate;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;

import gov.va.med.esr.common.model.lookup.SystemParameterUnit;
import gov.va.med.esr.common.model.system.SystemParameter;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.esr.service.SystemParametersChangedEvent;
import gov.va.med.fw.scheduling.DynamicCronTriggerBean;
import gov.va.med.fw.scheduling.SchedulingService;
import gov.va.med.fw.service.AbstractListenerService;
import gov.va.med.fw.service.event.ServiceEvent;
import gov.va.med.fw.util.DateUtils;
import gov.va.med.fw.util.InvalidConfigurationException;

/**
 * Reschedules triggers based on current SystemParameter settings.
 * 
 * Created Jun 7, 2006 9:51:32 PM
 * @author DNS   BOHMEG
 */
public class RescheduleDynamicCronTriggersProcessListener extends
		AbstractListenerService {
	private SchedulingService schedulingService;
	private List triggers;
	private SystemParameterService systemParameterService;

	/* (non-Javadoc)
	 * @see gov.va.med.fw.service.AbstractListenerService#processServiceEvent(gov.va.med.fw.service.event.ServiceEvent)
	 */
	protected void processServiceEvent(ServiceEvent event) {
		if(!(event instanceof SystemParametersChangedEvent))
			return;
		
		Iterator itr = triggers.iterator();
		DynamicCronTriggerBean targetTrigger = null;
		while(itr.hasNext()) {
			targetTrigger = (DynamicCronTriggerBean) itr.next();
			try {
				schedulingService.reschedule(targetTrigger.getName(), targetTrigger.getGroup(), modifyTrigger(targetTrigger));
			} catch(Exception e) {
				if(logger.isErrorEnabled())
					logger.error("Unable to reschedule trigger named " + targetTrigger.getName() + " based on a System Parameter change", e);
			}
		}
	}
	
	private Trigger modifyTrigger(DynamicCronTriggerBean trigger) throws Exception {
		SystemParameter parameter = systemParameterService.getByName(trigger.getSystemParameterName());
		SystemParameterUnit unit = parameter.getUnit();
		Trigger targetTrigger = trigger;
		long milliSecondInterval = 0;
		if(SystemParameterUnit.CODE_HOURS.getCode().equals(unit.getCode())) {
			// make hourly type of trigger
			milliSecondInterval = Long.parseLong(parameter.getValue()) * DateUtils.MILLIS_PER_HOUR;			
		} else if(SystemParameterUnit.CODE_DAYS.getCode().equals(unit.getCode())) {
			// make daily type of trigger
			milliSecondInterval = Long.parseLong(parameter.getValue()) * DateUtils.MILLIS_PER_HOUR  * 24;
		} else if(SystemParameterUnit.CODE_WEEKS.getCode().equals(unit.getCode())) {
			// make weekly type of trigger
			milliSecondInterval = Long.parseLong(parameter.getValue()) * DateUtils.MILLIS_PER_HOUR  * 24 * 7;
		} else if(SystemParameterUnit.CODE_MONTHS.getCode().equals(unit.getCode())) {
			// make monthly type of trigger (interpreted as every 30 days)
			milliSecondInterval = Long.parseLong(parameter.getValue()) * DateUtils.MILLIS_PER_HOUR  * 24 * 30;
		}
		
		if(milliSecondInterval != 0) {
			targetTrigger = new SimpleTrigger(trigger.getName(), trigger.getGroup(),
					SimpleTrigger.REPEAT_INDEFINITELY, milliSecondInterval);
			long startTime = (new Date()).getTime() + milliSecondInterval;
			targetTrigger.setStartTime(new Date(startTime));		
			
			targetTrigger.setJobName(trigger.getJobName());
			targetTrigger.setJobGroup(trigger.getJobGroup());
		}
		
		return targetTrigger;
	}
	

	/**
	 * @return Returns the schedulingService.
	 */
	public SchedulingService getSchedulingService() {
		return schedulingService;
	}

	/**
	 * @param schedulingService The schedulingService to set.
	 */
	public void setSchedulingService(SchedulingService schedulingService) {
		this.schedulingService = schedulingService;
	}

	/**
	 * @return Returns the systemParameterService.
	 */
	public SystemParameterService getSystemParameterService() {
		return systemParameterService;
	}

	/**
	 * @param systemParameterService The systemParameterService to set.
	 */
	public void setSystemParameterService(
			SystemParameterService systemParameterService) {
		this.systemParameterService = systemParameterService;
	}

	public void afterPropertiesSet() throws Exception {
		Validate.notNull(systemParameterService, "systemParameterService is required");
		Validate.notNull(schedulingService, "schedulingService is required");
		Validate.notNull(triggers, "triggers is required");
		
		// ensure all triggers are of correct type
		Iterator itr = triggers.iterator();
		while(itr.hasNext()) {
			if(!(itr.next() instanceof DynamicCronTriggerBean))
				throw new InvalidConfigurationException("triggers contain an element that is not an instanceof DynamicCronTriggerBean");
		}
	}

	/**
	 * @return Returns the triggers.
	 */
	public List getTriggers() {
		return triggers;
	}

	/**
	 * @param triggers The triggers to set.
	 */
	public void setTriggers(List triggers) {
		this.triggers = triggers;
	}

}
