package net.y3n20u.aeszip;

/**
 * This class represents the progress status of archiving. Each numbers will be
 * negative if unknown.
 * 
 * @author y3n20u@gmail.com
 * 
 */
public class ArchiveProgressStatus {
	private final int totalElementCount;
	private final int processedElementCount;
	private final long estimatedSizeTotal;
	private final long processedSizeTotal;
	private final long estimatedSizeCurrent;
	private final long processedSizeCurrent;
	private final String processedSourceName;
	private final String destinationName;

	public ArchiveProgressStatus(
			int totalElementCount, int processedElementCount,
			long estimatedSizeTotal, long processedSizeTotal,
			long estimatedSizeCurrent, long processedSizeCurrent,
			String processedSourceName, String destinationName) {
		if (totalElementCount > 0 && totalElementCount < processedElementCount) {
			// TODO: message
			throw new IllegalArgumentException();
		}
		if (estimatedSizeTotal > 0 && estimatedSizeTotal < processedSizeTotal) {
			// TODO: message
			throw new IllegalArgumentException();
		}
		if (estimatedSizeCurrent > 0 && estimatedSizeCurrent < processedSizeCurrent) {
			// TODO: message
			throw new IllegalArgumentException(processedSizeCurrent + " / " + estimatedSizeCurrent);
		}
		this.totalElementCount = totalElementCount;
		this.processedElementCount = processedElementCount;
		this.estimatedSizeTotal = estimatedSizeTotal;
		this.processedSizeTotal = processedSizeTotal;
		this.estimatedSizeCurrent = estimatedSizeCurrent;
		this.processedSizeCurrent = processedSizeCurrent;
		this.processedSourceName = (processedSourceName == null ? "" : processedSourceName);
		this.destinationName = (destinationName == null ? "" : destinationName);
	}

	public ArchiveProgressStatus(
			int totalElementCount, int processedElementCount,
			long estimatedSizeTotal, long processedSizeTotal,
			long estimatedSizeCurrent, long processedSizeCurrent) {
		this(totalElementCount, processedElementCount, estimatedSizeTotal, processedSizeTotal, estimatedSizeCurrent,
				processedSizeCurrent, "", "");
	}

	/**
	 * Generate a new status object updated only current and total processed
	 * size. Add the value of the argument to the current processed size and the
	 * total processed size.
	 * 
	 * @param increments
	 *            variation of the processed size of current entry.
	 * @return generated status
	 */
	public ArchiveProgressStatus generateUpdatedStatus(long increments) {
		return new ArchiveProgressStatus(this.getTotalElementCount(), this.getProcessedElementCount(),
				this.getEstimatedSizeTotal(), this.getProcessedSizeTotal() + increments,
				this.getEstimatedSizeCurrent(), this.getProcessedSizeCurrent() + increments,
				this.getProcessedSourceName(), this.getDestinationName());
	}

	/**
	 * Generate a new status object for next entry. This method generates a
	 * status object that has increased count of processed elements and zero for
	 * the processed size of the current entry.
	 * 
	 * @param nextEntrySize
	 *            the estimated size of the next entry.
	 * @return generated status
	 */
	public ArchiveProgressStatus generateUpdatedStatusWithNextEntry(long nextEntrySize, String newSource,
			String newDestination) {
		return new ArchiveProgressStatus(this.getTotalElementCount(), this.getProcessedElementCount() + 1,
				this.getEstimatedSizeTotal(), this.getProcessedSizeTotal(), nextEntrySize, 0L, newSource,
				newDestination);
	}

	public int getTotalElementCount() {
		return totalElementCount;
	}

	public int getProcessedElementCount() {
		return processedElementCount;
	}

	public long getEstimatedSizeTotal() {
		return estimatedSizeTotal;
	}

	public long getProcessedSizeTotal() {
		return processedSizeTotal;
	}

	public long getEstimatedSizeCurrent() {
		return estimatedSizeCurrent;
	}

	public long getProcessedSizeCurrent() {
		return processedSizeCurrent;
	}

	public String getProcessedSourceName() {
		return processedSourceName;
	}

	public String getDestinationName() {
		return destinationName;
	}

	public double getProgressPercentageTotal() {
		if (this.getEstimatedSizeTotal() < 0 || this.getProcessedSizeTotal() < 0) {
			return -1.0;
		}
		if (this.getEstimatedSizeTotal() == 0) {
			return 100.0;
		}
		double estimated = this.getEstimatedSizeTotal();
		double processed = this.getProcessedSizeTotal();
		return processed / estimated * 100.0;
	}

	public double getProgressPercentageCurrent() {
		if (this.getEstimatedSizeCurrent() < 0 || this.getProcessedSizeCurrent() < 0) {
			return -1.0;
		}
		if (this.getEstimatedSizeCurrent() == 0) {
			return 100.0;
		}
		double estimated = this.getEstimatedSizeCurrent();
		double processed = this.getProcessedSizeCurrent();
		return processed / estimated * 100.0;
	}

}
