key0-96/
key0-96/doc/key/
key0-96/doc/key/credits/
key0-96/doc/key/developers/
key0-96/doc/key/developers/resources/
key0-96/setup/caves/
key0-96/setup/help/
key0-96/setup/ruins/
key0-96/src/
key0-96/src/commands/
key0-96/src/events/
key0-96/src/hack/
key0-96/src/sql/
key0-96/src/swing/
key0-96/src/talker/forest/
key0-96/src/talker/objects/
key0-96/src/terminals/
/*
**               j###t  ########## ####   ####
**              j###t   ########## ####   ####
**             j###T               "###L J###"
**          ######P'    ##########  #########
**          ######k,    ##########   T######T
**          ####~###L   ####
**          #### q###L  ##########   .#####
**          ####  \###L ##########   #####"
**
**  Class History
**
**  Date        Name         Description
**  ---------|------------|-----------------------------------------------
**  06Oct97     exile        created this utility class
**  10Jul97     merlin       fixed to handle milliseconds greater than 10 digits**
**  05Nov98     subtle       made immutable for security
*/

package key.primitive;

import key.Grammar;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.StringTokenizer;
/**
  *  Represents an amount of time, such as 4 hours, or
  *  3 days, or whatever
 */
public final class Duration implements java.io.Serializable
{
	long milliseconds;

	public Duration()
	{
		milliseconds = 0;
	}

	/**
	  *  Constructs a new time with the specified duration
	  *  in milliseconds
	 */
	public Duration( long duration )
	{
		milliseconds = duration;
	}

	public Object Clone()
	{
		return( new Duration( milliseconds ) );
	}

	public long getTime()
	{
		return( milliseconds );
	}

	public final long getHours()
	{
		return( milliseconds / SIH );
	}

	/*
	public void setTime( long duration )
	{
		milliseconds = duration;
	}
	*/

	/*  - find the places that do this and change the
	    - add method to be functional in nature
	public void add( Duration d )
	{
		milliseconds += d.milliseconds;
	}
	*/

	/**
	  * Adds the supplied duration number times
	 */
	public Duration addMultiple( Duration d, int number )
	{
		return( new Duration( milliseconds + (d.milliseconds * number) ) );
	}
	
	public void subtract( Duration d )
	{
		milliseconds -= d.milliseconds;
	}
	
