package brn.sim.builder;

import jist.swans.Constants;
import jist.swans.Node;
import jist.swans.field.PathLoss;

/**
 * Abstract base class for all pathloss builders.
 *
 * @author kurth
 */
public abstract class PathLossBuilder extends Builder {

  public static abstract class PathLossParams extends Builder.Params {
    private static final long serialVersionUID = 1L;
  }

  public static class FreeSpaceParams extends PathLossParams {
    private static final long serialVersionUID = 1L;
  }

  public static class TwoRayParams extends PathLossParams {
    private static final long serialVersionUID = 1L;
  }

  public static class LogDistanceParams extends PathLossParams {
    private static final long serialVersionUID = 1L;

    /** Exponent for pathloss formula.
     *
     * from NS2.manual:
     * Environment:
     * Outdoor      Free space          2
     *              Shadowed urban area 2.7 to 5
     * In building  Line-of-sight       1.6 to 1.8
     *              Obstructed          4 to 6
     */
    public double exponent = 2.8;

    /** Reference distance for dist based shadowing (default 1m) */
    public double refDist = 1.0;

    public double getExponent() {
      return exponent;
    }
    public void setExponent(double exponent) {
      this.exponent = exponent;
    }
    public double getRefDist() {
      return refDist;
    }
    public void setRefDist(double refDist) {
      this.refDist = refDist;
    }
  }

//  public static class DistExponentialParams extends PathLossParams {
//    private static final long serialVersionUID = 1L;
//
//    /** Exponent for pathloss formula.
//     *
//     * from NS2.manual:
//     * Environment:
//     * Outdoor      Free space          2
//     *              Shadowed urban area 2.7 to 5
//     * In building  Line-of-sight       1.6 to 1.8
//     *              Obstructed          4 to 6
//     */
//    public double exponent = 2.8;
//
//    /** Reference distance for dist based shadowing (default 1m) */
//    public double refDist = 1.0;
//
//    public double getExponent() {
//      return exponent;
//    }
//    public void setExponent(double exponent) {
//      this.exponent = exponent;
//    }
//    public double getRefDist() {
//      return refDist;
//    }
//    public void setRefDist(double refDist) {
//      this.refDist = refDist;
//    }
//  }

//  public static class FriisShadowingParams extends PathLossParams {
//    private static final long serialVersionUID = 1L;
//
//    /** Exponent for pathloss formula.
//     *
//     * from NS2.manual:
//     * Environment:
//     * Outdoor      Free space          2
//     *              Shadowed urban area 2.7 to 5
//     * In building  Line-of-sight       1.6 to 1.8
//     *              Obstructed          4 to 6
//     */
//    public double exponent = 2.8;
//
//    /** Standard deviation for log-normal shadow fading.
//     *
//     * from NS2.manual:
//     * Environment            sigma (dB)
//     * Outdoor                4 to 12
//     * Office, hard partition 7
//     * Office, soft partition 9.6
//     * Factory, line-of-sight 3 to 6
//     * Factory, obstructed    6.8
//     */
//    public double stdDeviation = 6.0;
//
//    /** quantile for propagation limit estimation */
//    public double quantile = 0.95;
//
//    public double getExponent() {
//      return exponent;
//    }
//    public void setExponent(double exponent) {
//      this.exponent = exponent;
//    }
//    public double getQuantile() {
//      return quantile;
//    }
//    public void setQuantile(double quantile) {
//      this.quantile = quantile;
//    }
//    public double getStdDeviation() {
//      return stdDeviation;
//    }
//    public void setStdDeviation(double stdDeviation) {
//      this.stdDeviation = stdDeviation;
//    }
//  }

  public static class ShadowingParams extends PathLossParams {
    private static final long serialVersionUID = 1L;

    /** deterministic path loss */
    public PathLossParams pathloss = new LogDistanceParams();

    /** Standard deviation for log-normal shadow fading.
     *
     * from NS2.manual:
     * Environment            sigma (dB)
     * Outdoor                4 to 12
     * Office, hard partition 7
     * Office, soft partition 9.6
     * Factory, line-of-sight 3 to 6
     * Factory, obstructed    6.8
     */
    public double stdDeviation = 6.0;

