/*
 * Created on Jul 26, 2006
 * 
 * (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.workflow.sanmanager.entities;

/**
 * Contains all the possible Units for Drive Storage Capacity
 * 
 * @author Vijay Silva
 */
public enum DriveCapacityUnit
{
	/**
	 * Single Byte
	 */
	BYTE,

	/**
	 * KiloByte
	 */
	KILOBYTE,

	/**
	 * MegaByte
	 */
	MEGABYTE,

	/**
	 * GigaByte
	 */
	GIGABYTE,

	/**
	 * TeraByte
	 */
	TERABYTE;

	private static final double UNIT_CONVERSION_BASE = 1024D;

	/**
	 * Method to get a String representation of the unit
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		String displayValue = null;

		switch (this)
		{
		case BYTE:
			displayValue = "B";
			break;

		case KILOBYTE:
			displayValue = "KB";
			break;

		case MEGABYTE:
			displayValue = "MB";
			break;

		case GIGABYTE:
			displayValue = "GB";
			break;

		case TERABYTE:
			displayValue = "TB";
			break;
		}

		return displayValue;
	}

	// ========================================================================
	// ====================== UTILITY METHODS
	// ========================================================================

	/**
	 * Method to convert a Capacity value from its current Unit to the Target Unit
	 * 
	 * @param capacity
	 *            The Capacity value to convert
	 * @param unit
	 *            The unit of the capacity value to convert
	 * @param target
	 *            The target unit to convert to
	 * @return The converted capacity value for the target unit
	 */
	public static double convert(double capacity, DriveCapacityUnit unit, DriveCapacityUnit target)
	{
		if (unit == null)
		{
			String message = "The DriveCapacityUnit for the capacity to convert cannot be null.";
			throw new IllegalArgumentException(message);
		}

		if (target == null)
		{
			String message = "The DriveCapacityUnit to convert the capacity to cannot be null.";
			throw new IllegalArgumentException(message);
		}

		if (capacity < 0)
		{
			String message = "The Capacity value to convert cannot be negative.";
			throw new IllegalArgumentException(message);
		}

		if (unit == target)
			return capacity;

		double byteCapacity = convertToBytes(capacity, unit);
		return convertFromBytes(byteCapacity, target);
	}

	/**
	 * Method to get the best (largest) possible unit to display the input Byte Count.
	 * 
	 * @param byteCount
	 *            The number of Bytes to display
	 * 
	 * @return The DriveCapacityUnit to use when displaying the byte count.
	 */
	public static DriveCapacityUnit getBestDisplayUnit(long byteCount)
	{
		DriveCapacityUnit unit = DriveCapacityUnit.BYTE;

		long divResult = byteCount / (long) Math.pow(UNIT_CONVERSION_BASE, 4D);
		if (divResult > 0)
		{
			unit = DriveCapacityUnit.TERABYTE;
		}
		else if ((divResult = byteCount / (long) Math.pow(UNIT_CONVERSION_BASE, 3D)) > 0)
		{
			unit = DriveCapacityUnit.GIGABYTE;
		}
		else if ((divResult = byteCount / (long) Math.pow(UNIT_CONVERSION_BASE, 2D)) > 0)
		{
			unit = DriveCapacityUnit.MEGABYTE;
		}
		else if ((divResult = byteCount / (long) Math.pow(UNIT_CONVERSION_BASE, 1D)) > 0)
		{
			unit = DriveCapacityUnit.KILOBYTE;
		}

		return unit;
	}

	// ========================================================================
	// ====================== INTERNAL HELPER METHODS
	// ========================================================================

	/*
	 * Method to convert the capacity value given the unit to bytes
	 */
	private static double convertToBytes(double capacity, DriveCapacityUnit unit)
	{
		double convertedCapacity = capacity;

		switch (unit)
		{
		case KILOBYTE:
			convertedCapacity *= Math.pow(UNIT_CONVERSION_BASE, 1D);
			break;

		case MEGABYTE:
			convertedCapacity *= Math.pow(UNIT_CONVERSION_BASE, 2D);
			break;

		case GIGABYTE:
			convertedCapacity *= Math.pow(UNIT_CONVERSION_BASE, 3D);
			break;

		case TERABYTE:
			convertedCapacity *= Math.pow(UNIT_CONVERSION_BASE, 4D);
			break;
		}

		return convertedCapacity;
	}

	/*
	 * Method to convert the capacity value (in bytes) to the target
	 */
	private static double convertFromBytes(double capacity, DriveCapacityUnit target)
	{
		double convertedCapacity = capacity;

		switch (target)
		{
		case KILOBYTE:
			convertedCapacity /= Math.pow(UNIT_CONVERSION_BASE, 1D);
			break;

		case MEGABYTE:
			convertedCapacity /= Math.pow(UNIT_CONVERSION_BASE, 2D);
			break;

		case GIGABYTE:
			convertedCapacity /= Math.pow(UNIT_CONVERSION_BASE, 3D);
			break;

		case TERABYTE:
			convertedCapacity /= Math.pow(UNIT_CONVERSION_BASE, 4D);
			break;
		}

		return convertedCapacity;
	}
}