	/**
	  *  Given a string that represents a duration, parse it into a
	  *  value that can be used to construct a Duration.  (Don't
	  *  tell anyone, but it returns the duration in milliseconds).
	 */
	public static long parse( String s ) throws NumberFormatException
	{
		StringTokenizer st = new StringTokenizer( s, "hmsMwdfyq", true );

		long millisecs = 0;
		Double length;
		char periodType;
		boolean negative = false;
		long working;

		while( st.hasMoreTokens() )
		{	
			length = Double.valueOf( st.nextToken() );
			if( st.hasMoreTokens() )
			{
				periodType = st.nextToken().charAt(0);
				switch( periodType )
				{
					case 'y':
						working = (long)( SIY * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 's':
						working = (long)( SIS * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'w':
						working = (long)( SIW * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'M':
						working = (long)( SIMTH * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'f':
						working = (long)( SIF * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'q':
						working = (long)( SIQ * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'd':
						working = (long)( SID * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'm':
						working = (long)( SIM * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
					case 'h': 
					default:
						working = (long)( SIH * length.doubleValue() );
						if( working < 0 )
						{
							negative = true;
							working *= -1;
						}
						millisecs += working;
						break;
				}
			}
		}

		if ( negative )
			millisecs *= -1;

		return( millisecs );
	}

	public static final long SIS=1000;			// milliseconds in a Second
	public static final long SIM=60 * SIS;		// milliseconds in a Minute
	public static final long SIH=60 * SIM;		// milliseconds in a Hour
	public static final long SID=24 * SIH;		// milliseconds in a Day
	public static final long SIW=7 * SID;		// milliseconds in a Week
	public static final long SIF=2 * SIW;		// milliseconds in a Fortnight
	public static final long SIMTH = 4 * SIW;  // milliseconds in a Month
	public static final long SIQ= 3 * SIMTH;   // milliseconds in a Quarter
	public static final long SIY=365 * SID;	// milliseconds in a Year


        /**
          *Return short version of time (ETB)
        */
	public String toShortString()
	{
		return( toShortString( milliseconds ) );
	}

	public static String toShortString( long milliseconds )
	{
		String theTime = "";
		String seconds = "";
		String minutes = "";
		long secs = 0;

		long yrs=0;
		long wks=0;
		long days=0;
		long hrs=0;
		long mins=0;

		secs = milliseconds - ( ( yrs = getYears( milliseconds ) ) * SIY );
		secs = secs - ( ( wks=getWeeks( secs ) ) * SIW );
		secs = secs - ( ( days=getDays( secs ) ) * SID );
		secs = secs - ( ( hrs=getHours( secs ) ) * SIH );
		secs = secs - ( ( mins=getMinutes( secs ) ) * SIM );
		secs = secs / 1000;

		if( secs < 10 )
			seconds = "0";
		else
			seconds = "";
		seconds += Long.toString( secs );

		if ( mins < 10 )
			minutes = " ";
		else 
			minutes = "";
		minutes += Long.toString( mins );
	
		theTime = minutes + ":" + seconds ;
		return theTime;
	}

	
	/**
	  *  This routine courtesy of Adam Teague (brann)
	 */
	public String toString()
	{
		return( toString( milliseconds, false ) );
	}

	public String toTruncString()
	{
		return( toString( milliseconds, true ) );
	}
	
	public static String toString( long milliseconds, boolean shrt )
	{
        String TheTime[];
        int count = 0;
        long secs = 0;

        long yrs = 0;
        long wks = 0;
        long days = 0;
        long hrs = 0;
        long mins = 0;

		if ( milliseconds < 0 )
			milliseconds *= -1;

        secs = milliseconds - ( ( yrs = getYears( milliseconds ) ) * SIY );
        secs = secs - ( ( wks = getWeeks( secs ) ) * SIW );
        secs = secs - ( ( days = getDays( secs ) ) * SID );
        secs = secs - ( ( hrs = getHours( secs ) ) * SIH );
        secs = secs - ( ( mins = getMinutes( secs ) ) * SIM );
        secs = secs / 1000;
		
		TheTime = new String[ 7 ];
		
		count=0;

        if( yrs != 0 )
            TheTime[ count++ ] = Long.toString( yrs ) + " year" + ( yrs != 1 ? "s" : "" );
        if( wks != 0 )
            TheTime[ count++ ] = Long.toString( wks ) + " week" + ( wks != 1 ? "s" : "" );
        if( days != 0 )
            TheTime[ count++ ] = Long.toString( days ) + " day" + ( days != 1 ?
"s" : "" );
        if( hrs != 0 )
            TheTime[ count++ ] = Long.toString( hrs ) + " hour" + ( hrs != 1 ? "s" : "" );
        if( mins != 0 && !(count > 1 && shrt) )
            TheTime[ count++ ] = Long.toString( mins ) + " minute" + ( mins != 1 ? "s" : "" );
        if( secs != 0 && !(count > 1 && shrt) )
            TheTime[ count++ ] = Long.toString( secs ) + " second" + ( secs != 1 ? "s" : "" );
		
		if( count == 0 )
			return( "no time at all" );
		
		return( Grammar.enumerate( TheTime, count ) );
	}
	
	static private int getYears( long milliseconds )
	{
		return( (int)( milliseconds / SIY) );
	}

	static private int getWeeks( long milliseconds )
	{
		return( (int)( milliseconds / SIW) );
	}

	static private int getDays( long milliseconds )
	{
		return( (int)( milliseconds / SID) );
	}

	static private int getHours( long milliseconds )
	{
		return( (int)( milliseconds / SIH) );
	}

	static private int getMinutes( long milliseconds )
	{
		return( (int)( milliseconds / SIM) );
	}
}