/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2011 Ausenco Engineering Canada Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
package com.jaamsim.units;

import java.util.HashMap;

import com.sandwell.JavaSimulation.AliasListInput;
import com.sandwell.JavaSimulation.DoubleListInput;
import com.sandwell.JavaSimulation.Entity;
import com.sandwell.JavaSimulation.InputErrorException;

public abstract class Unit extends Entity {
	private static final HashMap<Class<? extends Unit>, String> siUnit;

	// if one entry, it is the number of SI units per this unit.  i.e. multiply by this number to convert this unit into SI units
	// if two entries, it is the number of SI units per this unit expressed as a fraction.  i.e. multiply by the first number and divide by the second number to convert this unit into SI units
	private final DoubleListInput conversionFactorToSI;
	private final AliasListInput alias; // a list of strings that can be used as alternate names of the object

	static {
		siUnit = new HashMap<Class<? extends Unit>, String>();
	}

	{
		conversionFactorToSI = new DoubleListInput( "ConversionFactorToSI", "Key Inputs", null );
		conversionFactorToSI.setValidRange( 1e-15d, Double.POSITIVE_INFINITY );
		conversionFactorToSI.setValidCountRange( 1, 2 );
		this.addInput( conversionFactorToSI, true );

		alias = new AliasListInput( "Alias", "Key Inputs", null, this );
		this.addInput( alias, true );
	}

	public Unit() {}

	@Override
	public void kill() {
		if( alias.getValue() != null ) {
			for( String str : alias.getValue() ) {
				this.removeAlias( str );
			}
		}
		super.kill();
	}

	public static final void setSIUnit(Class<? extends Unit> unitType, String si) {
		siUnit.put(unitType, si);
	}

	/**
	 * Get the SI unit for the given unit type.
	 * @param unitType
	 * @return a string describing the SI unit, or if one has not been defined: 'SI'
	 */
	public static final String getSIUnit(Class<? extends Unit> unitType) {
		String unit = siUnit.get(unitType);
		if (unit != null)
			return unit;

		return "SI";
	}

	/**
	 * Return the conversion factor to SI units
	 */
	public double getConversionFactorToSI() {

		if( conversionFactorToSI.getValue() == null ) {
			throw new InputErrorException( this.getName() + " missing conversion factor to SI" );
		}

		// if the conversionFactorToSI input has one value, then it is the conversion factor to SI units
		if( conversionFactorToSI.getValue().size() == 1 ) {
			return conversionFactorToSI.getValue().get( 0 );
		}
		else {
			// if the conversionFactorToSI input has two values,
			// then the first value divided by the second value is the conversion factor to SI units
			if( conversionFactorToSI.getValue().size() == 2 ) {
				return conversionFactorToSI.getValue().get( 0 ) / conversionFactorToSI.getValue().get( 1 );
			}
			else {
				throw new InputErrorException( this.getName() + " ConversionFactorToSI must have 1 or 2 values" );
			}
		}
	}

	/**
	 * Return the conversion factor to the given units
	 */
	public double getConversionFactorToUnit( Unit unit ) {
		Double factor1 = this.getConversionFactorToSI();
		Double factor2 = unit.getConversionFactorToSI();
		if( unit.getClass() == this.getClass() && factor1 != null && factor2 != null ) {
			return factor1 / factor2 ;
		}
		else {
			throw new InputErrorException( "Cannot convert from " + this + " to " + unit );
		}
	}

}

@@ -851,16 +851,60 @@
 ception;
+%0Aimport com.sandwell.JavaSimulation.Keyword;
 %0A%0Apublic
@@ -1016,484 +1016,805 @@
 ;%0A%0A%09
-// if one entry, it is the number of SI units per this unit.  i.e. multiply by this number to convert this unit into 
+@Keyword(description = %22Factor to convert from the specified unit to the System International (
 SI
+)
  unit
-s%0A%09// if two entries, it is the number of SI units per this unit expressed as a fraction.  i.e. multiply by the first number and divide by the second number to convert this unit into SI units%0A%09private final DoubleListInput conversionFactorToSI;%0A%09private final AliasListInput alias; // a list of strings that can be used as alternate names of the object
+. %22 +%0A%09%09%09%09%09%22The factor is entered as A / B, where A is the first entry and B is the second. %22 +%0A%09%09%09%09%09%22For example, to convert from miles per hour to m/s, the first factor is 1609.344 (meters in one mile) and %22 +%0A%09%09%09%09%09%22the second factor is 3600 (seconds in one hour).%22,%0A%09%09%09example = %22mph  ConversionFactorToSI %7B 1609.344  3600 %7D%22)%0A%09private final DoubleListInput conversionFactorToSI;%0A%0A%09@Keyword(description = %22Alternative names for the same unit.  For example, the unit 'Year' could have aliases of %22 +%0A%09%09%09%09%09%22'y' or 'yr'. With these aliases, the following inputs are equivalent: %7B 1.0 year %7D, %7B 1.0 y %7D, and %7B 1.0 yr %7D.%22,%0A%09%09%09example = %22Year Alias %7B y  yr %7D%22)%0A%09private final AliasListInput alias;
 %0A%0A%09s

Add keyword descriptions for Unit