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

import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.service.CampLejeuneService;
import gov.va.med.esr.service.PreferredFacilityService;
import gov.va.med.fw.batchprocess.AbstractDataFileListenerProcess;
import gov.va.med.fw.batchprocess.CampLejeuneImportProcessStatistics;
import gov.va.med.fw.batchprocess.DataFileProcessExecutionContext;
import gov.va.med.fw.batchprocess.DataProcessExecutionContext;
import gov.va.med.fw.rule.RuleValidationException;
import gov.va.med.fw.service.CLEARImportSuccessErrorReportException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.support.AbstractSpawnedThreadTask;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.dao.OptimisticLockingFailureException;

public class CampLejeuneImportProcessSpawnedThreadTask extends
		AbstractSpawnedThreadTask {

	private static final int DEFAULT_OPTIMSTIC_RETRIES = 5;
	
	public static final String ERROR_KEYWORD = "Exception Processing CLEAR Record: ";

	private DataFileProcessExecutionContext context;
	private List dataRecords;
	private CampLejeuneService campLejeuneService;
	

	private int optimisticLockRetries = DEFAULT_OPTIMSTIC_RETRIES;
	
	public DataFileProcessExecutionContext getContext() {
		return context;
	}
	public void setContext(DataFileProcessExecutionContext context) {
		this.context = context;
	}

	public int getOptimisticLockRetries() {
		return optimisticLockRetries;
	}
	public void setOptimisticLockRetries(int optimisticLockRetries) {
		this.optimisticLockRetries = optimisticLockRetries;
	}

	public List getDataRecords() {
		return dataRecords;
	}
	public void setDataRecords(List dataRecords) {
		this.dataRecords = dataRecords;
	}
	
	public CampLejeuneService getCampLejeuneService() {
		return campLejeuneService;
	}
	
	public void setCampLejeuneService(CampLejeuneService campLejeuneService) {
		this.campLejeuneService = campLejeuneService;
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.service.support.SpawnedThreadTask#execute()
	 */
	public void executeTask() throws Throwable {
		if (logger.isDebugEnabled()) {
			logger.debug("CampLejeuneImportProcessSpawnedThreadTask started");
		}
		
		int numberOfRetries;
		boolean optimisticLockSuccess;
		
		for (int i = 0; dataRecords != null && i < dataRecords.size(); i++) {
			if (context.isInterrupted()) {
				break;
			}
			
			CampLejeuneImportData dataRecord = (CampLejeuneImportData) dataRecords.get(i);
			
			try {

				if (logger.isDebugEnabled()) {
					logger.debug("Processing dataRecord #" + i);
				}
				
				numberOfRetries = optimisticLockRetries;
				optimisticLockSuccess = false;
			
				while (numberOfRetries > 0 && !optimisticLockSuccess) {
				
					try {
						Person incoming = campLejeuneService.findPersonWithCLEARData(dataRecord);
//						String oldPriGrp = getEnrollmentPriority(person.getEnrollmentDetermination());
						
						String[] oldNewErr = campLejeuneService.processCLEARData(incoming);
						if (! StringUtils.isEmpty(oldNewErr[2])) {
							//this exception is considered a successful case, but needs to create an exception record with specific reason  
							CampLejeuneImportProcessStatistics stats = (CampLejeuneImportProcessStatistics)context.getProcessStatistics();
							stats.incrementNumberOfSuccessfulRecords();
							stats.addDetailUnsuccess(dataRecord.getVeteranIdentifiers(), oldNewErr[2] + stats.LINE_BREAK);
							
							break;
						}
						
//						String newPriGrp = getEnrollmentPriority(person.getEnrollmentDetermination());
						
						optimisticLockSuccess = true;
						CampLejeuneImportProcessStatistics stats = (CampLejeuneImportProcessStatistics)context.getProcessStatistics();
						stats.incrementNumberOfSuccessfulRecords();
						
						stats.addDetailSuccess(dataRecord.getVeteranIdentifiers(), oldNewErr[0], oldNewErr[1]);
						
					} catch (OptimisticLockingFailureException ole) {
						numberOfRetries--;
						if (logger.isDebugEnabled()) {
							logger.debug("Encountered OptimisticLockingFailureException, # of retries remaining = " + numberOfRetries);
						}
						if (numberOfRetries == 0) {
							// out of re-tries, rethrow exception
							throw new ServiceException("Exhausted number of retries (" + optimisticLockRetries + ") for OptimisticLockingFailureException.");
						}
					} 
				} 
			}
			catch (Exception e) {
				handleFailure(context, dataRecord, e);
			}
		}
		
		CampLejeuneImportProcess.adjustTaskCount(
				context, -1);
		Object threadCreator = getThreadCreator(context);
		synchronized (threadCreator) {
			threadCreator.notifyAll();
		}
		if (logger.isDebugEnabled()) {
			logger.debug("CampLejeuneImportProcessSpawnedThreadTask ended, notified creator");
		}
		
		/*
		 * force release of context as thay will hold the ThreadPool(->Threads)
		 * this is necessary to GC ThreadPool threads at end
		 */
		context = null;
	}
	
    private String getEnrollmentPriority(EnrollmentDetermination enroll)
    {
        if (enroll != null && enroll.getPriorityGroup() != null)
        {
            String priority = enroll.getPriorityGroup().getDescription();

            if (enroll.getPrioritySubGroup() != null)
                priority += enroll.getPrioritySubGroup().getDescription();
            priority = priority.replaceAll("Enrollment Priority sub-Group", "");
            return priority.replaceAll("'", "");
        }
        return "";
    }
    
	private Object getThreadCreator(DataProcessExecutionContext context) {
		return context
				.getContextData()
				.get(
						CampLejeuneImportProcess.CONTEXT_THREAD_CREATOR);
	}
	
	private void handleFailure(DataFileProcessExecutionContext context,
			CampLejeuneImportData dataRecord, Exception e) {
		
		CampLejeuneImportProcessStatistics stats = (CampLejeuneImportProcessStatistics)context.getProcessStatistics();
		
		String errReason = null; 
//		String logTxt = null;
		if (e == null) {
			errReason = "Unknown Exception\n" ;
//			logTxt = errReason;
		}
		else {
//            StringWriter sw = new StringWriter();
//            e.printStackTrace(new PrintWriter(sw)); //get the StackTrace
 
			errReason =	e.getMessage(); 
//			logTxt = errReason + stats.LINE_BREAK  + sw.toString();
		}
/*		if (logger.isErrorEnabled()) {
			logger.error(this.ERROR_KEYWORD + logTxt);
		}*/
		
		stats.incrementNumberOfErrorRecords();
		stats.addDetailUnsuccess(dataRecord.getVeteranIdentifiers(), errReason);
	}
	
	
	
}