    /** quantile for propagation limit estimation */
    public double quantile = 0.95;

    /** Coherence time for dist based shadowing (default 1s) */
    public long coherenceTime = 1000 * Constants.MILLI_SECOND;

    /** Whether correlated shadowing should be symmetric on the wireless link */
    public boolean symmetricShadowing = true;

    /** whether to use exponential distributed shadowing intervals
     * (instead of deterministic, equal duration)
     */
    public boolean exponential = true;

    public long getCoherenceTime() {
      return coherenceTime;
    }
    public void setCoherenceTime(long coherenceTime) {
      this.coherenceTime = coherenceTime;
    }
    public boolean isSymmetricShadowing() {
      return symmetricShadowing;
    }
    public void setSymmetricShadowing(boolean symmetricShadowing) {
      this.symmetricShadowing = symmetricShadowing;
    }
    /* (non-Javadoc)
     * @see brn.sim.builder.Builder.Params#clone()
     */
    public Object clone() throws CloneNotSupportedException {
      ShadowingParams params = (ShadowingParams) super.clone();
      if (null != pathloss) pathloss = (PathLossParams) pathloss.clone();
      return params;
    }
    public double getStdDeviation() {
      return stdDeviation;
    }
    public void setStdDeviation(double stdDeviation) {
      this.stdDeviation = stdDeviation;
    }
    public double getQuantile() {
      return quantile;
    }
    public void setQuantile(double quantile) {
      this.quantile = quantile;
    }
    public PathLossParams getPathloss() {
      return pathloss;
    }
    public void setPathloss(PathLossParams pathloss) {
      this.pathloss = pathloss;
    }
    public boolean isExponential() {
      return exponential;
    }
    public void setExponential(boolean exponential) {
      this.exponential = exponential;
    }
  }


  /**
   * Free space path loss.
   *
   * @author kurth
   */
  public static class FreeSpaceBuilder extends PathLossBuilder {
    private static final long serialVersionUID = 1L;

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#getParamClass()
     */
    public Class getParamClass() {
      return FreeSpaceParams.class;
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
     */
    public Object build(Params params, Node node) throws BuilderException {
      return new PathLoss.FreeSpace();
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
     */
    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
      // pass..
    }
  }


  /**
   * Two ray path loss builder.
   *
   * @author kurth
   */
  public static class TwoRayBuilder extends PathLossBuilder {
    private static final long serialVersionUID = 1L;

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#getParamClass()
     */
    public Class getParamClass() {
      return TwoRayParams.class;
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
     */
    public Object build(Params params, Node node) throws BuilderException {
      return new PathLoss.TwoRay();
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
     */
    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
      // pass...
    }
  }

  /**
   * Two ray path loss builder.
   *
   * @author kurth
   */
  public static class LogDistanceBuilder extends PathLossBuilder {
    private static final long serialVersionUID = 1L;

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#getParamClass()
     */
    public Class getParamClass() {
      return LogDistanceParams.class;
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
     */
    public Object build(Params params, Node node) throws BuilderException {
      LogDistanceParams opts = (LogDistanceParams) params;
      return new PathLoss.LogDistance(opts.exponent, opts.refDist);
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
     */
    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
      // pass...
    }
  }

//  /**
//   * Pathloss builder based on friis path loss and uncorrelated log-normal shadowing.
//   *
//   * @author kurth
//   */
//  public static class FriisShadowingBuilder extends PathLossBuilder {
//    private static final long serialVersionUID = 1L;
//    /*
//     * (non-Javadoc)
//     * @see brn.sim.builder.Builder#getParamClass()
//     */
//    public Class getParamClass() {
//      return FriisShadowingParams.class;
//    }
//
//    /*
//     * (non-Javadoc)
//     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
//     */
//    public Object build(Params params, Node node) throws BuilderException {
//      FriisShadowingParams opts = (FriisShadowingParams) params;
//      return new PathLoss.FriisShadowing(opts.exponent, opts.stdDeviation,
//          opts.quantile);
//    }
//
//    /*
//     * (non-Javadoc)
//     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
//     */
//    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
//      // pass ...
//    }
//  }


