/*
 * Copyright 2012 Chris Vest
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package stormpot;

import java.util.concurrent.TimeUnit;

/**
 * A Timeout represents the maximum amount of time a caller is willing to wait
 * for a blocking operation to complete.
 * @author Chris Vest &lt;mr.chrisvest@gmail.com&gt;
 */
public class Timeout {
  private final long timeout;
  private final TimeUnit unit;
  
  /**
   * Construct a new timeout with the given value and unit. The unit cannot be
   * null, but the timeout value is unrestricted. The meaning of a negative
   * timeout value is specific to the implementation of the use site, but
   * typically means that no amount of blocking or waiting is tolerated.
   * @param timeout A numerical value for the timeout. Can be zero or negative,
   * though the meaning is implementation specific.
   * @param unit The unit of the timeout value. Never null.
   */
  public Timeout(long timeout, TimeUnit unit) {
    if (unit == null) {
      throw new IllegalArgumentException("unit cannot be null");
    }
    this.timeout = timeout;
    this.unit = unit;
  }

  /**
   * Get the timeout value in terms of the {@link #getUnit() unit}.
   * @return A numerical value of the timeout. Possibly zero or negative.
   */
  public long getTimeout() {
    return timeout;
  }

  /**
   * Get the unit for the {@link #getTimeout() timeout value}.
   * @return The {@link TimeUnit} of the timeout value. Never null.
   */
  public TimeUnit getUnit() {
    return unit;
  }

  /**
   * Calculate a deadline, as an instant in the future, in terms of the
   * {@link #getBaseUnit() base unit}. Once you have a deadline, you can ask
   * how much time is left until it transpires, with the
   * {@link #getTimeLeft(long)}, giving the deadline as an argument.
   * <p>
   * If the {@link #getTimeout() timeout value} is really small, zero or
   * negative, then the deadline might be an instant in the past.
   * @return A numerical value that represents the deadline from "now" until
   * this timeout has passed.
   */
  public long getDeadline() {
    return now() + unit.toNanos(timeout);
  }

  /**
   * Calculate the amount of time that is left within the deadline, in terms
   * of the {@link #getBaseUnit() base unit}. The argument is a deadline value
   * that has been calculated with the {@link #getDeadline()} method.
   * @param deadline The reference deadline from {@link #getDeadline()}.
   * @return The amount of time, in terms of the
   * {@link #getBaseUnit() base unit}, that is left within the deadline. If
   * this value is negative, then you have overrun the deadline.
   */
  public long getTimeLeft(long deadline) {
    return deadline - now();
  }

  private long now() {
    return System.nanoTime();
  }

  public TimeUnit getBaseUnit() {
    return TimeUnit.NANOSECONDS;
  }

  @Override
  public int hashCode() {
    long nanos = unit.toNanos(timeout);
    return 31 * 1 + (int) (nanos ^ (nanos >>> 32));
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof Timeout)) {
      return false;
    }
    Timeout that = (Timeout) obj;
    long thisNanos = unit.toNanos(timeout);
    long thatNanos = that.unit.toNanos(that.timeout);
    return thisNanos == thatNanos;
  }
}

@@ -853,16 +853,580 @@
 meout %7B%0A
+  private static interface Clock %7B%0A    long now();%0A  %7D%0A  %0A  private static final Clock clock;%0A  private static final TimeUnit clockUnit;%0A  %0A  static %7B%0A    if (System.getProperty(%22stormpot.timeout.clock%22, %22%22).equals(%22fast%22)) %7B%0A      clockUnit = TimeUnit.MILLISECONDS;%0A      clock = new Clock() %7B%0A        public long now() %7B%0A          return System.currentTimeMillis();%0A        %7D%0A      %7D;%0A    %7D else %7B%0A      clockUnit = TimeUnit.NANOSECONDS;%0A      clock = new Clock() %7B%0A        public long now() %7B%0A          return System.nanoTime();%0A        %7D%0A      %7D;%0A    %7D%0A  %7D%0A  %0A
   privat
@@ -3179,36 +3179,45 @@
 now() + 
-unit.toNanos
+getBaseUnit().convert
 (timeout
 );%0A  %7D%0A%0A
@@ -3204,24 +3204,30 @@
 vert(timeout
+, unit
 );%0A  %7D%0A%0A  /*
@@ -3830,39 +3830,33 @@
 %0A    return 
-System.nanoTime
+clock.now
 ();%0A  %7D%0A%0A  p
@@ -3897,36 +3897,25 @@
  return 
-TimeUnit.NANOSECONDS
+clockUnit
 ;%0A  %7D%0A%0A 

add experimental support for using System.currentTimeMillis as a time-source for calculating and measuring the deadline inside blocking methods such as claim(). The down-side of using System.currentTimeMillis is that its clock might be wound back, effectivily causing time to briefly run backwards. This can cause methods to overshoot their real-time deadlines by a wide margin. The up-side is that System.currentTimeMills is a significantly faster call than System.nanoTime.