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

import gov.va.med.esr.common.model.person.PersonMergeInfo;
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.service.LookupService;
import gov.va.med.esr.service.PersonHelperService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.PersonMergeService;
import gov.va.med.fw.batchprocess.AbstractDataQueryIncrementalProcess;
import gov.va.med.fw.batchprocess.DataQueryProcessExecutionContext;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.transaction.TransactionTimestampManager;

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

import org.apache.commons.lang.Validate;

/**
 * The batch process is to update merge record locked flg, merge start/end date 
 * of person_merge table to satisty the requirement of the surviving person has
 * enrollment data but the deprecated person does not automatically closed as 
 * complete. This also refers to CCR 10360. 
 * 
 * @author wayne.shew
 *
 */
public class DuplicateMergeBatchProcess extends
	AbstractDataQueryIncrementalProcess {

    private PersonService personService;
    private LookupService lookupService;  
	private PersonHelperService personHelperService;
	private PersonMergeService personMergeService;
	private TransactionTimestampManager timestampManager;
		

	public void processData(DataQueryProcessExecutionContext context, List acquiredData) {
		// TODO Auto-generated method stub

        if(logger.isDebugEnabled())
            logger.debug(getProcessName() + "Duplicate Merge batch process: Query increment result Size="
            		+ (acquiredData == null ? 0 : acquiredData.size()));
        
        // test log - To delete
//        System.out.println(getProcessName() + "Duplicate Merge batch process: Query increment result Size="
//        		+ (acquiredData == null ? 0 : acquiredData.size()));
        
        if (acquiredData == null)
            return;
        
        // 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++) {
            // Object[] returned from get when scrolling (idempotent is false)
            Object[] row = (Object[]) acquiredData.get(i);

            // Use the <sql-query>
            BigDecimal primaryPersonId = (BigDecimal) row[0]; 
            BigDecimal deprecatedPersonId = (BigDecimal) row[1];
            PersonEntityKey primaryPersonKey = new PersonIdEntityKeyImpl(primaryPersonId);
            PersonEntityKey deprecatedPersonKey = new PersonIdEntityKeyImpl(deprecatedPersonId);

            if(logger.isDebugEnabled())
            	logger.debug("Processing person merge record # " + (i+1) + " with primary person id =" 
            			+ primaryPersonId + ", deprecated person id =" + deprecatedPersonId);            
            
//            System.out.println("Processing person merge record # " + (i+1) + " with primary person id =" 
//        			+ primaryPersonId + ", deprecated person id =" + deprecatedPersonId);  

            try {
            	
            	// update person merge info by primary and deprecated person ids 
            	getPersonMergeService().updatePersonMergeInfoByPrimaryDepIDs(primaryPersonKey, deprecatedPersonKey);
		            
	            context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
	            
            } catch (Exception ex) {
                context.getProcessStatistics().incrementNumberOfErrorRecords();
                String errMsg = "Error while executing " + getProcessName() + " for primary person id="
                                + primaryPersonId + ", deprecated person id =" + deprecatedPersonId ;
                context.getExceptionData().add(errMsg+ " Reason: "+ ex.getMessage());
                if(logger.isWarnEnabled())
                    logger.warn(errMsg + " Reason: ", ex);
            }
            
            // Update statistics more frequently than once per batch (default size 500)
            if(context.getProcessStatistics().isTotalNumberMod(DEFAULT_JOB_RESULT_UPDATE_INTERVAL))
                this.updateJobResult(context);
        }
        
        if(logger.isDebugEnabled()) {
            logger.debug(getProcessName() + ": Processing of current batch complete.");
            logger.debug(getProcessName() + ": Successful records count = "+context.getProcessStatistics().getNumberOfSuccessfulRecords());
            logger.debug(getProcessName() + ": Failure records count ="+context.getProcessStatistics().getNumberOfErrorRecords());
        }
    
	}

	public LookupService getLookupService() {
		return lookupService;
	}

	public void setLookupService(LookupService lookupService) {
		this.lookupService = lookupService;
	}

	public PersonHelperService getPersonHelperService() {
		return personHelperService;
	}

	public void setPersonHelperService(PersonHelperService personHelperService) {
		this.personHelperService = personHelperService;
	}

	public PersonMergeService getPersonMergeService() {
		return personMergeService;
	}

	public void setPersonMergeService(PersonMergeService personMergeService) {
		this.personMergeService = personMergeService;
	}

	public PersonService getPersonService() {
		return personService;
	}

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

	public TransactionTimestampManager getTimestampManager() {
		return timestampManager;
	}

	public void setTimestampManager(TransactionTimestampManager timestampManager) {
		this.timestampManager = timestampManager;
	}
	
	public void afterPropertiesSet() {
	   	super.afterPropertiesSet();
        Validate.notNull(personService);
        Validate.notNull(lookupService);
        Validate.notNull(personHelperService);
        Validate.notNull(timestampManager);  
        Validate.notNull(personMergeService);   
	}
	    
}
