class RollGeskeWhaleyModel {

  public double price(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double[] dividends, final double[] dividendTimes) {
    ArgumentChecker.isTrue(spot > 0., "spot is not positive");
    ArgumentChecker.isTrue(strike > 0., "strike is not positive");
    ArgumentChecker.isFalse(Double.isNaN(interestRate), "interestRate is NaN");
    ArgumentChecker.isTrue(timeToExpiry > 0., "timeToExpiry is not positive");
    ArgumentChecker.isTrue(volatility >= -0., "volatility is negative");

    ArgumentChecker.notNull(dividends, "dividends");
    ArgumentChecker.notNull(dividendTimes, "dividendTimes");
    final int nDivs = dividends.length;
    ArgumentChecker.isTrue(nDivs == dividendTimes.length, "dividends and dividendTimes should be the same length");
    for (int i = 0; i < nDivs; ++i) {
      ArgumentChecker.isTrue(Doubles.isFinite(dividends[i]), "dividends contains infinity or NaN");
      ArgumentChecker.isTrue(Doubles.isFinite(dividendTimes[i]), "dividendTimes contains infinity or NaN");
    }

    if (dividendTimes[0] > timeToExpiry) {
      return BlackScholesFormulaRepository.price(spot, strike, timeToExpiry, volatility, interestRate, interestRate, true);
    }
    final int position = FunctionUtils.getLowerBoundIndex(dividendTimes, timeToExpiry);
    double modSpot = spot;
    for (int i = 0; i < position; ++i) {
      modSpot -= (dividends[i] * Math.exp(-interestRate * dividendTimes[i]));
    }

    return price(modSpot, strike, interestRate, timeToExpiry, volatility, dividends[position], dividendTimes[position]);
  }

  public  RollGeskeWhaleyModel();

}