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


import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.service.MessagingService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.fw.batchprocess.AbstractDataQueryIncrementalProcess;
import gov.va.med.fw.batchprocess.DataQueryProcessExecutionContext;
import gov.va.med.fw.batchprocess.ProcessStatistics;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StopWatchLogger;

import java.math.BigDecimal;
import java.util.List;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.Validate;


/**
 * A class for the one-time batch job to convert data for the Catastrophic Disability project.
 *
 */
public class CDConversionProcess extends AbstractDataQueryIncrementalProcess {

	private PersonService personService = null;
	private MessagingService messagingService = null;
	
	protected ProcessStatistics createProcessStatistics() {
	    return new CDConversionStatistics();
    }   

	protected void processData(DataQueryProcessExecutionContext context, List acquiredData) {
		if(logger.isInfoEnabled())
			logger.info("CD Conversion Process: Query result Size="+(acquiredData == null ? 0 : acquiredData.size()));

		if (acquiredData == null)
			return;

		StopWatchLogger watch = null;

		Person person = null;
		
	    // Add check for isInterrupted so don't have to wait for entire batch to finish
		for (int i = 0; i < acquiredData.size()  && !isInterrupted(context); i++) {
			
			if (logger.isDebugEnabled()) {
				watch = new StopWatchLogger(ClassUtils.getShortClassName(getClass())
						+ " processData[" + i + "]");
				if (watch != null) {
					watch.start();
				}
			}

			// Object[] returned from get when scrolling (idempotent is false)
			Object[] row = (Object[]) acquiredData.get(i);
			BigDecimal personId = (BigDecimal) row[0];

			try {
				person = personService.getPerson(new PersonIdEntityKeyImpl(personId)); 
				
				if (person == null)
					throw new ServiceException("Unable to find Person with personId= "+ personId);			
		
				boolean hasDescriptor = messagingService.processCDConversion(person);
				
				if (hasDescriptor) {
					context.getProcessStatistics().incrementNumberOfSuccessfulRecords();					
				} else {
					// If a candidate record was not converted, provide the business the reason why it was not converted
					((CDConversionStatistics) context.getProcessStatistics()).incrementNumberNotConverted();
					context.getExceptionData().add("Record not converted for person ID: " + personId);
				}
					
			} catch (Exception ex) {
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				String errMsg = "Error convertig CD data for person " + personId;
				context.getExceptionData().add(errMsg+ ". Reason: "+ ex.getMessage() + ".\n   Details: " + ex);
				if(logger.isWarnEnabled())
					logger.warn(errMsg + " Reason: ", ex);
			} finally {
				if (logger.isDebugEnabled() && watch != null)
					watch.stopAndLog();
			}
		}
		
		if(logger.isDebugEnabled()) {
			logger.debug("CDConversionProcess: Processing complete.");
			logger.debug("CDConversionProcess: Successful records count = "+context.getProcessStatistics().getNumberOfSuccessfulRecords());
			logger.debug("CDConversionProcess: Person records not converted to CD Descriptors = "+ ((CDConversionStatistics)context.getProcessStatistics()).getNumberNotConverted());
			logger.debug("CDConversionProcess: Failure records count ="+context.getProcessStatistics().getNumberOfErrorRecords());
		}
		
	}
	
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Validate.notNull(personService,	"A PersonService is needed");
		Validate.notNull(messagingService,	"A MessagingService is needed");
	}

	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}

	public MessagingService getMessagingService() {
		return messagingService;
	}

	public void setMessagingService(MessagingService messagingService) {
		this.messagingService = messagingService;
	}
}
