package jist.swans.field;

import jist.swans.Constants;
import jist.swans.misc.Location;
import jist.swans.radio.RadioInfo;

public interface PropagationDelay {

  /**
   * Calculate the propagation delay for both nodes.
   *
   * @param srcRadio source radio information
   * @param srcLocation source location
   * @param dstRadio destination radio information
   * @param dstLocation destination location
   * @return propagation delay in ticks.
   */
  long compute(RadioInfo srcRadio, Location srcLocation,
      RadioInfo dstRadio, Location dstLocation);


  /**
   * No propagation delay.
   *
   * @author kurth
   */
  public class None implements PropagationDelay {

    public long compute(RadioInfo srcRadio, Location srcLocation,
        RadioInfo dstRadio, Location dstLocation) {
      return 0;
    }

  }

  /**
   * No propagation delay.
   *
   * @author kurth
   */
  public class Fixed implements PropagationDelay {
    private long delay;

    public Fixed(long delay) {
      this.delay = delay;
    }

    public long compute(RadioInfo srcRadio, Location srcLocation,
        RadioInfo dstRadio, Location dstLocation) {
      return delay;
    }
  }

  /**
   * Distance-based model
   *
   * @author kurth
   */
  public class Dist implements PropagationDelay {

    public long compute(RadioInfo srcRadio, Location srcLocation,
        RadioInfo dstRadio, Location dstLocation) {
      double dist = srcLocation.distance(dstLocation);
      return (long)(Constants.SECOND * dist / Constants.SPEED_OF_LIGHT);
    }

  }

  /**
   * Distance based model with a normal distributed deviation.
   *
   * TODO or better poisson ??
   *
   * @author kurth
   */
  public class DistNormal extends Dist {
    private double propDelayStdDev = 2.;

    public DistNormal(double propDelayStdDev) {
      this.propDelayStdDev = propDelayStdDev;
    }

    /* (non-Javadoc)
     * @see jist.swans.field.PropagationDelay#compute(jist.swans.radio.RadioInfo, jist.swans.misc.Location, jist.swans.radio.RadioInfo, jist.swans.misc.Location)
     */
    public long compute(RadioInfo srcRadio, Location srcLocation,
        RadioInfo dstRadio, Location dstLocation) {
      long ret = super.compute(srcRadio, srcLocation, dstRadio, dstLocation);
      return ret + Math.abs((long)(Constants.random.nextGaussian() * propDelayStdDev));
    }

  }

}
