/**
 * A class that represents a driver of a car.
 */
public class Driver {
  
  /** The current car of the driver. */
  private Car myCar;
  
  /** The name of the driver. */
  private String name;
  
  /** The current age of the driver. */
  private int age;
 
  /** The amount of money the driver has. */
  private double money;
  
  /** The cost of insurance on the driver's current car. */
  private double insurance;
  
  /** The number of demerit points the driver has. */
  private int dPoints;
  
  /** The standard license plate of the driver */
  public static final String LICENSE_PLATE = "APS 101";
  
  /** The number of cars that have been used by any driver */
  private static int numUsedCars = 0;
  
  /**
   * Constructor 1:
   * Create a driver with no car.
   */
  public Driver(String n, int a, double m) {
    this.name = n;
    this.age = a;
    this.money = m;
    
    this.dPoints = 0; // driver starts off with no demerit points.
    this.insurance = 0.0;
    // myCar is already equal to null, by default.
  }
  
  /**
   * Constructor 2:
   * Create a driver with a car that takes the standard license plate.
   */
  public Driver(String n, int a, double m, Car c) {
    this(n, a, m);
    
    this.myCar = c;
    c.setLicensePlate(LICENSE_PLATE);
    
    this.updateInsurance();
  }
  
  /**
   * Constructor 3:
   * Create a driver with a car that takes the specified license plate lp.
   */
  public Driver(String n, int a, double m, Car c, String lp) {
    this(n, a, m);
    
    this.myCar = c;
    c.setLicensePlate(lp);
    
    this.updateInsurance();
  }
  
  /**
   * Calculate the monthly insurance the driver has to pay for the car.
   */
  private double calculateInsurance() {
    return (this.myCar.getPrice() * 0.05) * (1.0 / Math.log10(this.age))
      + (100.0 * this.dPoints);
  }
  
  /**
   * Update the monthly insurance the driver has to pay for the car.
   */
  public void updateInsurance() {
    this.insurance = bankersRound(this.calculateInsurance()); 
  }
  
  /**
   * Remove all of the driver's demerit points.
   */
  public void cleanRecord() {
    this.dPoints = 0;
    this.updateInsurance();
  }
  
  /**
   * Increase the demerit points, and the insurance of the driver.
   */
  public void receiveSpeedingTicket(int p) {
    this.dPoints = this.dPoints + p;
    this.updateInsurance();
  }
  
   /**
   * Decrease the money that the driver has, as a result of a parking ticket.
   */
  public void receiveParkingTicket(double f) {
    this.money = this.money - f;
  }
  
  /**
   * Change the colour of the current car to new colour c.
   */
  public void repaintCar(String c) {
    this.myCar.setColour(c);
  }
  
  /**
   * Sell the current car.
   * NOTE: assume that driver has a current car.
   */
  public void sellCar() {
    this.money = bankersRound(this.money + (0.75 * this.myCar.getPrice()));
    this.myCar = null;
    this.insurance = 0.0; 
    numUsedCars++;
  }
  
  /**
   * Buy a car c.
   * NOTE: assume that driver does not currently have a car.
   */
  public void buyCar(Car c, String lp) {
    this.myCar = c;
    this.myCar.setLicensePlate(lp);
    this.money = this.money - this.myCar.getPrice();
    this.updateInsurance();
  }
  
  /**
   * Pay the monthly insurance.
   */
  public void payInsurance() {
    this.money = this.money - this.insurance;
  }
  
  /**
   * Add more money to the driver.
   */
  public void makeMoney(double m) {
    this.money = this.money + m;
  }
  
  /**
   * Increase the driver's age by one year.
   */
  public void growOlder() {
    this.age++;
    this.updateInsurance();
  }
  
  /**
   * Check whether the driver has a car.
   */
  public boolean hasCar() {
    return this.myCar != null;
  }
  
  /**
   * Check whether the driver can afford Car c.
   */
  public boolean canAfford(Car c) {
    return this.money >= c.getPrice();
  }
  
  /**
   * Check whether the driver is in debt. 
   */
  public boolean inDebt() {
    return this.money < 0.0;
  }
  
  /**
   * Get the current car of the driver.
   */
  public Car getCar() {
    return this.myCar;
  }
  
  /**
   * Get the name of the driver.
   */
  public String getName() {
    return this.name;
  }
  
  /**
   * Get the age of the driver.
   */
  public int getAge() {
    return this.age;
  }
  
  /**
   * Get the amount of money the driver has.
   */
  public double getMoney() {
    return this.money;
  }
  
  /**
   * Get the amount of insurance the driver has to pay.
   */
  public double getInsurance() {
    return this.insurance;
  }
  
  /**
   * Get the number of demerit points the driver has.
   */
  public int getDemeritPoints() {
    return this.dPoints;
  }
  
  /** 
   * Get the total number of cars used by any driver. 
   */
  public static int getNumberOfUsedCars() {
    return numUsedCars;
  }
  
  /** Check whether cars c1 and c2 are the same car. */
  public static boolean compareCars(Car c1, Car c2) {
    return (c1.getYear() == c2.getYear()) 
      && (c1.getBrand().equals(c2.getBrand()))
      && (c1.getModel().equals(c2.getModel()));
  }
  
  /** Round number d to 2 decimal places. */
  public static double bankersRound(double d) {
    return Math.rint(d * 100.0) / 100.0;
  }
  
  /**
   * Get the information about the driver's current car.
   */
  public String carInfo() {
    return "" + this.myCar.getYear() + " " + this.myCar.getBrand() + " "
      + this.myCar.getModel() + ", " + this.myCar.getColour() + ", "
      + "License plate: " + this.myCar.getLicensePlate();
  }
  
  /**
   * Get the information about the driver.
   */
  public String driverInfo() {
    return this.name + ", " + this.age + " years old, $" + (int) this.money
      + " in the bank";
  }
  
}