class BlackScholesFormulaRepository {

  public static double price(
      double spot,
      double strike,
      double timeToExpiry,
      double lognormalVol,
      double interestRate,
      double costOfCarry,
      boolean isCall) {

    ArgChecker.isTrue(spot >= 0d, "negative/NaN spot; have {}", spot);
    ArgChecker.isTrue(strike >= 0d, "negative/NaN strike; have {}", strike);
    ArgChecker.isTrue(timeToExpiry >= 0d, "negative/NaN timeToExpiry; have {}", timeToExpiry);
    ArgChecker.isTrue(lognormalVol >= 0d, "negative/NaN lognormalVol; have {}", lognormalVol);
    ArgChecker.isFalse(Double.isNaN(interestRate), "interestRate is NaN");
    ArgChecker.isFalse(Double.isNaN(costOfCarry), "costOfCarry is NaN");

    if (interestRate > LARGE) {
      return 0d;
    }
    if (-interestRate > LARGE) {
      return Double.POSITIVE_INFINITY;
    }
    double discount = Math.abs(interestRate) < SMALL ? 1d : Math.exp(-interestRate * timeToExpiry);

    if (costOfCarry > LARGE) {
      return isCall ? Double.POSITIVE_INFINITY : 0d;
    }
    if (-costOfCarry > LARGE) {
      double res = isCall ? 0d : (discount > SMALL ? strike * discount : 0d);
      return Double.isNaN(res) ? discount : res;
    }
    double factor = Math.exp(costOfCarry * timeToExpiry);

    if (spot > LARGE * strike) {
      double tmp = Math.exp((costOfCarry - interestRate) * timeToExpiry);
      return isCall ? (tmp > SMALL ? spot * tmp : 0d) : 0d;
    }
    if (LARGE * spot < strike) {
      return (isCall || discount < SMALL) ? 0d : strike * discount;
    }
    if (spot > LARGE && strike > LARGE) {
      double tmp = Math.exp((costOfCarry - interestRate) * timeToExpiry);
      return isCall ? (tmp > SMALL ? spot * tmp : 0d) : (discount > SMALL ? strike * discount : 0d);
    }

    double rootT = Math.sqrt(timeToExpiry);
    double sigmaRootT = lognormalVol * rootT;
    if (Double.isNaN(sigmaRootT)) {
      sigmaRootT = 1d; //ref value is returned
    }

    int sign = isCall ? 1 : -1;
    double rescaledSpot = factor * spot;
    if (sigmaRootT < SMALL) {
      double res = isCall ?
          (rescaledSpot > strike ? discount * (rescaledSpot - strike) : 0d) :
          (rescaledSpot < strike ? discount * (strike - rescaledSpot) : 0d);
      return Double.isNaN(res) ? sign * (spot - discount * strike) : res;
    }

    double d1 = 0d;
    double d2 = 0d;
    if (Math.abs(spot - strike) < SMALL || sigmaRootT > LARGE) {
      double coefD1 = (costOfCarry / lognormalVol + 0.5 * lognormalVol);
      double coefD2 = (costOfCarry / lognormalVol - 0.5 * lognormalVol);
      double tmpD1 = coefD1 * rootT;
      double tmpD2 = coefD2 * rootT;
      d1 = Double.isNaN(tmpD1) ? 0d : tmpD1;
      d2 = Double.isNaN(tmpD2) ? 0d : tmpD2;
    } else {
      double tmp = costOfCarry * rootT / lognormalVol;
      double sig = (costOfCarry >= 0d) ? 1d : -1d;
      double scnd =
          Double.isNaN(tmp) ? ((lognormalVol < LARGE && lognormalVol > SMALL) ? sig / lognormalVol : sig * rootT) : tmp;
      d1 = Math.log(spot / strike) / sigmaRootT + scnd + 0.5 * sigmaRootT;
      d2 = d1 - sigmaRootT;
    }
    double res = sign * discount * (rescaledSpot * NORMAL.getCDF(sign * d1) - strike * NORMAL.getCDF(sign * d2));
    return Double.isNaN(res) ? 0d : Math.max(res, 0d);
  }

  private  BlackScholesFormulaRepository();

}