import java.util.*;
import java.text.*;

/* A PutOption is the right sell stocks at the strikePrice within the 
 * validity Period.  Each PutOption includes a number of shares and the premium
 * is the cost per share of the PutOption.  Other attributes include the current
 * stockPrice and the volatility.
 */
class GoodPutOption {
  
  private double strikePrice;  //Fixed option price per share
  private String symbol;       //Trading name
  private int validityPeriod;  //Number of days the option is valid after date 
                               //  of purchase
  private int numberOfShares;  //Number of shares of stock the option includes
  private double volatility;   //Standard deviation of the stock price as a 
                               //  fraction (<1, not in percent)
  private double stockPrice;   //Current market price of the stock per share
  private double premium;      //How much per share the buyer pays upfront for 
                               //  the option
  
  /* PutOption Constructor set the field values.
   */
  public GoodPutOption(String symbol, 
                   double strikePrice, 
                   double volatility,
                   int validityPeriod,
                   int numberOfShares,
                   double stockPrice) 
  {
	  if(strikePrice < 0 )
	  {
		  System.out.println("Warning: Strike Price is negative!");
	  }
	  if(volatility < 0 )
	  {
		  System.out.println("Warning: Volatility is negative!");
	  }
	  if(validityPeriod < 0 )
	  {
		  System.out.println("Warning: Validity Period is negative!");
	  }
	  if(numberOfShares < 0 )
	  {
		  System.out.println("Warning: Number of Shares is negative!");
	  }
	  if(stockPrice < 0 )
	  {
		  System.out.println("Warning: Stock Price is negative!");
	  }

    this.symbol = symbol;
    this.strikePrice = strikePrice;
    this.volatility = volatility;
    this.validityPeriod = validityPeriod;
    this.numberOfShares = numberOfShares;
    this.stockPrice = stockPrice;
    calculatePremium();
  }
  
  /* =Gets stockPrice */
  public double getStockPrice() {
    return stockPrice;
  }
  
  /* Sets stockPrice */
  public void setStockPrice(double s) {
	  if(stockPrice < 0) 
	  {
		  System.out.println("Stock price cannot be negative!");
	  }
	  else 
	  {
		  stockPrice = s;
	  }
  }
  
  /* =Gets strikePrice */
  public double getStrikePrice() {
    return strikePrice;
  }
  
  /* =Gets stock volatility */
  public double getVolatility() {
    return volatility;
  }
  
  /* =Gets number of shares */
  public double getShares() {
    return numberOfShares;
  }
  
  /* =Gets number of days the stock is valid since purchase */
  public int getValidityPeriod() {
    return validityPeriod;
  }
  
  /* =Gets the cost per share this PutOption */
  public double getPremium() {
    return premium;
  }
  
  /* Calculate the premium per share for this CallOption and set the field value.
   * The Black Scholes model says the price for a Put option is
   * Xe^(rt)N(-d2)-PN(-d1)
   * 
   * Where:
   * d1 = (ln(P/X)+(r+s^2/2)t)/(s*t^(1/2))
   * d2 = d1 - s*t^(1/2)
   * 
   * X = strike price
   * r = risk free rate
   * t = time till expiration in years
   * s = volatility
   * P = current stock price
   * 
   */
  public void calculatePremium() {
    double stock = getStockPrice();
    double rate = TradingFloor.RISK_FREE_RATE;
    double strike = getStrikePrice();
    double sigma = getVolatility();
    double t = getValidityPeriod()/365.0;
    if(t <= 0) 
    {
      System.out.println("Option is Expired");
      this.premium = 0;
      return;
    }
    else 
    {
      double d1 = (Math.log(stock/strike) + 
                  (rate+sigma*sigma/2.0)*t)/(sigma*Math.sqrt(t));
      double d2 = d1 - sigma*Math.sqrt(t);
      double n1 = Statistics.normalProbability((-1.0)*d1);
      double n2 = Statistics.normalProbability((-1.0)*d2);
      this.premium = strike*Math.pow(Math.E,((-1.0)*rate*t))*n2 - stock*n1;
      return;
    }
    
  }
  
  /* =Returns a String representation of this PutOption
   * Must return at least the Symbol, Stock Price, Stock Price.
   */ 
  public String toString() {
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    return symbol + " Stock: $" + df.format(stockPrice) + 
           " Strike: $" + df.format(strikePrice) + 
           " Premium: $" + df.format(premium);
  }
}



