/* Class Buyer represents the buyer of Call and Put options
 */

import java.text.*;

class GoodBuyer {
  
  //The name of the buyer
  private String name;
  
  //Amount of money the buyer has
  private double account;
  
  //A buyer holds at most one Call and one Put option
  private GoodCallOption callOp;
  private GoodPutOption putOp;
  
  /* Contructor takes in the Buyer's name and inital account balance */
  public GoodBuyer(String name, double initialAcctBalance) {
    this.name = name;
    this.account = initialAcctBalance;
    callOp = null;
    putOp = null;
  }
  
  /* =Gets name of this buyer */
  public String getName() { 
    return name;
  }
  
  /* =Gets account value of this buyer */
  public double getAccount() { 
    return account;
  }
  
  /* This Buyer purchases the newCallOption.
   * Buyer does not purchase if he/she already owns a Call option.
   * When buying the Call, first calculate the total premium.
   */
  public void buyCallOption(GoodCallOption newCallOption) {
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    
    if(newCallOption != null) 
    {
      if(this.callOp != null) 
      {
        System.out.println("Unable to buy option. "+name+" already owns one Call Option.");
        
      }
      else //option slot is empty
      {
		  newCallOption.calculatePremium();
		  if(account >= newCallOption.getPremium()*newCallOption.getShares()) 
		  {
			account -= newCallOption.getPremium()*newCallOption.getShares();
			this.callOp = newCallOption;
			System.out.println(name+" bought $"+df.format(callOp.getPremium())+" call option:");
			System.out.println("\t" +callOp.toString());
			System.out.println(name+"'s account balance: $"+df.format(account));
		  }
		  else 
		  {
			  System.out.println(name+" does not have enough money to purchase this option");
		  }
      }
    }
    else
    {
      System.out.println("You are trying to buy a Call Option that is null");
    }
  }
  
  /* This Buyer purchases the newPutOption. 
   * Buyer does not purchase if he/she already owns a Put option.
   * When buying the Put, first calculate the total premium.
   */
  public void buyPutOption(GoodPutOption newPutOption) {
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    
    if(newPutOption != null) 
    {
      if(this.putOp != null) 
      {
        System.out.println("Unable to buy option. "+name+" already owns one Put Option.");
      }
      else //Option slot is empty
      {
	    newPutOption.calculatePremium();
		  if(account >= newPutOption.getPremium()*newPutOption.getShares()) 
		  {
			  account -= newPutOption.getPremium()*newPutOption.getShares();
			  this.putOp = newPutOption;
			  System.out.println(name+" bought $"+df.format(putOp.getPremium())+" put option:");
			  System.out.println("\t" +putOp.toString());
			  System.out.println(name+"'s account balance: $"+df.format(account));
		  }
		  else 
		  {
			  System.out.println(name+" does not have enough money to purchase this option");
		  }
      }
    }
    else
    {
      System.out.println("You are trying to buy a Put Option that is null");
    }
  }
  
  /* =Calculate the payout from this Buyer exercising his/her Call option.
   * Payout should be max(0, StockPrice-StrikePrice)*numberOfShares
   * Update the account and callOp fields.
   */
  public double exerciseCallOption() {
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    double payout = 0;
    if(callOp != null) 
    {
      if(callOp.getStrikePrice() < callOp.getStockPrice()) 
      {
        payout += callOp.getShares()*((callOp.getStockPrice() - callOp.getStrikePrice()));
      }
      account += payout;
      System.out.println(name+" exercised Call for payout of $"+df.format(payout)+ ".\n New account balance: $"+df.format(account));
      callOp = null;
    }
    else 
    {
      System.out.println("There is no Call Option to exercise");
    }
    return payout;
  }
  
  /* =Calculate the payout from this Buyer exercising his/her Put option.
   * Payout should be max(0, StrikePrice-StockPrice)*numberOfShares.
   * Update the account and putOp fields.
   */
  public double exercisePutOption() {
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    
    double payout = 0;
    if(putOp != null) 
    {
      if(putOp.getStrikePrice() > putOp.getStockPrice()) 
      {
        System.out.println(putOp);
        payout += putOp.getShares()*((putOp.getStrikePrice() - putOp.getStockPrice()));
      }
      account += payout;
      System.out.println(name+" exercised Put for payout of $"+df.format(payout)+ ".\n New account balance: "+df.format(account));
      putOp = null;
    }
    else 
    {
      System.out.println("There is no Put Option to exercise");
    }
    return payout;
  }
  
  /* =Return a String representation of the Buyer.
   * Must include each option the Buyer owns, if any.
   */
  public String toString() {
    String output;
    NumberFormat df = NumberFormat.getNumberInstance();
    df.setMaximumFractionDigits(2);
    if(callOp == null && putOp == null) 
    {
      output = "Buyer "+name+" has $"+df.format(account)+" and owns nothing.";
    }
    else 
    {
      output = "Buyer "+name+" has $"+df.format(account)+" and owns \n";
      if(callOp != null) 
      {
        output += " CALL OPTION: ";
        output += "\n\t" + callOp.toString() + "\n";
      }
      if(putOp != null)
      {
        output += " PUT OPTION: ";
        output += "\n\t" + putOp.toString() + "\n";
      }
    }
    return output;
  }
}