  /**
   * Builder for shadowing based on (reference) distance with variable path loss
   * exponent and timely correlation.
   *
   * @author kurth
   */
  public static class ShadowingBuilder extends PathLossBuilder {
    private static final long serialVersionUID = 1L;
    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#getParamClass()
     */
    public Class getParamClass() {
      return ShadowingParams.class;
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
     */
    public Object build(Params params, Node node) throws BuilderException {
      ShadowingParams opts = (ShadowingParams) params;

      Builder builder = getProvider().getBuilder(opts.pathloss);
      PathLoss pathloss = (PathLoss) builder.build(opts.pathloss, node);
      getProvider().addHookUp(builder, opts.pathloss, node, pathloss);

      return new PathLoss.Shadowing(pathloss, opts.stdDeviation,
          opts.coherenceTime, opts.exponential, opts.symmetricShadowing, opts.quantile, 50);
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
     */
    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
      // pass...
    }
  }

  /**
   * @deprecated use {@link PathLossBuilder.ShadowingParams}
   */
  public static class DistShadowingParams  extends PathLossParams {
    private static final long serialVersionUID = 1L;

    /** Reference distance for dist based shadowing (default 1m) */
    public double refDist = 1.0;

    /** Coherence time for dist based shadowing (default 1s) */
    public long coherenceTime = 1000 * Constants.MILLI_SECOND;

    /** Whether correlated shadowing should be symmetric on the wireless link */
    public boolean symmetricShadowing = true;

    /** Exponent for pathloss formula.
     *
     * from NS2.manual:
     * Environment:
     * Outdoor      Free space          2
     *              Shadowed urban area 2.7 to 5
     * In building  Line-of-sight       1.6 to 1.8
     *              Obstructed          4 to 6
     */
    public double exponent = 2.8;

    /** Standard deviation for log-normal shadow fading.
     *
     * from NS2.manual:
     * Environment            sigma (dB)
     * Outdoor                4 to 12
     * Office, hard partition 7
     * Office, soft partition 9.6
     * Factory, line-of-sight 3 to 6
     * Factory, obstructed    6.8
     */
    public double stdDeviation = 6.0;

    /** quantile for propagation limit estimation */
    public double quantile = 0.95;

    public double getExponent() {
      return exponent;
    }
    public void setExponent(double exponent) {
      this.exponent = exponent;
    }
    public double getQuantile() {
      return quantile;
    }
    public void setQuantile(double quantile) {
      this.quantile = quantile;
    }
    public double getStdDeviation() {
      return stdDeviation;
    }
    public void setStdDeviation(double stdDeviation) {
      this.stdDeviation = stdDeviation;
    }
    public long getCoherenceTime() {
      return coherenceTime;
    }
    public void setCoherenceTime(long coherenceTime) {
      this.coherenceTime = coherenceTime;
    }
    public double getRefDist() {
      return refDist;
    }
    public void setRefDist(double refDist) {
      this.refDist = refDist;
    }
    public boolean isSymmetricShadowing() {
      return symmetricShadowing;
    }
    public void setSymmetricShadowing(boolean symmetricShadowing) {
      this.symmetricShadowing = symmetricShadowing;
    }
    /* (non-Javadoc)
     * @see brn.sim.builder.Builder.Params#clone()
     */
    public Object clone() {
      try {
        return super.clone();
      } catch (CloneNotSupportedException e) {
        e.printStackTrace();
        throw new Error(e);
      }
    }
  }

  /**
   * @deprecated use {@link PathLossBuilder.ShadowingBuilder}
   */
  public static class DistShadowingBuilder extends PathLossBuilder {
    private static final long serialVersionUID = 1L;
    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#getParamClass()
     */
    public Class getParamClass() {
      return DistShadowingParams.class;
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
     */
    public Object build(Params params, Node node) throws BuilderException {
      DistShadowingParams opts = (DistShadowingParams) params;
      return new PathLoss.DistShadowing(opts.exponent, opts.stdDeviation,
          opts.refDist, opts.coherenceTime, 50, opts.symmetricShadowing,
          opts.quantile);
    }

    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
     */
    public void hookUp(Params params, Node node, Object entity) throws BuilderException {
      // pass...
    }
  }
}
