1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.util.MathUtil;
    19  
    20  /**
    21   * {@code Time} is a holder for a time difference.
    22   * 
    23   * <p>{@code Time} splits a time difference (distance between two dates) into
    24   * days, hours, minutes, seconds and milliseconds to offers methods to access
    25   * the time difference value.
    26   * 
    27   * <p>There are two ways to access the {@code Time} instance:
    28   * 
    29   * <p>The first way is by {@code in*()}({@code inHours()}, {@code inMinutes()},...).
    30   * Those methods are coversions to the different time units. You can recieve the
    31   * complete value in a different unit.
    32   * 
    33   * Example:
    34   * <code>
    35   *   var time:Time = new Time(1.5, "d");
    36   *   trace(time.inDays()); // 1.5
    37   *   trace(time.inHours()); // 36
    38   *   trace(time.inMinutes()); // 2160
    39   * </code>
    40   * 
    41   * <p>The second way is by {@code get*()}({@code getHours()}, {@code getMinutes()},...).
    42   * Those methods contain only the part of each unit that is contained within the
    43   * value.
    44   * 
    45   * Example:
    46   * <code>
    47   *   var time:Time = new Time(1.5, "d");
    48   *   trace(time.getDays()); // 1.5
    49   *   trace(time.getHours()); // 12
    50   *   trace(time.getMinutes(); // 0
    51   * </code>
    52   * 
    53   * <p>Its possible to pass-in a number in to round the value to the next lower case:
    54   * 
    55   * Example:
    56   * <code>
    57   *   var time:Time = new Time(1.5, "d");
    58   *   trace(time.getDays(0)); // 1
    59   * </code>
    60   * 
    61   * @author Martin Heidegger
    62   * @version 1.0
    63   */
    64  class org.as2lib.data.type.Time extends BasicClass {
    65  	
    66  	/** Factor from ms to second. */ 
    67  	private static var SECOND:Number = 1000;
    68  	
    69  	/** Factor from ms to minute. */
    70  	private static var MINUTE:Number = SECOND*60;
    71  	
    72  	/** Factor from ms to hour. */
    73  	private static var HOUR:Number = MINUTE*60;
    74  	
    75  	/** Factor from ms to day. */
    76  	private static var DAY:Number = HOUR*24;
    77  	
    78  	/** Time difference in ms. */
    79  	private var ms:Number;
    80  	
    81  	/** Amount of days. */
    82  	private var days:Number;
    83  	
    84  	/** Amount of hours. */
    85  	private var hours:Number;
    86  	
    87  	/** Amount of minutes. */
    88  	private var minutes:Number;
    89  	
    90  	/** Amount of seconds. */
    91  	private var seconds:Number;
    92  	
    93  	/** Amount of milliseconds. */
    94  	private var milliSeconds:Number;
    95  	
    96  	/** Flag if the instance need to be evaluated by {@link #evaluate}. */
    97  	private var doEval:Boolean = true;
    98  	
    99  	/**
   100  	 * Constructs a new {@code Time} instance.
   101  	 * 
   102  	 * <p>Uses "ms" if no format or a wrong format was passed-in.
   103  	 * 
   104  	 * <p>Uses {@code Number.MAX_VALUE} if {@code Infinity} was passed-in.
   105  	 * 
   106  	 * 
   107       * @param time size of the time difference for the passed-in {@code format}
   108       * @param format (optional) "d"/"h"/"m"/"s"/"ms" for the unit of the amout,
   109       * 	      default case is "ms"
   110  	 */
   111  	public function Time(timeDifference:Number, format:String) {
   112  		setValue(timeDifference, format);
   113  	}
   114  	
   115  	/** 
   116  	 * Sets the time of the instance.
   117  	 * 
   118  	 * <p>Uses "ms" if no format or a wrong format was passed-in.
   119  	 * 
   120  	 * <p>Uses {@code Number.MAX_VALUE} if {@code Infinity} was passed-in.
   121  	 * 
   122       * @param time size of the time difference for the passed-in {@code format}
   123       * @param format (optional) "d"/"h"/"m"/"s"/"ms" for the unit of the amout.
   124       * 		  Default value is ms.
   125  	 */
   126  	public function setValue(timeDifference:Number, format:String):Time {
   127  		if (timeDifference == Infinity) {
   128  			timeDifference = Number.MAX_VALUE;
   129  		}
   130  		switch (format) {
   131  			case "d":
   132  				ms = timeDifference*DAY;
   133  				break;
   134  			case "h":
   135  				ms = timeDifference*HOUR;
   136  				break;
   137  			case "m":
   138  				ms = timeDifference*MINUTE;
   139  				break;
   140  			case "s":
   141  				ms = timeDifference*SECOND;
   142  				break;
   143  			default:
   144  				ms = timeDifference;
   145  		}
   146  		doEval = true;
   147  		return this;
   148  	}
   149  	
   150  	/**
   151  	 * Adds the passed-in {@code timedistance} to the current time.
   152  	 *  
   153  	 * @param timeDifference time difference to be added to the current time
   154  	 * @return new instance with the resulting amount of time
   155  	 */
   156  	public function plus(timeDifference:Time):Time {
   157  		return new Time(ms+timeDifference.valueOf());
   158  	}
   159  	
   160  	/**
   161  	 * Adds the passed-in {@code timeDifference} from the current time.
   162  	 *  
   163  	 * @param timeDifference time difference to be removed from the current time
   164  	 * @return new instance with the resulting amount of time
   165  	 */
   166  	public function minus(timeDifference:Time):Time {
   167  		return new Time(ms-timeDifference.valueOf());
   168  	}
   169  	
   170  	/**
   171  	 * Getter for the amount of milliseconds are contained within the time.
   172  	 * 
   173  	 * <p>It will not round the result if you pass-in nothing.
   174  	 * 
   175  	 * @param round (optional) the number of decimal spaces
   176  	 * @return time difference in milliseconds
   177  	 */
   178  	public function getMilliSeconds(round:Number):Number {
   179  		if (doEval) evaluate();
   180  		if (round == null) {
   181  			return milliSeconds;
   182  		} else {
   183  			return MathUtil.floor(milliSeconds, round);
   184  		}
   185  	}
   186  	
   187  	/**
   188  	 * Getter for the time distance in milliseconds.
   189  	 * 
   190  	 * @return time difference in milliseconds
   191  	 */
   192  	public function inMilliSeconds(Void):Number {
   193  		return ms;
   194  	}
   195  	
   196  	/**
   197  	 * Getter for the amount of seconds are contained within the time.
   198  	 * 
   199  	 * <p>It will not round the result if you pass-in nothing.
   200  	 * 
   201  	 * @param round (optional) the number of decimal spaces
   202  	 * @return time difference in seconds
   203  	 */
   204  	public function getSeconds(round:Number):Number {
   205  		if (doEval) evaluate();
   206  		if (round == null) {
   207  			return seconds;
   208  		} else {
   209  			return MathUtil.floor(seconds, round);
   210  		}
   211  	}
   212  	
   213  	/**
   214  	 * Getter for the time distance in seconds.
   215  	 * 
   216  	 * @return time difference in seconds
   217  	 */
   218  	public function inSeconds(Void):Number {
   219  		return ms/SECOND;
   220  	}
   221  	
   222  	/**
   223  	 * Getter for the amount of minutes are contained within the time.
   224  	 * 
   225  	 * <p>It will not round the result if you pass-in nothing.
   226  	 * 
   227  	 * @param round (optional) the number of decimal spaces
   228  	 * @return time difference in minutes
   229  	 */
   230  	public function getMinutes(round:Number):Number {
   231  		if (doEval) evaluate();
   232  		if (round == null) {
   233  			return minutes;
   234  		} else {
   235  			return MathUtil.floor(minutes, round);
   236  		}
   237  	}
   238  	
   239  	/**
   240  	 * Getter for the time distance in minutes.
   241  	 * 
   242  	 * @return time difference in minutes
   243  	 */
   244  	public function inMinutes(Void):Number {
   245  		return ms/MINUTE;
   246  	}
   247  	
   248  	/**
   249  	 * Getter for the amount of hours are contained within the time.
   250  	 * 
   251  	 * <p>It will not round the result if you pass-in nothing.
   252  	 * 
   253  	 * @param round (optional) the number of decimal spaces
   254  	 * @return time difference in hours
   255  	 */
   256  	public function getHours(round:Number):Number {
   257  		if (doEval) evaluate();
   258  		if (round == null) {
   259  			return hours;
   260  		} else {
   261  			return MathUtil.floor(hours, round);
   262  		}
   263  	}
   264  	
   265  	/**
   266  	 * Getter for the time distance in hours.
   267  	 * 
   268  	 * @return  time difference in hours
   269  	 */
   270  	public function inHours(Void):Number {
   271  		return ms/HOUR;
   272  	}
   273  	
   274  	/**
   275  	 * Getter for the amount of days are contained within the time.
   276  	 * 
   277  	 * <p>It will not round the result if you pass-in nothing.
   278  	 * 
   279  	 * @param round (optional) the number of decimal spaces
   280  	 * @return time difference in days
   281  	 */
   282  	public function getDays(round:Number):Number {
   283  		if (doEval) evaluate();
   284  		if (round == null) {
   285  			return days;
   286  		} else {
   287  			return MathUtil.floor(days, round);
   288  		}
   289  	}
   290  	
   291  	/**
   292  	 * Getter for the time distance in days.
   293  	 * 
   294  	 * @return  time difference in days
   295  	 */
   296  	public function inDays(Void):Number {
   297  		return ms/DAY;
   298  	}
   299  	
   300  	/**
   301  	 * Generates String representation of the time.
   302  	 * 
   303  	 * @return time difference as string
   304  	 */
   305  	public function toString():String {
   306  		return getDays(0)+"d "+getHours(0)+":"+getMinutes(0)+":"+getSeconds(0)+"."+getMilliSeconds(0);
   307  	}
   308  	
   309  	/**
   310  	 * Splits the time distance from ms (source value) into the different units.
   311  	 */
   312  	private function evaluate(Void):Void {
   313  		var negative = (ms >= 0) ? 1 : -1;
   314  		var rest:Number = ms;
   315  		
   316  		days = rest/DAY;
   317  		rest -= negative*Math.floor(days)*DAY;
   318  		
   319  		hours = rest/HOUR;
   320  		rest -= negative*Math.floor(hours)*HOUR;
   321  		
   322  		minutes = rest/MINUTE;
   323  		rest -= negative*Math.floor(minutes)*MINUTE;
   324  		
   325  		seconds = rest/SECOND;
   326  		rest -= negative*Math.floor(seconds)*SECOND;
   327  		
   328  		milliSeconds = rest;
   329  		
   330  		doEval = false;
   331  	}
   332  	
   333  	/**
   334  	 * Returns the value of the time distance (in ms).
   335  	 * 
   336  	 * @return value in ms
   337  	 */
   338  	public function valueOf():Number {
   339  		return ms;
   340  	}
   341  }