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


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

import org.apache.commons.lang.builder.ToStringBuilder;

import gov.va.med.fw.batchprocess.DataQueryProcessStatistics;
import gov.va.med.fw.batchprocess.ProcessStatistics;
import gov.va.med.fw.util.DateUtils;

/**
 * Initial javadoc for class MigrateBulkEEProcessStatistics.
 * TODO - Add content here
 * 
 * Created Sep 13, 2006 1:22:36 PM
 * @author DNS   BOHMEG
 */
public class MigrateBulkEEProcessStatistics extends DataQueryProcessStatistics {
	/**
	 * 
	 */
	private static final long serialVersionUID = -9119250116423503576L;
	private float totalSuccessfulDuration;
	
	private int numberOfEEDidNotChangeRecords;
	private int numberOfLettersTriggered;
	private int numberOfBulletinsTriggered;
	private int numberOfHL7MessagesTriggered;
	private int numberOfRecordsNotNeedingEEMigrated;

	private int extrapolatedTarget = 9000000;
	// use default if not specified
	private int parallelFactor = 2 /*managed instances in cluster that will service the payload JMS Messages */
											* 15 /*max mdb's/threads that can process at same time per managed instance*/;
	
	/**
	 * @param numberOfBulletinsTriggered The numberOfBulletinsTriggered to set.
	 */
	public void setNumberOfBulletinsTriggered(int numberOfBulletinsTriggered) {
		this.numberOfBulletinsTriggered = numberOfBulletinsTriggered;
	}

	/**
	 * @param numberOfEEDidNotChangeRecords The numberOfEEDidNotChangeRecords to set.
	 */
	public void setNumberOfEEDidNotChangeRecords(int numberOfEEDidNotChangeRecords) {
		this.numberOfEEDidNotChangeRecords = numberOfEEDidNotChangeRecords;
	}

	/**
	 * @param numberOfHL7MessagesTriggered The numberOfHL7MessagesTriggered to set.
	 */
	public void setNumberOfHL7MessagesTriggered(int numberOfHL7MessagesTriggered) {
		this.numberOfHL7MessagesTriggered = numberOfHL7MessagesTriggered;
	}

	/**
	 * @param numberOfLettersTriggered The numberOfLettersTriggered to set.
	 */
	public void setNumberOfLettersTriggered(int numberOfLettersTriggered) {
		this.numberOfLettersTriggered = numberOfLettersTriggered;
	}

	/**
	 * @param numberOfRecordsNotNeedingEEMigrated The numberOfRecordsNotNeedingEEMigrated to set.
	 */
	public void setNumberOfRecordsNotNeedingEEMigrated(
			int numberOfRecordsNotNeedingEEMigrated) {
		this.numberOfRecordsNotNeedingEEMigrated = numberOfRecordsNotNeedingEEMigrated;
	}

	public float getCurrentAverageSuccessfulDuration() {
		return this.getNumberOfSuccessfulRecords() > 0 ? this.totalSuccessfulDuration / this.getNumberOfSuccessfulRecords() : 0;
	}
	
	protected void buildToString(ToStringBuilder builder) {
		super.buildToString(builder);
		builder.append("averageDurationPerSuccessfulPerson", getCurrentAverageSuccessfulDuration());
		builder.append("numberOfEEDidNotChangeRecords", numberOfEEDidNotChangeRecords);
		builder.append("numberOfBulletinsTriggered", numberOfBulletinsTriggered);
		builder.append("numberOfHL7MessagesTriggered", numberOfHL7MessagesTriggered);
		builder.append("numberOfRecordsNotNeedingEEMigrated", numberOfRecordsNotNeedingEEMigrated);
		if(super.getProcessingStartDate() != null && super.getProcessingEndDate() != null && getNumberOfTotalRecords() > 0) {
			/* have to decide what "duration" to use when extrapolating....
			 * 	-the "overall processing" duration includes initial query cost AND wait times on JMS queues
			 * 	-the "business service" duration includes only the person retrieval and the calculateEE cost.
			 */
			long durationMillis = super.getProcessingEndDate().getTime() - super.getProcessingStartDate().getTime();
			
			builder.append("** EXTRAPOLATED Duration (represented in hours) for " + extrapolatedTarget + " records",
					(durationMillis/ (float) getNumberOfTotalRecords()) * extrapolatedTarget / DateUtils.MILLIS_PER_HOUR);
			builder.append("** EXTRAPOLATED Duration (represented in days) for " + extrapolatedTarget + " records",
					(durationMillis/ (float) getNumberOfTotalRecords()) * extrapolatedTarget / DateUtils.MILLIS_PER_DAY);
			
			/* only worth extrapolating out when total records processed was 1.  It is assumed that anything more than that already
			 * began to be processed in parallel across the cluster so we would be double counting here 
			 */
			if(this.getNumberOfTotalRecords() == 1) {
				builder.append("parallelFactor", parallelFactor);
				builder.append("** EXTRAPOLATED Parallel Duration (represented in hours) for " + extrapolatedTarget + " records",
						((durationMillis/ (float) getNumberOfTotalRecords()) * extrapolatedTarget / DateUtils.MILLIS_PER_HOUR) / parallelFactor);
				builder.append("** EXTRAPOLATED Parallel Duration (represented in days) for " + extrapolatedTarget + " records",
						((durationMillis/ (float) getNumberOfTotalRecords()) * extrapolatedTarget / DateUtils.MILLIS_PER_DAY) / parallelFactor);
			}
		}
	}

