package seatrading.main;

import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Daniel "3ICE" Berezvai
 */
public class Harbor {

  private String name;
  private final Point2D.Double coords;
  /**
   * Quick access to the harbor's inventory, free to modify by all friend
   * classes.
   */
  protected List<Goods> goods;
  /**
   * Separate quick access to the harbor's oil storage, free to modify by all
   * friend classes.
   */
  protected Oil oil;

  /**
   * Creates a new Harbor and prints out information about it.
   *
   * @param name What to call the Harbor.
   * @param coords Where to spawn the Harbor. (requires Point2D.Double)
   */
  public Harbor(String name, Double coords) {
    System.out.println("\tCreating a harbor called \"" + name + "\" at ("
            + coords.x + ", " + coords.y + ").");
    this.name = name;
    this.coords = coords;
    goods = new ArrayList<>(1);
  }

  /**
   * Wrapper for Point2D.Double.distance(Point2D pt);
   *
   * @param h the target harbor
   * @return the distance
   */
  public double getDistanceFrom(Harbor h) {
    return this.coords.distance(h.coords);
  }

  public String getName() {
    return name;
  }

  /**
   * Generates some random tradegoods to have in stock at initialization time.
   */
  void initialLoad() {
    int upper = SeaTrading.rnd.nextInt(10) + 1;
    for (int i = 0; i < upper; i++) {
      Goods good = new Goods(Goods.rndName(),
              SeaTrading.round(SeaTrading.rnd.nextDouble() * 100_000));
      if (doesntAlreadyHaveThisTradeGood(good)) {
        goods.add(good);
      }// else {System.out.println("Successfully prevented double-add of " + good.getName());}
    }
    oil = new Oil(Oil.rndName(), SeaTrading.rnd.nextInt(1_000_000));
  }

  /**
   * Lists all goods in stock, not forgetting about the separately kept oil.
   */
  void printCurrentLoad() {
    System.out.print("\t" + name + " has " + oil.toString());
    for (Goods good : goods) {
      System.out.print(", " + SeaTrading.round(good.getWeight()) + " tons of " + good.getName());
    }
    System.out.println(".");
  }

  /**
   * Checks inventory for similarly named tradegoods in order to keep the new
   * one in the same
   *
   * @param thatGood The good we are looking for
   * @return true if no such good exists in inventory
   * @see findTradeGoodPriceByName();
   */
  private boolean doesntAlreadyHaveThisTradeGood(Goods thatGood) {
    for (Goods thisGood : goods) {
      if (thisGood.getName().equals(thatGood.getName())) {
        return false;
      }
    }
    return true;
  }

  private int findTradeGoodPriceByName(String name) {
    for (Goods good : goods) {
      if (good.getName().equals(name)) {
        return good.getPrice();
      }
    }
    return -1;
  }

  /**
   * Purchase fuel from the harbor's stock. Price is determined by the buyer
   * because we are generous.
   *
   * @param amount How much you want.
   * @return How much you actually get. Thanks to rmAmount()
   * @see rmAmount()
   */
  public int buyFuel(int amount) {
    return oil.rmAmount(amount);
  }

  /**
   * Don't forget to compare oil types before your purchase!
   *
   * @param amount How much you'd like.
   * @return a brand new oil object containing the amount you wanted, or all our
   * fuel if we happen to be low on stock.
   */
  public Oil buyOil(int amount) {
    Oil result = new Oil(oil.getName(), oil.rmAmount(amount));
    return result;
  }

  /**
   * Price checker
   *
   * @param good the trade goods you are interested in selling
   * @return a price offer
   */
  public double offerGoodsForSale(Goods good) {
    if (doesntAlreadyHaveThisTradeGood(good)) {
      return good.getPrice() * 1.5;
    } else {
      return findTradeGoodPriceByName(good.getName());
    }
  }

  /**
   * ToDo: Destroy good, signifying it was sold.
   *
   * @see offerGoodsForSale()
   */
  public double sell(Goods good) {
    return offerGoodsForSale(good);
  }

  /**
   * Checks the harbor's inventory for trade goods.
   *
   * @return True if we have something in stock.
   */
  public boolean hasGoodsForSale() {
    return !goods.isEmpty();
  }

  /**
   * Place an offer to buy some of the harbor's stock. Smart bounds, gives as
   * much as it can.
   *
   * @param maxWeight Should be the ship's empty cargo space.
   * @return a brand new trade goods object complete with price information.
   */
  public Goods buyGoods(double maxWeight) {
    Goods g = goods.get(SeaTrading.rnd.nextInt(goods.size()));
    //System.err.println("source g = " + g.toString());
    return new Goods(g.getName(), g.rmWeight(maxWeight), g.getPrice());
  }
}
