class BlackOneTouchCashPriceFormulaRepository {

  public double price(
      double spot,
      double timeToExpiry,
      double costOfCarry,
      double rate,
      double lognormalVol,
      SimpleConstantContinuousBarrier barrier) {

    ArgChecker.notNull(barrier, "barrier");
    boolean isKnockIn = barrier.getKnockType().isKnockIn();
    boolean isDown = barrier.getBarrierType().isDown();
    double h = barrier.getBarrierLevel();
    ArgChecker.isFalse(isDown && spot <= barrier.getBarrierLevel(),
        "The Data is not consistent with an alive barrier (DOWN and spot<=barrier).");
    ArgChecker.isFalse(!isDown && spot >= barrier.getBarrierLevel(),
        "The Data is not consistent with an alive barrier (UP and spot>=barrier).");
    double eta = isDown ? 1 : -1;
    double df2 = Math.exp(-rate * timeToExpiry);
    double lognormalVolSq = lognormalVol * lognormalVol;
    double lognormalVolT = lognormalVol * Math.sqrt(timeToExpiry);
    if (nearZero(Math.min(timeToExpiry, lognormalVolSq), SMALL)) {
      return isKnockIn ? 0d : df2;
    }
    double mu = (costOfCarry - 0.5 * lognormalVolSq) / lognormalVolSq;
    double lambda = Math.sqrt(mu * mu + 2 * rate / lognormalVolSq);
    double m1 = lognormalVolT * (1 + mu);
    double x2 = Math.log(spot / h) / lognormalVolT + m1;
    double y2 = Math.log(h / spot) / lognormalVolT + m1;
    double z = Math.log(h / spot) / lognormalVolT + lambda * lognormalVolT;
    double xE = isKnockIn ?
        getF(spot, z, lognormalVolT, h, mu, lambda, eta) :
        getE(spot, df2, x2, y2, lognormalVolT, h, mu, eta);
    return xE;
  }

}