	/**
	 * @return Returns the numberOfEEDidNotChangeRecords.
	 */
	public int getNumberOfEEDidNotChangeRecords() {
		return numberOfEEDidNotChangeRecords;
	}

	/**
	 * @return Returns the numberOfBulletinsTriggered.
	 */
	public int getNumberOfBulletinsTriggered() {
		return numberOfBulletinsTriggered;
	}

	/**
	 * @return Returns the numberOfHL7MessagesTriggered.
	 */
	public int getNumberOfHL7MessagesTriggered() {
		return numberOfHL7MessagesTriggered;
	}

	public void incrementNumberOfHL7MessagesTriggered(int recordsCount) {
		numberOfHL7MessagesTriggered += recordsCount;
	}
	
	public void incrementNumberOfBulletinsTriggered(int recordsCount) {
		numberOfBulletinsTriggered += recordsCount;
	}

	public void incrementNumberOfRecordsNotNeedingEEMigrated() {
		incrementNumberOfRecordsNotNeedingEEMigrated(1);
	}

	public void incrementNumberOfRecordsNotNeedingEEMigrated(int count) {
		numberOfRecordsNotNeedingEEMigrated = numberOfRecordsNotNeedingEEMigrated + count; 
		super.incrementNumberOfTotalRecords(count);
	}
	
	/**
	 * @return Returns the extrapolatedTarget.
	 */
	public int getExtrapolatedTarget() {
		return extrapolatedTarget;
	}

	/**
	 * @param extrapolatedTarget The extrapolatedTarget to set.
	 */
	public void setExtrapolatedTarget(int extrapolatedTarget) {
		this.extrapolatedTarget = extrapolatedTarget;
	}

	public int getNumberOfRecordsNotNeedingEEMigrated() {
		return numberOfRecordsNotNeedingEEMigrated;
	}

	/**
	 * @return Returns the numberOfLettersTriggered.
	 */
	public int getNumberOfLettersTriggered() {
		return numberOfLettersTriggered;
	}
	
	public void incrementNumberOfLettersTriggered(int recordsCount) {
		numberOfLettersTriggered += recordsCount;
	}	

	public void incrementNumberOfEEDidNotChangeRecords() {
		incrementNumberOfEEDidNotChangeRecords(1);
	}

	public void incrementNumberOfEEDidNotChangeRecords(int count) {
		numberOfEEDidNotChangeRecords = numberOfEEDidNotChangeRecords + count;
	}
	
	protected void appendStats(ProcessStatistics stats) {
		MigrateBulkEEProcessStatistics incoming = (MigrateBulkEEProcessStatistics) stats;
		this.incrementNumberOfBulletinsTriggered(incoming.getNumberOfBulletinsTriggered());
		this.incrementNumberOfEEDidNotChangeRecords(incoming.getNumberOfEEDidNotChangeRecords());
		this.incrementNumberOfHL7MessagesTriggered(incoming.getNumberOfHL7MessagesTriggered());
		this.incrementNumberOfLettersTriggered(incoming.getNumberOfLettersTriggered());
		
		// don't want to affect "total" count, so this one must be done differently
		this.setNumberOfRecordsNotNeedingEEMigrated(this.getNumberOfRecordsNotNeedingEEMigrated() +
				incoming.getNumberOfRecordsNotNeedingEEMigrated());
		//this.incrementNumberOfRecordsNotNeedingEEMigrated(incoming.getNumberOfRecordsNotNeedingEEMigrated());
		
		this.setTotalSuccessfulDuration(this.getTotalSuccessfulDuration() + incoming.getTotalSuccessfulDuration());
	}

	/**
	 * @return Returns the parallelFactor.
	 */
	public int getParallelFactor() {
		return parallelFactor;
	}

	/**
	 * @param parallelFactor The parallelFactor to set.
	 */
	public void setParallelFactor(int parallelFactor) {
		this.parallelFactor = parallelFactor;
	}

	/**
	 * @return the totalSuccessfulDuration
	 */
	public float getTotalSuccessfulDuration() {
		return totalSuccessfulDuration;
	}

	/**
	 * @param totalSuccessfulDuration the totalSuccessfulDuration to set
	 */
	public void setTotalSuccessfulDuration(float totalSuccessfulDuration) {
		this.totalSuccessfulDuration = totalSuccessfulDuration;
	}	
	
	public void incrementTotalSuccessfulDuration(float successfulDuration) {
		this.totalSuccessfulDuration += successfulDuration;
		this.incrementNumberOfSuccessfulRecords();
	}
}
