/**
 * A two-part measurement (e.g., a length in feet and inches, a
 * weight in pounds and ounces, ...)
 *
 * A two-part measurement consists of a number of 
 * large units (e.g., feet) and a number of small 
 * units (e.g., inches)
 *
 * This class is abstract.  Concrete children must implement the
 * initializeUnits() method that initializes various "constants"
 * that are used throughout the class.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0  
 */
public abstract class TwoPartMeasure
{
    private int           large, sign, small;
   

    protected int         smallsPerLarge;
    protected String      largeUnitsSingular, largeUnitsPlural;
    protected String      smallUnitsSingular, smallUnitsPlural;



    /**
     * Default Constructor
     */
    public TwoPartMeasure()
    {
	this(0, 0, true);
    }


    /**
     * Explicit Value Constructor
     *
     * @param large  The number of large units (must be positive)
     * @param small  The number of small units (must be positive)
     */
    public TwoPartMeasure(int large, int small)
    {
	this(large, small, true);
    }





    /**
     * Explicit Value Constructor
     *
     * @param large    The number of large units (must be positive)
     * @param small    The number of small units (must be positive)
     * @param positive true for positive and false for negative
     */
    public TwoPartMeasure(int large, int small, boolean positive)
    {
	this.large = Math.abs(large);
	this.small = Math.abs(small);

	this.sign   = 1;
	if (!positive) this.sign = -1;


	initializeUnits();
    }




    /**
     * Change this TwoPartMeasure by a given amount
     *
     * @param other   The amount to change this TwoPartMeasure by
     */
    public void changeBy(TwoPartMeasure other)
    {
	int           otherTotal, thisTotal, total;

	otherTotal = other.toSmall();
	thisTotal  = this.toSmall();

	total = thisTotal + otherTotal;

	large = total / smallsPerLarge;
	small = total % smallsPerLarge;
    }






    /**
     * Check to see if thisTwoPartMeasure is equal to 
     * a given TwoPartMeasure
     *
     * @param other   The other TwoPartMeasure used in the comparison
     * @return        true if the two are equal and false otherwise
     */
    public boolean equals(TwoPartMeasure other)
    {
	boolean comparison;
	int     otherTotal, thisTotal;

	thisTotal  = this.toSmall();
	otherTotal = other.toSmall();

	comparison = false;
	if (thisTotal == otherTotal) comparison = true;

	return comparison;
    }






    /**
     * Initialize the "constants" used by a TwoPartMeasure,
     * specifically:
     *
     *    smallsPerLarge     (e.g., inches per foot, ounces per pound)
     *    largeUnitsSingular (e.g., "foot", "pound")
     *    largeUnitsPlural   (e.g., "feet", "pounds")
     *    smallUnitsSingular (e.g., "inch", "ounce")
     *    smallUnitsPlural   (e.g., "inches", "ounces")
     */
    protected abstract void initializeUnits();



    /**
     * "Convert" this TwoPartMeasure to small units
     * (e.g., from 5 feet 7 inches to 67 inches)
     *
     * @return   The value in small units
     */
    private int toSmall()
    {
	int         total;

	total = sign * ((large * smallsPerLarge) + small);
	return total;
    }



    /**
     * Get a String representation of this Length
     *
     * @return  The String
     */ 
    public String toString()
    {
	String     s;

	s = new String();
	if (sign < 0) s += "Negative ";

	if (large == 1) s += large + " " + largeUnitsSingular;
	else            s += large + " " + largeUnitsPlural;

	if (small == 1) s += "  " + small + " " + smallUnitsSingular;
	else            s += "  " + small + " " + smallUnitsPlural;

	return s;
    }

}
